mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-02 04:12:16 +00:00
fix(oidc): use authenticated encryption for opaque tokens (#12017)
# Which Problems Are Solved Opaque tokens now use authenticated encryption. # How the Problems Are Solved - Upgrade zitadel/oidc to v3.47 - Copy crypto implementation for refresh and session tokens (internal to zitadel) - Added config that allows validating old tokens for gradual roll-out # Additional Changes - Set NX cache for `integration-test-build` to `false`, working on a seperate fix. # Additional Context - closes #11315 --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: muhlemmer <[email protected]>
This commit is contained in:
@@ -2,7 +2,6 @@ package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -204,15 +203,6 @@ func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (_ op.Au
|
||||
panic(o.panicErr("AuthRequestByCode"))
|
||||
}
|
||||
|
||||
// decryptGrant decrypts a code or refresh_token
|
||||
func (o *OPStorage) decryptGrant(grant string) (string, error) {
|
||||
decodedGrant, err := base64.RawURLEncoding.DecodeString(grant)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return o.encAlg.DecryptString(decodedGrant, o.encAlg.EncryptionKeyID())
|
||||
}
|
||||
|
||||
func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) (err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() {
|
||||
@@ -529,7 +519,7 @@ func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, to
|
||||
span.EndWithError(err)
|
||||
}()
|
||||
|
||||
plainToken, err := o.decryptGrant(token)
|
||||
plainToken, err := o.authAlg.DecryptToken(token)
|
||||
if err != nil {
|
||||
return "", "", op.ErrInvalidRefreshToken
|
||||
}
|
||||
|
||||
+20
-8
@@ -83,7 +83,7 @@ type OPStorage struct {
|
||||
defaultIdTokenLifetime time.Duration
|
||||
defaultRefreshTokenIdleExpiration time.Duration
|
||||
defaultRefreshTokenExpiration time.Duration
|
||||
encAlg crypto.EncryptionAlgorithm
|
||||
authAlg crypto.AuthAlgorithm
|
||||
assetAPIPrefix func(ctx context.Context) string
|
||||
contextToIssuer func(context.Context) string
|
||||
federateLogoutCache cache.Cache[federatedlogout.Index, string, *federatedlogout.FederatedLogout]
|
||||
@@ -118,7 +118,7 @@ func NewServer(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
repo repository.Repository,
|
||||
encryptionAlg crypto.EncryptionAlgorithm,
|
||||
authAlg crypto.AuthAlgorithm,
|
||||
targetEncryptionAlgorithm crypto.EncryptionAlgorithm,
|
||||
cryptoKey []byte,
|
||||
es *eventstore.Eventstore,
|
||||
@@ -132,12 +132,24 @@ func NewServer(
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
|
||||
}
|
||||
storage := newStorage(config, command, query, repo, encryptionAlg, es, ContextToIssuer, federatedLogoutCache)
|
||||
storage := newStorage(config, command, query, repo, authAlg, es, ContextToIssuer, federatedLogoutCache)
|
||||
keyCache := newPublicKeyCache(ctx, config.PublicKeyCacheMaxAge, queryKeyFunc(query))
|
||||
accessTokenKeySet := newOidcKeySet(keyCache, withKeyExpiryCheck(true))
|
||||
idTokenHintKeySet := newOidcKeySet(keyCache)
|
||||
|
||||
var options []op.Option
|
||||
alg := op.NewAES256GCMCrypto(opConfig.CryptoKey, "")
|
||||
if authAlg.LegacyTokenEnabled() {
|
||||
alg = op.NewCompositeCrypto(
|
||||
alg,
|
||||
[]op.Decrypter{
|
||||
alg,
|
||||
op.NewAESCrypto(opConfig.CryptoKey),
|
||||
},
|
||||
)
|
||||
}
|
||||
options := []op.Option{
|
||||
op.WithCrypto(alg),
|
||||
}
|
||||
if !externalSecure {
|
||||
options = append(options, op.WithAllowInsecure())
|
||||
}
|
||||
@@ -173,9 +185,9 @@ func NewServer(
|
||||
jwksCacheControlMaxAge: config.JWKSCacheControlMaxAge,
|
||||
fallbackLogger: fallbackLogger,
|
||||
hasher: hasher,
|
||||
encAlg: encryptionAlg,
|
||||
encAlg: authAlg,
|
||||
targetEncryptionAlgorithm: targetEncryptionAlgorithm,
|
||||
opCrypto: op.NewAESCrypto(opConfig.CryptoKey),
|
||||
opCrypto: alg,
|
||||
assetAPIPrefix: assets.AssetAPI(),
|
||||
}
|
||||
metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
|
||||
@@ -247,7 +259,7 @@ func newStorage(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
repo repository.Repository,
|
||||
encAlg crypto.EncryptionAlgorithm,
|
||||
authAlg crypto.AuthAlgorithm,
|
||||
es *eventstore.Eventstore,
|
||||
contextToIssuer func(context.Context) string,
|
||||
federateLogoutCache cache.Cache[federatedlogout.Index, string, *federatedlogout.FederatedLogout],
|
||||
@@ -264,7 +276,7 @@ func newStorage(
|
||||
defaultIdTokenLifetime: config.DefaultIdTokenLifetime,
|
||||
defaultRefreshTokenIdleExpiration: config.DefaultRefreshTokenIdleExpiration,
|
||||
defaultRefreshTokenExpiration: config.DefaultRefreshTokenExpiration,
|
||||
encAlg: encAlg,
|
||||
authAlg: authAlg,
|
||||
assetAPIPrefix: assets.AssetAPI(),
|
||||
contextToIssuer: contextToIssuer,
|
||||
federateLogoutCache: federateLogoutCache,
|
||||
|
||||
@@ -39,7 +39,7 @@ type Server struct {
|
||||
fallbackLogger *slog.Logger
|
||||
hasher *crypto.Hasher
|
||||
signingKeyAlgorithm string
|
||||
encAlg crypto.EncryptionAlgorithm
|
||||
encAlg crypto.AuthAlgorithm
|
||||
targetEncryptionAlgorithm crypto.EncryptionAlgorithm
|
||||
opCrypto op.Crypto
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
@@ -145,15 +144,3 @@ func (s *Server) createJWT(ctx context.Context, client op.Client, session *comma
|
||||
|
||||
return crypto.Sign(claims, signer)
|
||||
}
|
||||
|
||||
// decryptCode decrypts a code or refresh_token
|
||||
func (s *Server) decryptCode(ctx context.Context, code string) (_ string, err error) {
|
||||
_, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
decoded, err := base64.RawURLEncoding.DecodeString(code)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s.encAlg.DecryptString(decoded, s.encAlg.EncryptionKeyID())
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func (s *Server) CodeExchange(ctx context.Context, r *op.ClientRequest[oidc.Acce
|
||||
return nil, zerrors.ThrowInternal(nil, "OIDC-Ae2ph", "Error.Internal")
|
||||
}
|
||||
|
||||
plainCode, err := s.decryptCode(ctx, r.Data.Code)
|
||||
plainCode, err := s.encAlg.DecryptToken(r.Data.Code)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "OIDC-ahLi2", "Errors.User.Code.Invalid")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user