mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
Merge commit from fork
* feat(jwt idp): manage and validate audience * translations * fix tests * address comments * update migration version * fix merge
This commit is contained in:
@@ -28,6 +28,7 @@ type Provider struct {
|
||||
issuer string
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
audience string
|
||||
isLinkingAllowed bool
|
||||
isCreationAllowed bool
|
||||
isAutoCreation bool
|
||||
@@ -67,13 +68,14 @@ func WithAutoUpdate() ProviderOpts {
|
||||
}
|
||||
|
||||
// New creates a JWT provider
|
||||
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
|
||||
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName, audience string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
|
||||
provider := &Provider{
|
||||
name: name,
|
||||
issuer: issuer,
|
||||
jwtEndpoint: jwtEndpoint,
|
||||
keysEndpoint: keysEndpoint,
|
||||
headerName: headerName,
|
||||
audience: audience,
|
||||
encryptionAlg: encryptionAlg,
|
||||
}
|
||||
for _, option := range options {
|
||||
|
||||
@@ -20,6 +20,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
@@ -43,6 +44,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -64,6 +66,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -83,6 +86,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -108,6 +112,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -135,6 +140,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
opts []ProviderOpts
|
||||
}
|
||||
@@ -159,6 +165,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -181,6 +188,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -211,6 +219,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
tt.fields.opts...,
|
||||
)
|
||||
|
||||
@@ -100,6 +100,11 @@ func (s *Session) validateToken(ctx context.Context, token string) (*oidc.IDToke
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
|
||||
}
|
||||
|
||||
if s.Provider.audience != "" {
|
||||
if err = oidc.CheckAudience(claims, s.Provider.audience); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
|
||||
}
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
httpMock func(issuer string)
|
||||
authURL string
|
||||
@@ -60,6 +61,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -83,6 +85,36 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
httpMock: func(issuer string) {
|
||||
gock.New(issuer).
|
||||
Get("/keys").
|
||||
Reply(200).
|
||||
JSON(keys(t))
|
||||
},
|
||||
authURL: "https://auth.com/jwt?authRequestID=testState",
|
||||
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
|
||||
Token: &oauth2.Token{},
|
||||
IDToken: "invalidToken",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, ErrInvalidToken)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid token (audience)",
|
||||
fields: fields{
|
||||
issuer: "https://jwt.com",
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -214,6 +246,69 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "clientID",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
httpMock: func(issuer string) {
|
||||
gock.New(issuer).
|
||||
Get("/keys").
|
||||
Reply(200).
|
||||
JSON(keys(t))
|
||||
},
|
||||
authURL: "https://auth.com/jwt?authRequestID=testState",
|
||||
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
|
||||
Token: &oauth2.Token{},
|
||||
IDToken: idToken(t, "https://jwt.com", time.Now().Add(time.Hour), 0),
|
||||
IDTokenClaims: &oidc.IDTokenClaims{
|
||||
TokenClaims: oidc.TokenClaims{
|
||||
Subject: "sub",
|
||||
},
|
||||
UserInfoProfile: oidc.UserInfoProfile{
|
||||
Picture: "picture",
|
||||
Name: "firstname lastname",
|
||||
GivenName: "firstname",
|
||||
FamilyName: "lastname",
|
||||
Nickname: "nickname",
|
||||
PreferredUsername: "username",
|
||||
Profile: "profile",
|
||||
Locale: oidc.NewLocale(language.English),
|
||||
},
|
||||
UserInfoEmail: oidc.UserInfoEmail{
|
||||
Email: "email",
|
||||
EmailVerified: oidc.Bool(true),
|
||||
},
|
||||
UserInfoPhone: oidc.UserInfoPhone{
|
||||
PhoneNumber: "phone",
|
||||
PhoneNumberVerified: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
id: "sub",
|
||||
firstName: "firstname",
|
||||
lastName: "lastname",
|
||||
displayName: "firstname lastname",
|
||||
nickName: "nickname",
|
||||
preferredUsername: "username",
|
||||
email: "email",
|
||||
isEmailVerified: true,
|
||||
phone: "phone",
|
||||
isPhoneVerified: true,
|
||||
preferredLanguage: language.English,
|
||||
avatarURL: "picture",
|
||||
profile: "profile",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "successful fetch (no audience check)",
|
||||
fields: fields{
|
||||
issuer: "https://jwt.com",
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -281,6 +376,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user