Skip to content

feat(auth): cache Argon2 hash calculations - #793

Merged
maki5 merged 3 commits into
opencloud-eu:mainfrom
maki5:feat/argon2_app_token_auth_optimization
Sep 9, 2026
Merged

feat(auth): cache Argon2 hash calculations#793
maki5 merged 3 commits into
opencloud-eu:mainfrom
maki5:feat/argon2_app_token_auth_optimization

Conversation

@maki5

@maki5 maki5 commented Sep 7, 2026

Copy link
Copy Markdown

Introduced cache for in app tokens, this will prevent regeneration of argon2 token on every auth verification which is time and resource consuming

closes #opencloud-eu/opencloud#3157

@maki5
maki5 requested review from butonic and rhafer September 7, 2026 14:24

@rhafer rhafer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This should help a lot to improve the auth performance for apptokens.

Unless I am overlooking something I don't think the use of hmac instead of plain sha256 provides any benefits. But please correct me if I am wrong here.

Find my other comments inline.

Comment thread pkg/appauth/manager/jsoncs3/jsoncs3.go Outdated
generator: generator,
uTimeUpdateInterval: uTimeUpdateInterval,
authCache: expirable.NewLRU[string, *apppb.AppPassword](0, nil, defaultCacheTTL),
authCacheSecret: []byte(sharedconf.GetJWTSecret("")),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we picking the JWTSecret here as the key for hmac? If we really need to use hmac at all (I have doubts, see below), I'd suggest to just generate a random key at initialization, after all this is just an in memory cache.

Comment thread pkg/appauth/manager/jsoncs3/jsoncs3.go Outdated
}

func (m *manager) createAuthCacheKey(userID, secret string) string {
mac := hmac.New(sha256.New, m.authCacheSecret)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the benefit of using hmac here? The cache is in-memory only. If an attacker is able to obtain a memory dump, that dump not only contains the cache but almost certainly also the secret. Or am I missing something?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking initially just about sha256, the reason for hmac was just to have a more complex encoding. But I believe you are right here, are we ok to switch to sha256 or you have a better suggestion what can we use here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sha256 should be fine

Comment thread pkg/appauth/manager/jsoncs3/jsoncs3.go Outdated

cached := proto.Clone(pw).(*apppb.AppPassword)
cached.Password = id
m.authCache.Add(cacheKey, cached)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This executes inside the store.Update callback, before the metadata update is confirmed. If the subsequent upload fails or retries after an etag conflict caused by another replica revoking the token, GetAppPassword can return NotFound while the stale credential remains usable from cache for up to 60 seconds.

It's better to move the cache insertion outside the callback and perform it only after store.Update succeeded.

return hex.EncodeToString(mac.Sum(nil))
}

func (m *manager) removeFromAuthCache(userID, secretOrId string) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it would help to have some comment here about what this is doing and why secretOrId can be a secret or id. It's a bit confusing.

Comment thread pkg/appauth/manager/jsoncs3/jsoncs3.go Outdated

func (m *manager) createAuthCacheKey(userID, secret string) string {
mac := hmac.New(sha256.New, m.authCacheSecret)
_, _ = mac.Write([]byte(userID + ":" + secret))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I'd suggest to not use : as the delimiter here but something unambigous e.g. a 0 byte:

_, _ = x.Write([]byte(userID))
_, _ = x.Write([]byte{0})
_, _ = x.Write([]byte(secret))

@maki5
maki5 requested a review from rhafer September 9, 2026 07:10

@rhafer rhafer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, apart from the type which make the linter fail in CI.

Comment thread pkg/appauth/manager/jsoncs3/jsoncs3.go Outdated
Co-authored-by: Ralf Haferkamp <ralf@h4kamp.de>
@maki5
maki5 merged commit 1b8c2f1 into opencloud-eu:main Sep 9, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants