mirror of
https://github.com/netbirdio/dex.git
synced 2026-05-22 18:43:53 -07:00
feat: add a jti per default (#4695)
Signed-off-by: Roger Meier <r.meier@siemens.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/dexidp/dex/connector"
|
||||
"github.com/dexidp/dex/server/internal"
|
||||
@@ -271,6 +272,7 @@ type idTokenClaims struct {
|
||||
Audience audience `json:"aud"`
|
||||
Expiry int64 `json:"exp"`
|
||||
IssuedAt int64 `json:"iat"`
|
||||
JWTID string `json:"jti,omitempty"`
|
||||
AuthorizingParty string `json:"azp,omitempty"`
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
AuthTime int64 `json:"auth_time,omitempty"`
|
||||
@@ -357,6 +359,7 @@ func (s *Server) newIDToken(ctx context.Context, clientID string, claims storage
|
||||
Nonce: nonce,
|
||||
Expiry: expiry.Unix(),
|
||||
IssuedAt: issuedAt.Unix(),
|
||||
JWTID: uuid.New().String(),
|
||||
}
|
||||
|
||||
// Include auth_time when sessions are enabled and the value is available.
|
||||
|
||||
@@ -1099,6 +1099,84 @@ func TestNewIDTokenUsesStoredAlgorithmUntilNextRotation(t *testing.T) {
|
||||
require.Equal(t, wantCodeHash, claims.CodeHash)
|
||||
}
|
||||
|
||||
func TestNewIDTokenContainsJTI(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
logger := slog.New(slog.DiscardHandler)
|
||||
store := memory.New(logger)
|
||||
|
||||
now := time.Now().UTC()
|
||||
err := store.UpdateKeys(ctx, func(keys storage.Keys) (storage.Keys, error) {
|
||||
keys.SigningKey = &jose.JSONWebKey{
|
||||
Key: testKey,
|
||||
KeyID: "test-rs256",
|
||||
Algorithm: string(jose.RS256),
|
||||
Use: "sig",
|
||||
}
|
||||
keys.SigningKeyPub = &jose.JSONWebKey{
|
||||
Key: testKey.Public(),
|
||||
KeyID: "test-rs256",
|
||||
Algorithm: string(jose.RS256),
|
||||
Use: "sig",
|
||||
}
|
||||
keys.NextRotation = now.Add(time.Hour)
|
||||
return keys, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
localConfig := signer.LocalConfig{
|
||||
KeysRotationPeriod: time.Hour.String(),
|
||||
Algorithm: jose.RS256,
|
||||
}
|
||||
sig, err := localConfig.Open(ctx, store, time.Hour, func() time.Time { return now }, logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
sig.Start(ctx)
|
||||
|
||||
issuerURL, err := url.Parse("https://issuer.example.com")
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Server{
|
||||
signer: sig,
|
||||
issuerURL: *issuerURL,
|
||||
logger: logger,
|
||||
now: func() time.Time { return now },
|
||||
idTokensValidFor: time.Hour,
|
||||
}
|
||||
|
||||
keys, err := sig.ValidationKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, keys)
|
||||
|
||||
extractJTI := func(t *testing.T, idToken string) string {
|
||||
t.Helper()
|
||||
jws, err := jose.ParseSigned(idToken, []jose.SignatureAlgorithm{jose.RS256})
|
||||
require.NoError(t, err)
|
||||
payload, err := jws.Verify(keys[0])
|
||||
require.NoError(t, err)
|
||||
var claims struct {
|
||||
JTI string `json:"jti"`
|
||||
}
|
||||
err = json.Unmarshal(payload, &claims)
|
||||
require.NoError(t, err)
|
||||
return claims.JTI
|
||||
}
|
||||
|
||||
token1, _, err := s.newIDToken(ctx, "client", storage.Claims{UserID: "1", Username: "alice"}, []string{"openid"}, "n1", "", "", "mock", time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
token2, _, err := s.newIDToken(ctx, "client", storage.Claims{UserID: "1", Username: "alice"}, []string{"openid"}, "n2", "", "", "mock", time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
jti1 := extractJTI(t, token1)
|
||||
jti2 := extractJTI(t, token2)
|
||||
|
||||
assert.NotEmpty(t, jti1, "jti claim must be present and non-empty")
|
||||
assert.NotEmpty(t, jti2, "jti claim must be present and non-empty")
|
||||
assert.NotEqual(t, jti1, jti2, "each token must have a unique jti")
|
||||
}
|
||||
|
||||
func TestSessionMatchesHint(t *testing.T) {
|
||||
// genSubject("foo", "bar") == "CgNmb28SA2Jhcg" (from TestGetSubject)
|
||||
assert.True(t, sessionMatchesHint(&storage.AuthSession{UserID: "foo", ConnectorID: "bar"}, "CgNmb28SA2Jhcg"))
|
||||
|
||||
Reference in New Issue
Block a user