2023-07-14 11:16:16 +00:00
|
|
|
//go:build integration
|
|
|
|
|
|
|
|
package oidc_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2023-10-17 15:19:51 +00:00
|
|
|
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
|
|
|
"github.com/zitadel/oidc/v3/pkg/client/rs"
|
|
|
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
2023-11-23 14:17:50 +00:00
|
|
|
"golang.org/x/text/language"
|
2023-07-14 11:16:16 +00:00
|
|
|
|
2023-11-23 14:17:50 +00:00
|
|
|
oidc_api "github.com/zitadel/zitadel/internal/api/oidc"
|
2023-07-14 11:16:16 +00:00
|
|
|
"github.com/zitadel/zitadel/pkg/grpc/authn"
|
|
|
|
"github.com/zitadel/zitadel/pkg/grpc/management"
|
2023-09-13 12:43:01 +00:00
|
|
|
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
|
2023-07-14 11:16:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestOPStorage_SetUserinfoFromToken(t *testing.T) {
|
|
|
|
clientID := createClient(t)
|
|
|
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess)
|
2023-11-06 09:48:28 +00:00
|
|
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
2023-07-14 11:16:16 +00:00
|
|
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
|
|
|
AuthRequestId: authRequestID,
|
|
|
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
|
|
|
Session: &oidc_pb.Session{
|
|
|
|
SessionId: sessionID,
|
|
|
|
SessionToken: sessionToken,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// code exchange
|
|
|
|
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
|
|
|
|
tokens, err := exchangeTokens(t, clientID, code)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assertTokens(t, tokens, true)
|
|
|
|
assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime)
|
|
|
|
|
|
|
|
// test actual userinfo
|
2023-10-17 15:19:51 +00:00
|
|
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
2023-07-14 11:16:16 +00:00
|
|
|
require.NoError(t, err)
|
2023-10-17 15:19:51 +00:00
|
|
|
userinfo, err := rp.Userinfo[*oidc.UserInfo](CTX, tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider)
|
2023-07-14 11:16:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
assertUserinfo(t, userinfo)
|
|
|
|
}
|
|
|
|
|
2023-11-21 12:11:38 +00:00
|
|
|
func TestServer_Introspect(t *testing.T) {
|
2023-07-14 11:16:16 +00:00
|
|
|
project, err := Tester.CreateProject(CTX)
|
|
|
|
require.NoError(t, err)
|
2023-07-19 11:17:39 +00:00
|
|
|
app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
2023-07-14 11:16:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
api, err := Tester.CreateAPIClient(CTX, project.GetId())
|
|
|
|
require.NoError(t, err)
|
|
|
|
keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{
|
|
|
|
ProjectId: project.GetId(),
|
|
|
|
AppId: api.GetAppId(),
|
|
|
|
Type: authn.KeyType_KEY_TYPE_JSON,
|
|
|
|
ExpirationDate: nil,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2023-10-17 15:19:51 +00:00
|
|
|
resourceServer, err := Tester.CreateResourceServer(CTX, keyResp.GetKeyDetails())
|
2023-07-14 11:16:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-11-23 14:17:50 +00:00
|
|
|
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess, oidc_api.ScopeResourceOwner}
|
2023-07-14 11:16:16 +00:00
|
|
|
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
2023-11-06 09:48:28 +00:00
|
|
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
2023-07-14 11:16:16 +00:00
|
|
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
|
|
|
AuthRequestId: authRequestID,
|
|
|
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
|
|
|
Session: &oidc_pb.Session{
|
|
|
|
SessionId: sessionID,
|
|
|
|
SessionToken: sessionToken,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// code exchange
|
|
|
|
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
|
|
|
|
tokens, err := exchangeTokens(t, app.GetClientId(), code)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assertTokens(t, tokens, true)
|
|
|
|
assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime)
|
|
|
|
|
|
|
|
// test actual introspection
|
2023-10-17 15:19:51 +00:00
|
|
|
introspection, err := rs.Introspect[*oidc.IntrospectionResponse](context.Background(), resourceServer, tokens.AccessToken)
|
2023-07-14 11:16:16 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
assertIntrospection(t, introspection,
|
|
|
|
Tester.OIDCIssuer(), app.GetClientId(),
|
|
|
|
scope, []string{app.GetClientId(), api.GetClientId(), project.GetId()},
|
|
|
|
tokens.Expiry, tokens.Expiry.Add(-12*time.Hour))
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertUserinfo(t *testing.T, userinfo *oidc.UserInfo) {
|
|
|
|
assert.Equal(t, User.GetUserId(), userinfo.Subject)
|
|
|
|
assert.Equal(t, "Mickey", userinfo.GivenName)
|
|
|
|
assert.Equal(t, "Mouse", userinfo.FamilyName)
|
|
|
|
assert.Equal(t, "Mickey Mouse", userinfo.Name)
|
|
|
|
assert.NotEmpty(t, userinfo.PreferredUsername)
|
|
|
|
assert.Equal(t, userinfo.PreferredUsername, userinfo.Email)
|
|
|
|
assert.False(t, bool(userinfo.EmailVerified))
|
|
|
|
assertOIDCTime(t, userinfo.UpdatedAt, User.GetDetails().GetChangeDate().AsTime())
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertIntrospection(
|
|
|
|
t *testing.T,
|
|
|
|
introspection *oidc.IntrospectionResponse,
|
|
|
|
issuer, clientID string,
|
|
|
|
scope, audience []string,
|
|
|
|
expiration, creation time.Time,
|
|
|
|
) {
|
|
|
|
assert.True(t, introspection.Active)
|
|
|
|
assert.Equal(t, scope, []string(introspection.Scope))
|
|
|
|
assert.Equal(t, clientID, introspection.ClientID)
|
|
|
|
assert.Equal(t, oidc.BearerToken, introspection.TokenType)
|
|
|
|
assertOIDCTime(t, introspection.Expiration, expiration)
|
|
|
|
assertOIDCTime(t, introspection.IssuedAt, creation)
|
|
|
|
assertOIDCTime(t, introspection.NotBefore, creation)
|
|
|
|
assert.Equal(t, User.GetUserId(), introspection.Subject)
|
|
|
|
assert.ElementsMatch(t, audience, introspection.Audience)
|
|
|
|
assert.Equal(t, issuer, introspection.Issuer)
|
|
|
|
assert.NotEmpty(t, introspection.JWTID)
|
|
|
|
assert.NotEmpty(t, introspection.Username)
|
|
|
|
assert.Equal(t, introspection.Username, introspection.PreferredUsername)
|
|
|
|
assert.Equal(t, "Mickey", introspection.GivenName)
|
|
|
|
assert.Equal(t, "Mouse", introspection.FamilyName)
|
|
|
|
assert.Equal(t, "Mickey Mouse", introspection.Name)
|
2023-11-23 14:17:50 +00:00
|
|
|
assert.Equal(t, oidc.Gender("male"), introspection.Gender)
|
|
|
|
assert.Equal(t, oidc.NewLocale(language.Dutch), introspection.Locale)
|
2023-07-14 11:16:16 +00:00
|
|
|
assert.Equal(t, introspection.Username, introspection.Email)
|
|
|
|
assert.False(t, bool(introspection.EmailVerified))
|
|
|
|
assertOIDCTime(t, introspection.UpdatedAt, User.GetDetails().GetChangeDate().AsTime())
|
2023-11-23 14:17:50 +00:00
|
|
|
|
|
|
|
require.NotNil(t, introspection.Claims)
|
|
|
|
assert.Equal(t, User.Details.ResourceOwner, introspection.Claims[oidc_api.ClaimResourceOwner+"id"])
|
|
|
|
assert.NotEmpty(t, introspection.Claims[oidc_api.ClaimResourceOwner+"name"])
|
|
|
|
assert.NotEmpty(t, introspection.Claims[oidc_api.ClaimResourceOwner+"primary_domain"])
|
2023-07-14 11:16:16 +00:00
|
|
|
}
|