mirror of
https://github.com/zitadel/zitadel.git
synced 2025-05-06 09:16:49 +00:00
fix: use of generic oauth provider (#5345)
Adds a id_attribute to the GenericOAuthProvider, which is used to map the external User. Further mapping can be done in actions by using the `rawInfo` of the new `ctx.v1.providerInfo` field.
This commit is contained in:
parent
cfe00ef0d0
commit
2efa305e10
@ -26,6 +26,9 @@ The first parameter contains the following fields
|
|||||||
This is a verification errors string representation. If the verification succeeds, this is "none"
|
This is a verification errors string representation. If the verification succeeds, this is "none"
|
||||||
- `authRequest` [*auth request*](/docs/apis/actions/objects#auth-request)
|
- `authRequest` [*auth request*](/docs/apis/actions/objects#auth-request)
|
||||||
- `httpRequest` [*http request*](/docs/apis/actions/objects#http-request)
|
- `httpRequest` [*http request*](/docs/apis/actions/objects#http-request)
|
||||||
|
- `providerInfo` *Any*
|
||||||
|
Returns the response of the provider. In case the provider is a Generic OAuth Provider, the information is accessible through:
|
||||||
|
- `rawInfo` *Any*
|
||||||
- `api`
|
- `api`
|
||||||
The second parameter contains the following fields
|
The second parameter contains the following fields
|
||||||
- `v1`
|
- `v1`
|
||||||
|
@ -210,6 +210,7 @@ func addGenericOAuthProviderToCommand(req *admin_pb.AddGenericOAuthProviderReque
|
|||||||
TokenEndpoint: req.TokenEndpoint,
|
TokenEndpoint: req.TokenEndpoint,
|
||||||
UserEndpoint: req.UserEndpoint,
|
UserEndpoint: req.UserEndpoint,
|
||||||
Scopes: req.Scopes,
|
Scopes: req.Scopes,
|
||||||
|
IDAttribute: req.IdAttribute,
|
||||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,6 +224,7 @@ func updateGenericOAuthProviderToCommand(req *admin_pb.UpdateGenericOAuthProvide
|
|||||||
TokenEndpoint: req.TokenEndpoint,
|
TokenEndpoint: req.TokenEndpoint,
|
||||||
UserEndpoint: req.UserEndpoint,
|
UserEndpoint: req.UserEndpoint,
|
||||||
Scopes: req.Scopes,
|
Scopes: req.Scopes,
|
||||||
|
IDAttribute: req.IdAttribute,
|
||||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +227,7 @@ func addGenericOAuthProviderToCommand(req *mgmt_pb.AddGenericOAuthProviderReques
|
|||||||
TokenEndpoint: req.TokenEndpoint,
|
TokenEndpoint: req.TokenEndpoint,
|
||||||
UserEndpoint: req.UserEndpoint,
|
UserEndpoint: req.UserEndpoint,
|
||||||
Scopes: req.Scopes,
|
Scopes: req.Scopes,
|
||||||
|
IDAttribute: req.IdAttribute,
|
||||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,6 +241,7 @@ func updateGenericOAuthProviderToCommand(req *mgmt_pb.UpdateGenericOAuthProvider
|
|||||||
TokenEndpoint: req.TokenEndpoint,
|
TokenEndpoint: req.TokenEndpoint,
|
||||||
UserEndpoint: req.UserEndpoint,
|
UserEndpoint: req.UserEndpoint,
|
||||||
Scopes: req.Scopes,
|
Scopes: req.Scopes,
|
||||||
|
IDAttribute: req.IdAttribute,
|
||||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/actions/object"
|
"github.com/zitadel/zitadel/internal/actions/object"
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/idp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Login) runPostExternalAuthenticationActions(
|
func (l *Login) runPostExternalAuthenticationActions(
|
||||||
@ -20,6 +21,7 @@ func (l *Login) runPostExternalAuthenticationActions(
|
|||||||
tokens *oidc.Tokens,
|
tokens *oidc.Tokens,
|
||||||
authRequest *domain.AuthRequest,
|
authRequest *domain.AuthRequest,
|
||||||
httpRequest *http.Request,
|
httpRequest *http.Request,
|
||||||
|
idpUser idp.User,
|
||||||
authenticationError error,
|
authenticationError error,
|
||||||
) (*domain.ExternalUser, error) {
|
) (*domain.ExternalUser, error) {
|
||||||
ctx := httpRequest.Context()
|
ctx := httpRequest.Context()
|
||||||
@ -86,6 +88,9 @@ func (l *Login) runPostExternalAuthenticationActions(
|
|||||||
actions.SetFields("externalUser", func(c *actions.FieldConfig) interface{} {
|
actions.SetFields("externalUser", func(c *actions.FieldConfig) interface{} {
|
||||||
return object.UserFromExternalUser(c, user)
|
return object.UserFromExternalUser(c, user)
|
||||||
}),
|
}),
|
||||||
|
actions.SetFields("providerInfo", func(c *actions.FieldConfig) interface{} {
|
||||||
|
return c.Runtime.ToValue(idpUser)
|
||||||
|
}),
|
||||||
actions.SetFields("authRequest", object.AuthRequestField(authRequest)),
|
actions.SetFields("authRequest", object.AuthRequestField(authRequest)),
|
||||||
actions.SetFields("httpRequest", object.HTTPRequestField(httpRequest)),
|
actions.SetFields("httpRequest", object.HTTPRequestField(httpRequest)),
|
||||||
actions.SetFields("authError", authErrStr),
|
actions.SetFields("authError", authErrStr),
|
||||||
@ -337,18 +342,39 @@ func (l *Login) runPostCreationActions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tokenCtxFields(tokens *oidc.Tokens) []actions.FieldOption {
|
func tokenCtxFields(tokens *oidc.Tokens) []actions.FieldOption {
|
||||||
return []actions.FieldOption{
|
var accessToken, idToken string
|
||||||
actions.SetFields("accessToken", tokens.AccessToken),
|
getClaim := func(claim string) interface{} {
|
||||||
actions.SetFields("idToken", tokens.IDToken),
|
return nil
|
||||||
actions.SetFields("getClaim", func(claim string) interface{} {
|
}
|
||||||
|
claimsJSON := func() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if tokens == nil {
|
||||||
|
return []actions.FieldOption{
|
||||||
|
actions.SetFields("accessToken", accessToken),
|
||||||
|
actions.SetFields("idToken", idToken),
|
||||||
|
actions.SetFields("getClaim", getClaim),
|
||||||
|
actions.SetFields("claimsJSON", claimsJSON),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessToken = tokens.AccessToken
|
||||||
|
idToken = tokens.IDToken
|
||||||
|
if tokens.IDTokenClaims != nil {
|
||||||
|
getClaim = func(claim string) interface{} {
|
||||||
return tokens.IDTokenClaims.GetClaim(claim)
|
return tokens.IDTokenClaims.GetClaim(claim)
|
||||||
}),
|
}
|
||||||
actions.SetFields("claimsJSON", func() (string, error) {
|
claimsJSON = func() (string, error) {
|
||||||
c, err := json.Marshal(tokens.IDTokenClaims)
|
c, err := json.Marshal(tokens.IDTokenClaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(c), nil
|
return string(c), nil
|
||||||
}),
|
}
|
||||||
|
}
|
||||||
|
return []actions.FieldOption{
|
||||||
|
actions.SetFields("accessToken", accessToken),
|
||||||
|
actions.SetFields("idToken", idToken),
|
||||||
|
actions.SetFields("getClaim", getClaim),
|
||||||
|
actions.SetFields("claimsJSON", claimsJSON),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/idp"
|
"github.com/zitadel/zitadel/internal/idp"
|
||||||
"github.com/zitadel/zitadel/internal/idp/providers/google"
|
"github.com/zitadel/zitadel/internal/idp/providers/google"
|
||||||
"github.com/zitadel/zitadel/internal/idp/providers/jwt"
|
"github.com/zitadel/zitadel/internal/idp/providers/jwt"
|
||||||
|
"github.com/zitadel/zitadel/internal/idp/providers/oauth"
|
||||||
openid "github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
openid "github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
)
|
)
|
||||||
@ -134,14 +135,15 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
|||||||
}
|
}
|
||||||
var provider idp.Provider
|
var provider idp.Provider
|
||||||
switch identityProvider.Type {
|
switch identityProvider.Type {
|
||||||
|
case domain.IDPTypeOAuth:
|
||||||
|
provider, err = l.oauthProvider(r.Context(), identityProvider)
|
||||||
case domain.IDPTypeOIDC:
|
case domain.IDPTypeOIDC:
|
||||||
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
||||||
case domain.IDPTypeJWT:
|
case domain.IDPTypeJWT:
|
||||||
provider, err = l.jwtProvider(identityProvider)
|
provider, err = l.jwtProvider(identityProvider)
|
||||||
case domain.IDPTypeGoogle:
|
case domain.IDPTypeGoogle:
|
||||||
provider, err = l.googleProvider(r.Context(), identityProvider)
|
provider, err = l.googleProvider(r.Context(), identityProvider)
|
||||||
case domain.IDPTypeOAuth,
|
case domain.IDPTypeLDAP,
|
||||||
domain.IDPTypeLDAP,
|
|
||||||
domain.IDPTypeAzureAD,
|
domain.IDPTypeAzureAD,
|
||||||
domain.IDPTypeGitHub,
|
domain.IDPTypeGitHub,
|
||||||
domain.IDPTypeGitHubEE,
|
domain.IDPTypeGitHubEE,
|
||||||
@ -177,33 +179,39 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
|||||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||||
authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID)
|
authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.externalAuthFailed(w, r, authReq, nil, err)
|
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
identityProvider, err := l.getIDPByID(r, authReq.SelectedIDPConfigID)
|
identityProvider, err := l.getIDPByID(r, authReq.SelectedIDPConfigID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.externalAuthFailed(w, r, authReq, nil, err)
|
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var provider idp.Provider
|
var provider idp.Provider
|
||||||
var session idp.Session
|
var session idp.Session
|
||||||
switch identityProvider.Type {
|
switch identityProvider.Type {
|
||||||
|
case domain.IDPTypeOAuth:
|
||||||
|
provider, err = l.oauthProvider(r.Context(), identityProvider)
|
||||||
|
if err != nil {
|
||||||
|
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
session = &oauth.Session{Provider: provider.(*oauth.Provider), Code: data.Code}
|
||||||
case domain.IDPTypeOIDC:
|
case domain.IDPTypeOIDC:
|
||||||
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.externalAuthFailed(w, r, authReq, nil, err)
|
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session = &openid.Session{Provider: provider.(*openid.Provider), Code: data.Code}
|
session = &openid.Session{Provider: provider.(*openid.Provider), Code: data.Code}
|
||||||
case domain.IDPTypeGoogle:
|
case domain.IDPTypeGoogle:
|
||||||
provider, err = l.googleProvider(r.Context(), identityProvider)
|
provider, err = l.googleProvider(r.Context(), identityProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.externalAuthFailed(w, r, authReq, nil, err)
|
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session = &openid.Session{Provider: provider.(*google.Provider).Provider, Code: data.Code}
|
session = &openid.Session{Provider: provider.(*google.Provider).Provider, Code: data.Code}
|
||||||
case domain.IDPTypeJWT,
|
case domain.IDPTypeJWT,
|
||||||
domain.IDPTypeOAuth,
|
|
||||||
domain.IDPTypeLDAP,
|
domain.IDPTypeLDAP,
|
||||||
domain.IDPTypeAzureAD,
|
domain.IDPTypeAzureAD,
|
||||||
domain.IDPTypeGitHub,
|
domain.IDPTypeGitHub,
|
||||||
@ -219,7 +227,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
|||||||
|
|
||||||
user, err := session.FetchUser(r.Context())
|
user, err := session.FetchUser(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.externalAuthFailed(w, r, authReq, tokens(session), err)
|
l.externalAuthFailed(w, r, authReq, tokens(session), user, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
||||||
@ -236,7 +244,7 @@ func (l *Login) handleExternalUserAuthenticated(
|
|||||||
callback func(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest),
|
callback func(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest),
|
||||||
) {
|
) {
|
||||||
externalUser := mapIDPUserToExternalUser(user, provider.ID)
|
externalUser := mapIDPUserToExternalUser(user, provider.ID)
|
||||||
externalUser, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, nil)
|
externalUser, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, user, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.renderError(w, r, authReq, err)
|
l.renderError(w, r, authReq, err)
|
||||||
return
|
return
|
||||||
@ -600,6 +608,31 @@ func (l *Login) jwtProvider(identityProvider *query.IDPTemplate) (*jwt.Provider,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Login) oauthProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*oauth.Provider, error) {
|
||||||
|
secret, err := crypto.DecryptString(identityProvider.OAuthIDPTemplate.ClientSecret, l.idpConfigAlg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config := &oauth2.Config{
|
||||||
|
ClientID: identityProvider.OAuthIDPTemplate.ClientID,
|
||||||
|
ClientSecret: secret,
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: identityProvider.OAuthIDPTemplate.AuthorizationEndpoint,
|
||||||
|
TokenURL: identityProvider.OAuthIDPTemplate.TokenEndpoint,
|
||||||
|
},
|
||||||
|
RedirectURL: l.baseURL(ctx) + EndpointExternalLoginCallback,
|
||||||
|
Scopes: identityProvider.OAuthIDPTemplate.Scopes,
|
||||||
|
}
|
||||||
|
return oauth.New(
|
||||||
|
config,
|
||||||
|
identityProvider.Name,
|
||||||
|
identityProvider.OAuthIDPTemplate.UserEndpoint,
|
||||||
|
func() idp.User {
|
||||||
|
return oauth.NewUserMapper(identityProvider.OAuthIDPTemplate.IDAttribute)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserGrant, resourceOwner string) error {
|
func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserGrant, resourceOwner string) error {
|
||||||
if len(userGrants) == 0 {
|
if len(userGrants) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -613,11 +646,8 @@ func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserG
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens, err error) {
|
func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens, user idp.User, err error) {
|
||||||
if tokens == nil {
|
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, user, err); actionErr != nil {
|
||||||
tokens = &oidc.Tokens{Token: &oauth2.Token{}}
|
|
||||||
}
|
|
||||||
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, err); actionErr != nil {
|
|
||||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||||
}
|
}
|
||||||
l.renderLogin(w, r, authReq, err)
|
l.renderLogin(w, r, authReq, err)
|
||||||
|
@ -66,8 +66,7 @@ func (l *Login) handleJWTRequest(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, identityProvider *query.IDPTemplate) {
|
func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, identityProvider *query.IDPTemplate) {
|
||||||
token, err := getToken(r, identityProvider.JWTIDPTemplate.HeaderName)
|
token, err := getToken(r, identityProvider.JWTIDPTemplate.HeaderName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
emptyTokens := &oidc.Tokens{Token: &oauth2.Token{}}
|
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
|
||||||
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, emptyTokens, authReq, r, err); actionErr != nil {
|
|
||||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +75,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
|
|||||||
}
|
}
|
||||||
provider, err := l.jwtProvider(identityProvider)
|
provider, err := l.jwtProvider(identityProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
emptyTokens := &oidc.Tokens{Token: &oauth2.Token{}}
|
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
|
||||||
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, emptyTokens, authReq, r, err); actionErr != nil {
|
|
||||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||||
}
|
}
|
||||||
l.renderError(w, r, authReq, err)
|
l.renderError(w, r, authReq, err)
|
||||||
@ -86,7 +84,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
|
|||||||
session := &jwt.Session{Provider: provider, Tokens: &oidc.Tokens{IDToken: token, Token: &oauth2.Token{}}}
|
session := &jwt.Session{Provider: provider, Tokens: &oidc.Tokens{IDToken: token, Token: &oauth2.Token{}}}
|
||||||
user, err := session.FetchUser(r.Context())
|
user, err := session.FetchUser(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens(session), authReq, r, err); actionErr != nil {
|
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), tokens(session), authReq, r, user, err); actionErr != nil {
|
||||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||||
}
|
}
|
||||||
l.renderError(w, r, authReq, err)
|
l.renderError(w, r, authReq, err)
|
||||||
|
@ -16,6 +16,7 @@ type GenericOAuthProvider struct {
|
|||||||
TokenEndpoint string
|
TokenEndpoint string
|
||||||
UserEndpoint string
|
UserEndpoint string
|
||||||
Scopes []string
|
Scopes []string
|
||||||
|
IDAttribute string
|
||||||
IDPOptions idp.Options
|
IDPOptions idp.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ type OAuthIDPWriteModel struct {
|
|||||||
TokenEndpoint string
|
TokenEndpoint string
|
||||||
UserEndpoint string
|
UserEndpoint string
|
||||||
Scopes []string
|
Scopes []string
|
||||||
|
IDAttribute string
|
||||||
idp.Options
|
idp.Options
|
||||||
|
|
||||||
State domain.IDPState
|
State domain.IDPState
|
||||||
@ -48,6 +49,7 @@ func (wm *OAuthIDPWriteModel) reduceAddedEvent(e *idp.OAuthIDPAddedEvent) {
|
|||||||
wm.TokenEndpoint = e.TokenEndpoint
|
wm.TokenEndpoint = e.TokenEndpoint
|
||||||
wm.UserEndpoint = e.UserEndpoint
|
wm.UserEndpoint = e.UserEndpoint
|
||||||
wm.Scopes = e.Scopes
|
wm.Scopes = e.Scopes
|
||||||
|
wm.IDAttribute = e.IDAttribute
|
||||||
wm.State = domain.IDPStateActive
|
wm.State = domain.IDPStateActive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +75,9 @@ func (wm *OAuthIDPWriteModel) reduceChangedEvent(e *idp.OAuthIDPChangedEvent) {
|
|||||||
if e.Scopes != nil {
|
if e.Scopes != nil {
|
||||||
wm.Scopes = e.Scopes
|
wm.Scopes = e.Scopes
|
||||||
}
|
}
|
||||||
|
if e.IDAttribute != nil {
|
||||||
|
wm.IDAttribute = *e.IDAttribute
|
||||||
|
}
|
||||||
wm.Options.ReduceChanges(e.OptionChanges)
|
wm.Options.ReduceChanges(e.OptionChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +88,8 @@ func (wm *OAuthIDPWriteModel) NewChanges(
|
|||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.Crypto,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.OAuthIDPChanges, error) {
|
) ([]idp.OAuthIDPChanges, error) {
|
||||||
@ -115,6 +121,9 @@ func (wm *OAuthIDPWriteModel) NewChanges(
|
|||||||
if !reflect.DeepEqual(wm.Scopes, scopes) {
|
if !reflect.DeepEqual(wm.Scopes, scopes) {
|
||||||
changes = append(changes, idp.ChangeOAuthScopes(scopes))
|
changes = append(changes, idp.ChangeOAuthScopes(scopes))
|
||||||
}
|
}
|
||||||
|
if wm.IDAttribute != idAttribute {
|
||||||
|
changes = append(changes, idp.ChangeOAuthIDAttribute(idAttribute))
|
||||||
|
}
|
||||||
opts := wm.Options.Changes(options)
|
opts := wm.Options.Changes(options)
|
||||||
if !opts.IsZero() {
|
if !opts.IsZero() {
|
||||||
changes = append(changes, idp.ChangeOAuthOptions(opts))
|
changes = append(changes, idp.ChangeOAuthOptions(opts))
|
||||||
|
@ -273,6 +273,9 @@ func (c *Commands) prepareAddInstanceOAuthProvider(a *instance.Aggregate, writeM
|
|||||||
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
|
||||||
}
|
}
|
||||||
|
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf3f", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
events, err := filter(ctx, writeModel.Query())
|
events, err := filter(ctx, writeModel.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -297,6 +300,7 @@ func (c *Commands) prepareAddInstanceOAuthProvider(a *instance.Aggregate, writeM
|
|||||||
provider.AuthorizationEndpoint,
|
provider.AuthorizationEndpoint,
|
||||||
provider.TokenEndpoint,
|
provider.TokenEndpoint,
|
||||||
provider.UserEndpoint,
|
provider.UserEndpoint,
|
||||||
|
provider.IDAttribute,
|
||||||
provider.Scopes,
|
provider.Scopes,
|
||||||
provider.IDPOptions,
|
provider.IDPOptions,
|
||||||
),
|
),
|
||||||
@ -322,6 +326,9 @@ func (c *Commands) prepareUpdateInstanceOAuthProvider(a *instance.Aggregate, wri
|
|||||||
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
|
||||||
}
|
}
|
||||||
|
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-asf3fs", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
events, err := filter(ctx, writeModel.Query())
|
events, err := filter(ctx, writeModel.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -345,6 +352,7 @@ func (c *Commands) prepareUpdateInstanceOAuthProvider(a *instance.Aggregate, wri
|
|||||||
provider.AuthorizationEndpoint,
|
provider.AuthorizationEndpoint,
|
||||||
provider.TokenEndpoint,
|
provider.TokenEndpoint,
|
||||||
provider.UserEndpoint,
|
provider.UserEndpoint,
|
||||||
|
provider.IDAttribute,
|
||||||
provider.Scopes,
|
provider.Scopes,
|
||||||
provider.IDPOptions,
|
provider.IDPOptions,
|
||||||
)
|
)
|
||||||
|
@ -67,7 +67,8 @@ func (wm *InstanceOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.Crypto,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.OAuthIDPChangedEvent, error) {
|
) (*instance.OAuthIDPChangedEvent, error) {
|
||||||
@ -80,6 +81,7 @@ func (wm *InstanceOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
|
idAttribute,
|
||||||
scopes,
|
scopes,
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
@ -145,6 +145,27 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
err: caos_errors.IsErrorInvalidArgument,
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid id attribute",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||||
|
provider: GenericOAuthProvider{
|
||||||
|
Name: "name",
|
||||||
|
ClientID: "clientID",
|
||||||
|
ClientSecret: "clientSecret",
|
||||||
|
AuthorizationEndpoint: "auth",
|
||||||
|
TokenEndpoint: "token",
|
||||||
|
UserEndpoint: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ok",
|
name: "ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -167,6 +188,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -185,6 +207,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -214,6 +237,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
[]string{"user"},
|
[]string{"user"},
|
||||||
idp.Options{
|
idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
@ -238,6 +262,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
Scopes: []string{"user"},
|
Scopes: []string{"user"},
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
IDPOptions: idp.Options{
|
IDPOptions: idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
IsLinkingAllowed: true,
|
IsLinkingAllowed: true,
|
||||||
@ -390,6 +415,26 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
err: caos_errors.IsErrorInvalidArgument,
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid id attribute",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||||
|
id: "id1",
|
||||||
|
provider: GenericOAuthProvider{
|
||||||
|
Name: "name",
|
||||||
|
ClientID: "clientID",
|
||||||
|
AuthorizationEndpoint: "auth",
|
||||||
|
TokenEndpoint: "token",
|
||||||
|
UserEndpoint: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "not found",
|
name: "not found",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -406,6 +451,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -431,6 +477,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -446,6 +493,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -471,6 +519,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -496,6 +545,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
idp.ChangeOAuthTokenEndpoint("new token"),
|
idp.ChangeOAuthTokenEndpoint("new token"),
|
||||||
idp.ChangeOAuthUserEndpoint("new user"),
|
idp.ChangeOAuthUserEndpoint("new user"),
|
||||||
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
|
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
|
||||||
|
idp.ChangeOAuthIDAttribute("newAttribute"),
|
||||||
idp.ChangeOAuthOptions(idp.OptionChanges{
|
idp.ChangeOAuthOptions(idp.OptionChanges{
|
||||||
IsCreationAllowed: &t,
|
IsCreationAllowed: &t,
|
||||||
IsLinkingAllowed: &t,
|
IsLinkingAllowed: &t,
|
||||||
@ -523,6 +573,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
|
|||||||
TokenEndpoint: "new token",
|
TokenEndpoint: "new token",
|
||||||
UserEndpoint: "new user",
|
UserEndpoint: "new user",
|
||||||
Scopes: []string{"openid", "profile"},
|
Scopes: []string{"openid", "profile"},
|
||||||
|
IDAttribute: "newAttribute",
|
||||||
IDPOptions: idp.Options{
|
IDPOptions: idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
IsLinkingAllowed: true,
|
IsLinkingAllowed: true,
|
||||||
|
@ -262,6 +262,9 @@ func (c *Commands) prepareAddOrgOAuthProvider(a *org.Aggregate, writeModel *OrgO
|
|||||||
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
|
||||||
}
|
}
|
||||||
|
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sadf3d", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
events, err := filter(ctx, writeModel.Query())
|
events, err := filter(ctx, writeModel.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -286,6 +289,7 @@ func (c *Commands) prepareAddOrgOAuthProvider(a *org.Aggregate, writeModel *OrgO
|
|||||||
provider.AuthorizationEndpoint,
|
provider.AuthorizationEndpoint,
|
||||||
provider.TokenEndpoint,
|
provider.TokenEndpoint,
|
||||||
provider.UserEndpoint,
|
provider.UserEndpoint,
|
||||||
|
provider.IDAttribute,
|
||||||
provider.Scopes,
|
provider.Scopes,
|
||||||
provider.IDPOptions,
|
provider.IDPOptions,
|
||||||
),
|
),
|
||||||
@ -314,6 +318,9 @@ func (c *Commands) prepareUpdateOrgOAuthProvider(a *org.Aggregate, writeModel *O
|
|||||||
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
|
||||||
}
|
}
|
||||||
|
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAe4gh", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
events, err := filter(ctx, writeModel.Query())
|
events, err := filter(ctx, writeModel.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -337,6 +344,7 @@ func (c *Commands) prepareUpdateOrgOAuthProvider(a *org.Aggregate, writeModel *O
|
|||||||
provider.AuthorizationEndpoint,
|
provider.AuthorizationEndpoint,
|
||||||
provider.TokenEndpoint,
|
provider.TokenEndpoint,
|
||||||
provider.UserEndpoint,
|
provider.UserEndpoint,
|
||||||
|
provider.IDAttribute,
|
||||||
provider.Scopes,
|
provider.Scopes,
|
||||||
provider.IDPOptions,
|
provider.IDPOptions,
|
||||||
)
|
)
|
||||||
|
@ -69,7 +69,8 @@ func (wm *OrgOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.Crypto,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.OAuthIDPChangedEvent, error) {
|
) (*org.OAuthIDPChangedEvent, error) {
|
||||||
@ -82,6 +83,7 @@ func (wm *OrgOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
|
idAttribute,
|
||||||
scopes,
|
scopes,
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
@ -150,6 +150,28 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
err: caos_errors.IsErrorInvalidArgument,
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid id attribute",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
resourceOwner: "org1",
|
||||||
|
provider: GenericOAuthProvider{
|
||||||
|
Name: "name",
|
||||||
|
ClientID: "clientID",
|
||||||
|
ClientSecret: "clientSecret",
|
||||||
|
AuthorizationEndpoint: "auth",
|
||||||
|
TokenEndpoint: "token",
|
||||||
|
UserEndpoint: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ok",
|
name: "ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -170,6 +192,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -188,6 +211,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -215,6 +239,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
[]string{"user"},
|
[]string{"user"},
|
||||||
idp.Options{
|
idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
@ -239,6 +264,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
Scopes: []string{"user"},
|
Scopes: []string{"user"},
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
IDPOptions: idp.Options{
|
IDPOptions: idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
IsLinkingAllowed: true,
|
IsLinkingAllowed: true,
|
||||||
@ -398,6 +424,27 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
err: caos_errors.IsErrorInvalidArgument,
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"invalid id attribute",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
resourceOwner: "org1",
|
||||||
|
id: "id1",
|
||||||
|
provider: GenericOAuthProvider{
|
||||||
|
Name: "name",
|
||||||
|
ClientID: "clientID",
|
||||||
|
AuthorizationEndpoint: "auth",
|
||||||
|
TokenEndpoint: "token",
|
||||||
|
UserEndpoint: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errors.IsErrorInvalidArgument,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "not found",
|
name: "not found",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -415,6 +462,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -440,6 +488,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -456,6 +505,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
AuthorizationEndpoint: "auth",
|
AuthorizationEndpoint: "auth",
|
||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
|
IDAttribute: "idAttribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -481,6 +531,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
"auth",
|
"auth",
|
||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
|
"idAttribute",
|
||||||
nil,
|
nil,
|
||||||
idp.Options{},
|
idp.Options{},
|
||||||
)),
|
)),
|
||||||
@ -504,6 +555,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
idp.ChangeOAuthTokenEndpoint("new token"),
|
idp.ChangeOAuthTokenEndpoint("new token"),
|
||||||
idp.ChangeOAuthUserEndpoint("new user"),
|
idp.ChangeOAuthUserEndpoint("new user"),
|
||||||
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
|
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
|
||||||
|
idp.ChangeOAuthIDAttribute("newAttribute"),
|
||||||
idp.ChangeOAuthOptions(idp.OptionChanges{
|
idp.ChangeOAuthOptions(idp.OptionChanges{
|
||||||
IsCreationAllowed: &t,
|
IsCreationAllowed: &t,
|
||||||
IsLinkingAllowed: &t,
|
IsLinkingAllowed: &t,
|
||||||
@ -531,6 +583,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
|
|||||||
TokenEndpoint: "new token",
|
TokenEndpoint: "new token",
|
||||||
UserEndpoint: "new user",
|
UserEndpoint: "new user",
|
||||||
Scopes: []string{"openid", "profile"},
|
Scopes: []string{"openid", "profile"},
|
||||||
|
IDAttribute: "newAttribute",
|
||||||
IDPOptions: idp.Options{
|
IDPOptions: idp.Options{
|
||||||
IsCreationAllowed: true,
|
IsCreationAllowed: true,
|
||||||
IsLinkingAllowed: true,
|
IsLinkingAllowed: true,
|
||||||
|
@ -2,6 +2,8 @@ package oauth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
@ -11,92 +13,97 @@ import (
|
|||||||
var _ idp.User = (*UserMapper)(nil)
|
var _ idp.User = (*UserMapper)(nil)
|
||||||
|
|
||||||
// UserMapper is an implementation of [idp.User].
|
// UserMapper is an implementation of [idp.User].
|
||||||
// It can be used in ZITADEL actions to map the raw `info`
|
// It can be used in ZITADEL actions to map the `RawInfo`
|
||||||
type UserMapper struct {
|
type UserMapper struct {
|
||||||
ID string
|
idAttribute string
|
||||||
FirstName string
|
RawInfo map[string]interface{}
|
||||||
LastName string
|
}
|
||||||
DisplayName string
|
|
||||||
NickName string
|
func NewUserMapper(idAttribute string) *UserMapper {
|
||||||
PreferredUsername string
|
return &UserMapper{
|
||||||
Email string
|
idAttribute: idAttribute,
|
||||||
EmailVerified bool
|
RawInfo: make(map[string]interface{}),
|
||||||
Phone string
|
}
|
||||||
PhoneVerified bool
|
|
||||||
PreferredLanguage string
|
|
||||||
AvatarURL string
|
|
||||||
Profile string
|
|
||||||
info map[string]interface{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserMapper) UnmarshalJSON(data []byte) error {
|
func (u *UserMapper) UnmarshalJSON(data []byte) error {
|
||||||
if u.info == nil {
|
return json.Unmarshal(data, &u.RawInfo)
|
||||||
u.info = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
return json.Unmarshal(data, &u.info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID is an implementation of the [idp.User] interface.
|
// GetID is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetID() string {
|
func (u *UserMapper) GetID() string {
|
||||||
return u.ID
|
id, ok := u.RawInfo[u.idAttribute]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch i := id.(type) {
|
||||||
|
case string:
|
||||||
|
return i
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(i)
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(i, 'f', -1, 64)
|
||||||
|
default:
|
||||||
|
return fmt.Sprint(i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirstName is an implementation of the [idp.User] interface.
|
// GetFirstName is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetFirstName() string {
|
func (u *UserMapper) GetFirstName() string {
|
||||||
return u.FirstName
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLastName is an implementation of the [idp.User] interface.
|
// GetLastName is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetLastName() string {
|
func (u *UserMapper) GetLastName() string {
|
||||||
return u.LastName
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisplayName is an implementation of the [idp.User] interface.
|
// GetDisplayName is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetDisplayName() string {
|
func (u *UserMapper) GetDisplayName() string {
|
||||||
return u.DisplayName
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNickname is an implementation of the [idp.User] interface.
|
// GetNickname is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetNickname() string {
|
func (u *UserMapper) GetNickname() string {
|
||||||
return u.NickName
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreferredUsername is an implementation of the [idp.User] interface.
|
// GetPreferredUsername is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetPreferredUsername() string {
|
func (u *UserMapper) GetPreferredUsername() string {
|
||||||
return u.PreferredUsername
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmail is an implementation of the [idp.User] interface.
|
// GetEmail is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetEmail() string {
|
func (u *UserMapper) GetEmail() string {
|
||||||
return u.Email
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmailVerified is an implementation of the [idp.User] interface.
|
// IsEmailVerified is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) IsEmailVerified() bool {
|
func (u *UserMapper) IsEmailVerified() bool {
|
||||||
return u.EmailVerified
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPhone is an implementation of the [idp.User] interface.
|
// GetPhone is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetPhone() string {
|
func (u *UserMapper) GetPhone() string {
|
||||||
return u.Phone
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPhoneVerified is an implementation of the [idp.User] interface.
|
// IsPhoneVerified is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) IsPhoneVerified() bool {
|
func (u *UserMapper) IsPhoneVerified() bool {
|
||||||
return u.PhoneVerified
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreferredLanguage is an implementation of the [idp.User] interface.
|
// GetPreferredLanguage is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetPreferredLanguage() language.Tag {
|
func (u *UserMapper) GetPreferredLanguage() language.Tag {
|
||||||
return language.Make(u.PreferredLanguage)
|
return language.Und
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvatarURL is an implementation of the [idp.User] interface.
|
// GetAvatarURL is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetAvatarURL() string {
|
func (u *UserMapper) GetAvatarURL() string {
|
||||||
return u.AvatarURL
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProfile is an implementation of the [idp.User] interface.
|
// GetProfile is an implementation of the [idp.User] interface.
|
||||||
func (u *UserMapper) GetProfile() string {
|
func (u *UserMapper) GetProfile() string {
|
||||||
return u.Profile
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -93,9 +93,7 @@ func TestProvider_FetchUser(t *testing.T) {
|
|||||||
Reply(http.StatusInternalServerError)
|
Reply(http.StatusInternalServerError)
|
||||||
},
|
},
|
||||||
userMapper: func() idp.User {
|
userMapper: func() idp.User {
|
||||||
return &UserMapper{
|
return NewUserMapper("userID")
|
||||||
ID: "userID",
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
authURL: "https://oauth2.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
authURL: "https://oauth2.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
||||||
tokens: &oidc.Tokens{
|
tokens: &oidc.Tokens{
|
||||||
@ -135,7 +133,7 @@ func TestProvider_FetchUser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
userMapper: func() idp.User {
|
userMapper: func() idp.User {
|
||||||
return &UserMapper{}
|
return NewUserMapper("userID")
|
||||||
},
|
},
|
||||||
authURL: "https://issuer.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
authURL: "https://issuer.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
||||||
tokens: &oidc.Tokens{
|
tokens: &oidc.Tokens{
|
||||||
@ -147,12 +145,13 @@ func TestProvider_FetchUser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
user: &UserMapper{
|
user: &UserMapper{
|
||||||
info: map[string]interface{}{
|
idAttribute: "userID",
|
||||||
|
RawInfo: map[string]interface{}{
|
||||||
"userID": "id",
|
"userID": "id",
|
||||||
"custom": "claim",
|
"custom": "claim",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "",
|
id: "id",
|
||||||
firstName: "",
|
firstName: "",
|
||||||
lastName: "",
|
lastName: "",
|
||||||
displayName: "",
|
displayName: "",
|
||||||
@ -202,7 +201,7 @@ func TestProvider_FetchUser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
userMapper: func() idp.User {
|
userMapper: func() idp.User {
|
||||||
return &UserMapper{}
|
return NewUserMapper("userID")
|
||||||
},
|
},
|
||||||
authURL: "https://issuer.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
authURL: "https://issuer.com/authorize?client_id=clientID&redirect_uri=redirectURI&response_type=code&scope=user&state=testState",
|
||||||
tokens: nil,
|
tokens: nil,
|
||||||
@ -210,12 +209,13 @@ func TestProvider_FetchUser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
user: &UserMapper{
|
user: &UserMapper{
|
||||||
info: map[string]interface{}{
|
idAttribute: "userID",
|
||||||
|
RawInfo: map[string]interface{}{
|
||||||
"userID": "id",
|
"userID": "id",
|
||||||
"custom": "claim",
|
"custom": "claim",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "",
|
id: "id",
|
||||||
firstName: "",
|
firstName: "",
|
||||||
lastName: "",
|
lastName: "",
|
||||||
displayName: "",
|
displayName: "",
|
||||||
|
@ -54,6 +54,7 @@ type OAuthIDPTemplate struct {
|
|||||||
TokenEndpoint string
|
TokenEndpoint string
|
||||||
UserEndpoint string
|
UserEndpoint string
|
||||||
Scopes database.StringArray
|
Scopes database.StringArray
|
||||||
|
IDAttribute string
|
||||||
}
|
}
|
||||||
|
|
||||||
type OIDCIDPTemplate struct {
|
type OIDCIDPTemplate struct {
|
||||||
@ -196,6 +197,10 @@ var (
|
|||||||
name: projection.OAuthScopesCol,
|
name: projection.OAuthScopesCol,
|
||||||
table: oauthIdpTemplateTable,
|
table: oauthIdpTemplateTable,
|
||||||
}
|
}
|
||||||
|
OAuthIDAttributeCol = Column{
|
||||||
|
name: projection.OAuthIDAttributeCol,
|
||||||
|
table: oauthIdpTemplateTable,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -505,6 +510,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
|||||||
OAuthTokenEndpointCol.identifier(),
|
OAuthTokenEndpointCol.identifier(),
|
||||||
OAuthUserEndpointCol.identifier(),
|
OAuthUserEndpointCol.identifier(),
|
||||||
OAuthScopesCol.identifier(),
|
OAuthScopesCol.identifier(),
|
||||||
|
OAuthIDAttributeCol.identifier(),
|
||||||
// oidc
|
// oidc
|
||||||
OIDCIDCol.identifier(),
|
OIDCIDCol.identifier(),
|
||||||
OIDCIssuerCol.identifier(),
|
OIDCIssuerCol.identifier(),
|
||||||
@ -564,6 +570,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
|||||||
oauthTokenEndpoint := sql.NullString{}
|
oauthTokenEndpoint := sql.NullString{}
|
||||||
oauthUserEndpoint := sql.NullString{}
|
oauthUserEndpoint := sql.NullString{}
|
||||||
oauthScopes := database.StringArray{}
|
oauthScopes := database.StringArray{}
|
||||||
|
oauthIDAttribute := sql.NullString{}
|
||||||
|
|
||||||
oidcID := sql.NullString{}
|
oidcID := sql.NullString{}
|
||||||
oidcIssuer := sql.NullString{}
|
oidcIssuer := sql.NullString{}
|
||||||
@ -627,6 +634,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
|||||||
&oauthTokenEndpoint,
|
&oauthTokenEndpoint,
|
||||||
&oauthUserEndpoint,
|
&oauthUserEndpoint,
|
||||||
&oauthScopes,
|
&oauthScopes,
|
||||||
|
&oauthIDAttribute,
|
||||||
// oidc
|
// oidc
|
||||||
&oidcID,
|
&oidcID,
|
||||||
&oidcIssuer,
|
&oidcIssuer,
|
||||||
@ -686,6 +694,7 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
|||||||
TokenEndpoint: oauthTokenEndpoint.String,
|
TokenEndpoint: oauthTokenEndpoint.String,
|
||||||
UserEndpoint: oauthUserEndpoint.String,
|
UserEndpoint: oauthUserEndpoint.String,
|
||||||
Scopes: oauthScopes,
|
Scopes: oauthScopes,
|
||||||
|
IDAttribute: oauthIDAttribute.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if oidcID.Valid {
|
if oidcID.Valid {
|
||||||
@ -770,6 +779,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
|||||||
OAuthTokenEndpointCol.identifier(),
|
OAuthTokenEndpointCol.identifier(),
|
||||||
OAuthUserEndpointCol.identifier(),
|
OAuthUserEndpointCol.identifier(),
|
||||||
OAuthScopesCol.identifier(),
|
OAuthScopesCol.identifier(),
|
||||||
|
OAuthIDAttributeCol.identifier(),
|
||||||
// oidc
|
// oidc
|
||||||
OIDCIDCol.identifier(),
|
OIDCIDCol.identifier(),
|
||||||
OIDCIssuerCol.identifier(),
|
OIDCIssuerCol.identifier(),
|
||||||
@ -833,6 +843,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
|||||||
oauthTokenEndpoint := sql.NullString{}
|
oauthTokenEndpoint := sql.NullString{}
|
||||||
oauthUserEndpoint := sql.NullString{}
|
oauthUserEndpoint := sql.NullString{}
|
||||||
oauthScopes := database.StringArray{}
|
oauthScopes := database.StringArray{}
|
||||||
|
oauthIDAttribute := sql.NullString{}
|
||||||
|
|
||||||
oidcID := sql.NullString{}
|
oidcID := sql.NullString{}
|
||||||
oidcIssuer := sql.NullString{}
|
oidcIssuer := sql.NullString{}
|
||||||
@ -896,6 +907,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
|||||||
&oauthTokenEndpoint,
|
&oauthTokenEndpoint,
|
||||||
&oauthUserEndpoint,
|
&oauthUserEndpoint,
|
||||||
&oauthScopes,
|
&oauthScopes,
|
||||||
|
&oauthIDAttribute,
|
||||||
// oidc
|
// oidc
|
||||||
&oidcID,
|
&oidcID,
|
||||||
&oidcIssuer,
|
&oidcIssuer,
|
||||||
@ -954,6 +966,7 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
|||||||
TokenEndpoint: oauthTokenEndpoint.String,
|
TokenEndpoint: oauthTokenEndpoint.String,
|
||||||
UserEndpoint: oauthUserEndpoint.String,
|
UserEndpoint: oauthUserEndpoint.String,
|
||||||
Scopes: oauthScopes,
|
Scopes: oauthScopes,
|
||||||
|
IDAttribute: oauthIDAttribute.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if oidcID.Valid {
|
if oidcID.Valid {
|
||||||
|
@ -29,13 +29,14 @@ var (
|
|||||||
` projections.idp_templates2.is_auto_creation,` +
|
` projections.idp_templates2.is_auto_creation,` +
|
||||||
` projections.idp_templates2.is_auto_update,` +
|
` projections.idp_templates2.is_auto_update,` +
|
||||||
// oauth
|
// oauth
|
||||||
` projections.idp_templates2_oauth.idp_id,` +
|
` projections.idp_templates2_oauth2.idp_id,` +
|
||||||
` projections.idp_templates2_oauth.client_id,` +
|
` projections.idp_templates2_oauth2.client_id,` +
|
||||||
` projections.idp_templates2_oauth.client_secret,` +
|
` projections.idp_templates2_oauth2.client_secret,` +
|
||||||
` projections.idp_templates2_oauth.authorization_endpoint,` +
|
` projections.idp_templates2_oauth2.authorization_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.token_endpoint,` +
|
` projections.idp_templates2_oauth2.token_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.user_endpoint,` +
|
` projections.idp_templates2_oauth2.user_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.scopes,` +
|
` projections.idp_templates2_oauth2.scopes,` +
|
||||||
|
` projections.idp_templates2_oauth2.id_attribute,` +
|
||||||
// oidc
|
// oidc
|
||||||
` projections.idp_templates2_oidc.idp_id,` +
|
` projections.idp_templates2_oidc.idp_id,` +
|
||||||
` projections.idp_templates2_oidc.issuer,` +
|
` projections.idp_templates2_oidc.issuer,` +
|
||||||
@ -77,7 +78,7 @@ var (
|
|||||||
` projections.idp_templates2_ldap.avatar_url_attribute,` +
|
` projections.idp_templates2_ldap.avatar_url_attribute,` +
|
||||||
` projections.idp_templates2_ldap.profile_attribute` +
|
` projections.idp_templates2_ldap.profile_attribute` +
|
||||||
` FROM projections.idp_templates2` +
|
` FROM projections.idp_templates2` +
|
||||||
` LEFT JOIN projections.idp_templates2_oauth ON projections.idp_templates2.id = projections.idp_templates2_oauth.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oauth.instance_id` +
|
` LEFT JOIN projections.idp_templates2_oauth2 ON projections.idp_templates2.id = projections.idp_templates2_oauth2.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oauth2.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
||||||
@ -105,6 +106,7 @@ var (
|
|||||||
"token_endpoint",
|
"token_endpoint",
|
||||||
"user_endpoint",
|
"user_endpoint",
|
||||||
"scopes",
|
"scopes",
|
||||||
|
"id_attribute",
|
||||||
// oidc config
|
// oidc config
|
||||||
"id_id",
|
"id_id",
|
||||||
"issuer",
|
"issuer",
|
||||||
@ -160,13 +162,14 @@ var (
|
|||||||
` projections.idp_templates2.is_auto_creation,` +
|
` projections.idp_templates2.is_auto_creation,` +
|
||||||
` projections.idp_templates2.is_auto_update,` +
|
` projections.idp_templates2.is_auto_update,` +
|
||||||
// oauth
|
// oauth
|
||||||
` projections.idp_templates2_oauth.idp_id,` +
|
` projections.idp_templates2_oauth2.idp_id,` +
|
||||||
` projections.idp_templates2_oauth.client_id,` +
|
` projections.idp_templates2_oauth2.client_id,` +
|
||||||
` projections.idp_templates2_oauth.client_secret,` +
|
` projections.idp_templates2_oauth2.client_secret,` +
|
||||||
` projections.idp_templates2_oauth.authorization_endpoint,` +
|
` projections.idp_templates2_oauth2.authorization_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.token_endpoint,` +
|
` projections.idp_templates2_oauth2.token_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.user_endpoint,` +
|
` projections.idp_templates2_oauth2.user_endpoint,` +
|
||||||
` projections.idp_templates2_oauth.scopes,` +
|
` projections.idp_templates2_oauth2.scopes,` +
|
||||||
|
` projections.idp_templates2_oauth2.id_attribute,` +
|
||||||
// oidc
|
// oidc
|
||||||
` projections.idp_templates2_oidc.idp_id,` +
|
` projections.idp_templates2_oidc.idp_id,` +
|
||||||
` projections.idp_templates2_oidc.issuer,` +
|
` projections.idp_templates2_oidc.issuer,` +
|
||||||
@ -209,7 +212,7 @@ var (
|
|||||||
` projections.idp_templates2_ldap.profile_attribute,` +
|
` projections.idp_templates2_ldap.profile_attribute,` +
|
||||||
` COUNT(*) OVER ()` +
|
` COUNT(*) OVER ()` +
|
||||||
` FROM projections.idp_templates2` +
|
` FROM projections.idp_templates2` +
|
||||||
` LEFT JOIN projections.idp_templates2_oauth ON projections.idp_templates2.id = projections.idp_templates2_oauth.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oauth.instance_id` +
|
` LEFT JOIN projections.idp_templates2_oauth2 ON projections.idp_templates2.id = projections.idp_templates2_oauth2.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oauth2.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
||||||
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
||||||
@ -237,6 +240,7 @@ var (
|
|||||||
"token_endpoint",
|
"token_endpoint",
|
||||||
"user_endpoint",
|
"user_endpoint",
|
||||||
"scopes",
|
"scopes",
|
||||||
|
"id_attribute",
|
||||||
// oidc config
|
// oidc config
|
||||||
"id_id",
|
"id_id",
|
||||||
"issuer",
|
"issuer",
|
||||||
@ -339,6 +343,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
database.StringArray{"profile"},
|
database.StringArray{"profile"},
|
||||||
|
"id-attribute",
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -404,6 +409,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
Scopes: []string{"profile"},
|
Scopes: []string{"profile"},
|
||||||
|
IDAttribute: "id-attribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -436,6 +442,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
"idp-id",
|
"idp-id",
|
||||||
"issuer",
|
"issuer",
|
||||||
@ -531,6 +538,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -626,6 +634,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -720,6 +729,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -833,6 +843,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -957,6 +968,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1079,6 +1091,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1176,6 +1189,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1239,6 +1253,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1302,6 +1317,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
database.StringArray{"profile"},
|
database.StringArray{"profile"},
|
||||||
|
"id-attribute",
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1365,6 +1381,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
"idp-id-oidc",
|
"idp-id-oidc",
|
||||||
"issuer",
|
"issuer",
|
||||||
@ -1428,6 +1445,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
// oidc
|
// oidc
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -1561,6 +1579,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
|||||||
TokenEndpoint: "token",
|
TokenEndpoint: "token",
|
||||||
UserEndpoint: "user",
|
UserEndpoint: "user",
|
||||||
Scopes: []string{"profile"},
|
Scopes: []string{"profile"},
|
||||||
|
IDAttribute: "id-attribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,10 @@ func (p *idpLoginPolicyLinkProjection) reducers() []handler.AggregateReducer {
|
|||||||
Event: org.IDPConfigRemovedEventType,
|
Event: org.IDPConfigRemovedEventType,
|
||||||
Reduce: p.reduceIDPConfigRemoved,
|
Reduce: p.reduceIDPConfigRemoved,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: org.IDPRemovedEventType,
|
||||||
|
Reduce: p.reduceIDPRemoved,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: org.OrgRemovedEventType,
|
Event: org.OrgRemovedEventType,
|
||||||
Reduce: p.reduceOwnerRemoved,
|
Reduce: p.reduceOwnerRemoved,
|
||||||
@ -106,6 +110,10 @@ func (p *idpLoginPolicyLinkProjection) reducers() []handler.AggregateReducer {
|
|||||||
Event: instance.IDPConfigRemovedEventType,
|
Event: instance.IDPConfigRemovedEventType,
|
||||||
Reduce: p.reduceIDPConfigRemoved,
|
Reduce: p.reduceIDPConfigRemoved,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: instance.IDPRemovedEventType,
|
||||||
|
Reduce: p.reduceIDPRemoved,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: instance.InstanceRemovedEventType,
|
Event: instance.InstanceRemovedEventType,
|
||||||
Reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol),
|
Reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol),
|
||||||
@ -209,6 +217,27 @@ func (p *idpLoginPolicyLinkProjection) reduceIDPConfigRemoved(event eventstore.E
|
|||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *idpLoginPolicyLinkProjection) reduceIDPRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
var idpID string
|
||||||
|
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *org.IDPRemovedEvent:
|
||||||
|
idpID = e.ID
|
||||||
|
case *instance.IDPRemovedEvent:
|
||||||
|
idpID = e.ID
|
||||||
|
default:
|
||||||
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SFED3", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPRemovedEventType, instance.IDPRemovedEventType})
|
||||||
|
}
|
||||||
|
|
||||||
|
return crdb.NewDeleteStatement(event,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(IDPLoginPolicyLinkIDPIDCol, idpID),
|
||||||
|
handler.NewCond(IDPLoginPolicyLinkResourceOwnerCol, event.Aggregate().ResourceOwner),
|
||||||
|
handler.NewCond(IDPLoginPolicyLinkInstanceIDCol, event.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *idpLoginPolicyLinkProjection) reducePolicyRemoved(event eventstore.Event) (*handler.Statement, error) {
|
func (p *idpLoginPolicyLinkProjection) reducePolicyRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||||
e, ok := event.(*org.LoginPolicyRemovedEvent)
|
e, ok := event.(*org.LoginPolicyRemovedEvent)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -331,6 +331,66 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "org IDPRemovedEvent",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(org.IDPRemovedEventType),
|
||||||
|
org.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"id": "id"
|
||||||
|
}`),
|
||||||
|
), org.IDPRemovedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&idpLoginPolicyLinkProjection{}).reduceIDPRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: org.AggregateType,
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"id",
|
||||||
|
"ro-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "iam IDPRemovedEvent",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(instance.IDPRemovedEventType),
|
||||||
|
instance.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"id": "id"
|
||||||
|
}`),
|
||||||
|
), instance.IDPRemovedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&idpLoginPolicyLinkProjection{}).reduceIDPRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: instance.AggregateType,
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"id",
|
||||||
|
"ro-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "org.reduceOwnerRemoved",
|
name: "org.reduceOwnerRemoved",
|
||||||
reduce: (&idpLoginPolicyLinkProjection{}).reduceOwnerRemoved,
|
reduce: (&idpLoginPolicyLinkProjection{}).reduceOwnerRemoved,
|
||||||
|
@ -24,7 +24,7 @@ const (
|
|||||||
IDPTemplateGoogleTable = IDPTemplateTable + "_" + IDPTemplateGoogleSuffix
|
IDPTemplateGoogleTable = IDPTemplateTable + "_" + IDPTemplateGoogleSuffix
|
||||||
IDPTemplateLDAPTable = IDPTemplateTable + "_" + IDPTemplateLDAPSuffix
|
IDPTemplateLDAPTable = IDPTemplateTable + "_" + IDPTemplateLDAPSuffix
|
||||||
|
|
||||||
IDPTemplateOAuthSuffix = "oauth"
|
IDPTemplateOAuthSuffix = "oauth2"
|
||||||
IDPTemplateOIDCSuffix = "oidc"
|
IDPTemplateOIDCSuffix = "oidc"
|
||||||
IDPTemplateJWTSuffix = "jwt"
|
IDPTemplateJWTSuffix = "jwt"
|
||||||
IDPTemplateGoogleSuffix = "google"
|
IDPTemplateGoogleSuffix = "google"
|
||||||
@ -54,6 +54,7 @@ const (
|
|||||||
OAuthTokenEndpointCol = "token_endpoint"
|
OAuthTokenEndpointCol = "token_endpoint"
|
||||||
OAuthUserEndpointCol = "user_endpoint"
|
OAuthUserEndpointCol = "user_endpoint"
|
||||||
OAuthScopesCol = "scopes"
|
OAuthScopesCol = "scopes"
|
||||||
|
OAuthIDAttributeCol = "id_attribute"
|
||||||
|
|
||||||
OIDCIDCol = "idp_id"
|
OIDCIDCol = "idp_id"
|
||||||
OIDCInstanceIDCol = "instance_id"
|
OIDCInstanceIDCol = "instance_id"
|
||||||
@ -139,6 +140,7 @@ func newIDPTemplateProjection(ctx context.Context, config crdb.StatementHandlerC
|
|||||||
crdb.NewColumn(OAuthTokenEndpointCol, crdb.ColumnTypeText),
|
crdb.NewColumn(OAuthTokenEndpointCol, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(OAuthUserEndpointCol, crdb.ColumnTypeText),
|
crdb.NewColumn(OAuthUserEndpointCol, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(OAuthScopesCol, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
crdb.NewColumn(OAuthScopesCol, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
||||||
|
crdb.NewColumn(OAuthIDAttributeCol, crdb.ColumnTypeText),
|
||||||
},
|
},
|
||||||
crdb.NewPrimaryKey(OAuthInstanceIDCol, OAuthIDCol),
|
crdb.NewPrimaryKey(OAuthInstanceIDCol, OAuthIDCol),
|
||||||
IDPTemplateOAuthSuffix,
|
IDPTemplateOAuthSuffix,
|
||||||
@ -417,6 +419,7 @@ func (p *idpTemplateProjection) reduceOAuthIDPAdded(event eventstore.Event) (*ha
|
|||||||
handler.NewCol(OAuthTokenEndpointCol, idpEvent.TokenEndpoint),
|
handler.NewCol(OAuthTokenEndpointCol, idpEvent.TokenEndpoint),
|
||||||
handler.NewCol(OAuthUserEndpointCol, idpEvent.UserEndpoint),
|
handler.NewCol(OAuthUserEndpointCol, idpEvent.UserEndpoint),
|
||||||
handler.NewCol(OAuthScopesCol, database.StringArray(idpEvent.Scopes)),
|
handler.NewCol(OAuthScopesCol, database.StringArray(idpEvent.Scopes)),
|
||||||
|
handler.NewCol(OAuthIDAttributeCol, idpEvent.IDAttribute),
|
||||||
},
|
},
|
||||||
crdb.WithTableSuffix(IDPTemplateOAuthSuffix),
|
crdb.WithTableSuffix(IDPTemplateOAuthSuffix),
|
||||||
),
|
),
|
||||||
@ -1176,6 +1179,9 @@ func reduceOAuthIDPChangedColumns(idpEvent idp.OAuthIDPChangedEvent) []handler.C
|
|||||||
if idpEvent.Scopes != nil {
|
if idpEvent.Scopes != nil {
|
||||||
oauthCols = append(oauthCols, handler.NewCol(OAuthScopesCol, database.StringArray(idpEvent.Scopes)))
|
oauthCols = append(oauthCols, handler.NewCol(OAuthScopesCol, database.StringArray(idpEvent.Scopes)))
|
||||||
}
|
}
|
||||||
|
if idpEvent.IDAttribute != nil {
|
||||||
|
oauthCols = append(oauthCols, handler.NewCol(OAuthIDAttributeCol, *idpEvent.IDAttribute))
|
||||||
|
}
|
||||||
return oauthCols
|
return oauthCols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +154,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"tokenEndpoint": "token",
|
"tokenEndpoint": "token",
|
||||||
"userEndpoint": "user",
|
"userEndpoint": "user",
|
||||||
"scopes": ["profile"],
|
"scopes": ["profile"],
|
||||||
|
"idAttribute": "id-attribute",
|
||||||
"isCreationAllowed": true,
|
"isCreationAllowed": true,
|
||||||
"isLinkingAllowed": true,
|
"isLinkingAllowed": true,
|
||||||
"isAutoCreation": true,
|
"isAutoCreation": true,
|
||||||
@ -188,7 +189,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.idp_templates2_oauth (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
expectedStmt: "INSERT INTO projections.idp_templates2_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"idp-id",
|
"idp-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -198,6 +199,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
database.StringArray{"profile"},
|
database.StringArray{"profile"},
|
||||||
|
"id-attribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -223,6 +225,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"tokenEndpoint": "token",
|
"tokenEndpoint": "token",
|
||||||
"userEndpoint": "user",
|
"userEndpoint": "user",
|
||||||
"scopes": ["profile"],
|
"scopes": ["profile"],
|
||||||
|
"idAttribute": "id-attribute",
|
||||||
"isCreationAllowed": true,
|
"isCreationAllowed": true,
|
||||||
"isLinkingAllowed": true,
|
"isLinkingAllowed": true,
|
||||||
"isAutoCreation": true,
|
"isAutoCreation": true,
|
||||||
@ -257,7 +260,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.idp_templates2_oauth (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
expectedStmt: "INSERT INTO projections.idp_templates2_oauth2 (idp_id, instance_id, client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"idp-id",
|
"idp-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -267,6 +270,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
database.StringArray{"profile"},
|
database.StringArray{"profile"},
|
||||||
|
"id-attribute",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -304,7 +308,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.idp_templates2_oauth SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
expectedStmt: "UPDATE projections.idp_templates2_oauth2 SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"id",
|
"id",
|
||||||
"idp-id",
|
"idp-id",
|
||||||
@ -334,6 +338,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"tokenEndpoint": "token",
|
"tokenEndpoint": "token",
|
||||||
"userEndpoint": "user",
|
"userEndpoint": "user",
|
||||||
"scopes": ["profile"],
|
"scopes": ["profile"],
|
||||||
|
"idAttribute": "id-attribute",
|
||||||
"isCreationAllowed": true,
|
"isCreationAllowed": true,
|
||||||
"isLinkingAllowed": true,
|
"isLinkingAllowed": true,
|
||||||
"isAutoCreation": true,
|
"isAutoCreation": true,
|
||||||
@ -363,7 +368,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.idp_templates2_oauth SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes) = ($1, $2, $3, $4, $5, $6) WHERE (idp_id = $7) AND (instance_id = $8)",
|
expectedStmt: "UPDATE projections.idp_templates2_oauth2 SET (client_id, client_secret, authorization_endpoint, token_endpoint, user_endpoint, scopes, id_attribute) = ($1, $2, $3, $4, $5, $6, $7) WHERE (idp_id = $8) AND (instance_id = $9)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"client_id",
|
"client_id",
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -371,6 +376,7 @@ func TestIDPTemplateProjection_reducesOAuth(t *testing.T) {
|
|||||||
"token",
|
"token",
|
||||||
"user",
|
"user",
|
||||||
database.StringArray{"profile"},
|
database.StringArray{"profile"},
|
||||||
|
"id-attribute",
|
||||||
"idp-id",
|
"idp-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
},
|
},
|
||||||
|
@ -20,6 +20,7 @@ type OAuthIDPAddedEvent struct {
|
|||||||
TokenEndpoint string `json:"tokenEndpoint,omitempty"`
|
TokenEndpoint string `json:"tokenEndpoint,omitempty"`
|
||||||
UserEndpoint string `json:"userEndpoint,omitempty"`
|
UserEndpoint string `json:"userEndpoint,omitempty"`
|
||||||
Scopes []string `json:"scopes,omitempty"`
|
Scopes []string `json:"scopes,omitempty"`
|
||||||
|
IDAttribute string `json:"idAttribute,omitempty"`
|
||||||
Options
|
Options
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +32,8 @@ func NewOAuthIDPAddedEvent(
|
|||||||
clientSecret *crypto.CryptoValue,
|
clientSecret *crypto.CryptoValue,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options Options,
|
options Options,
|
||||||
) *OAuthIDPAddedEvent {
|
) *OAuthIDPAddedEvent {
|
||||||
@ -45,6 +47,7 @@ func NewOAuthIDPAddedEvent(
|
|||||||
TokenEndpoint: tokenEndpoint,
|
TokenEndpoint: tokenEndpoint,
|
||||||
UserEndpoint: userEndpoint,
|
UserEndpoint: userEndpoint,
|
||||||
Scopes: scopes,
|
Scopes: scopes,
|
||||||
|
IDAttribute: idAttribute,
|
||||||
Options: options,
|
Options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,6 +84,7 @@ type OAuthIDPChangedEvent struct {
|
|||||||
TokenEndpoint *string `json:"tokenEndpoint,omitempty"`
|
TokenEndpoint *string `json:"tokenEndpoint,omitempty"`
|
||||||
UserEndpoint *string `json:"userEndpoint,omitempty"`
|
UserEndpoint *string `json:"userEndpoint,omitempty"`
|
||||||
Scopes []string `json:"scopes,omitempty"`
|
Scopes []string `json:"scopes,omitempty"`
|
||||||
|
IDAttribute *string `json:"idAttribute,omitempty"`
|
||||||
OptionChanges
|
OptionChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +155,12 @@ func ChangeOAuthScopes(scopes []string) func(*OAuthIDPChangedEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChangeOAuthIDAttribute(idAttribute string) func(*OAuthIDPChangedEvent) {
|
||||||
|
return func(e *OAuthIDPChangedEvent) {
|
||||||
|
e.IDAttribute = &idAttribute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *OAuthIDPChangedEvent) Data() interface{} {
|
func (e *OAuthIDPChangedEvent) Data() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@ func NewOAuthIDPAddedEvent(
|
|||||||
clientSecret *crypto.CryptoValue,
|
clientSecret *crypto.CryptoValue,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) *OAuthIDPAddedEvent {
|
) *OAuthIDPAddedEvent {
|
||||||
@ -55,6 +56,7 @@ func NewOAuthIDPAddedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
|
idAttribute,
|
||||||
scopes,
|
scopes,
|
||||||
options,
|
options,
|
||||||
),
|
),
|
||||||
|
@ -36,7 +36,8 @@ func NewOAuthIDPAddedEvent(
|
|||||||
clientSecret *crypto.CryptoValue,
|
clientSecret *crypto.CryptoValue,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint,
|
||||||
|
idAttribute string,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) *OAuthIDPAddedEvent {
|
) *OAuthIDPAddedEvent {
|
||||||
@ -55,6 +56,7 @@ func NewOAuthIDPAddedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
|
idAttribute,
|
||||||
scopes,
|
scopes,
|
||||||
options,
|
options,
|
||||||
),
|
),
|
||||||
|
@ -4343,7 +4343,9 @@ message AddGenericOAuthProviderRequest {
|
|||||||
string token_endpoint = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string token_endpoint = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string user_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string user_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
repeated string scopes = 7 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
repeated string scopes = 7 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||||
zitadel.idp.v1.Options provider_options = 8;
|
// identifying attribute of the user in the response of the user_endpoint
|
||||||
|
string id_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
zitadel.idp.v1.Options provider_options = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddGenericOAuthProviderResponse {
|
message AddGenericOAuthProviderResponse {
|
||||||
@ -4361,7 +4363,9 @@ message UpdateGenericOAuthProviderRequest {
|
|||||||
string token_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string token_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string user_endpoint = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string user_endpoint = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
repeated string scopes = 8 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
repeated string scopes = 8 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||||
zitadel.idp.v1.Options provider_options = 9;
|
// identifying attribute of the user in the response of the user_endpoint
|
||||||
|
string id_attribute = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
zitadel.idp.v1.Options provider_options = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateGenericOAuthProviderResponse {
|
message UpdateGenericOAuthProviderResponse {
|
||||||
|
@ -275,6 +275,7 @@ message OAuthConfig {
|
|||||||
string token_endpoint = 3;
|
string token_endpoint = 3;
|
||||||
string user_endpoint = 4;
|
string user_endpoint = 4;
|
||||||
repeated string scopes = 5;
|
repeated string scopes = 5;
|
||||||
|
string id_attribute = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GenericOIDCConfig {
|
message GenericOIDCConfig {
|
||||||
|
@ -11017,7 +11017,9 @@ message AddGenericOAuthProviderRequest {
|
|||||||
string token_endpoint = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string token_endpoint = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string user_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string user_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
repeated string scopes = 7 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
repeated string scopes = 7 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||||
zitadel.idp.v1.Options provider_options = 8;
|
// identifying attribute of the user in the response of the user_endpoint
|
||||||
|
string id_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
zitadel.idp.v1.Options provider_options = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddGenericOAuthProviderResponse {
|
message AddGenericOAuthProviderResponse {
|
||||||
@ -11035,7 +11037,9 @@ message UpdateGenericOAuthProviderRequest {
|
|||||||
string token_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string token_endpoint = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string user_endpoint = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string user_endpoint = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
repeated string scopes = 8 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
repeated string scopes = 8 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||||
zitadel.idp.v1.Options provider_options = 9;
|
// identifying attribute of the user in the response of the user_endpoint
|
||||||
|
string id_attribute = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
zitadel.idp.v1.Options provider_options = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateGenericOAuthProviderResponse {
|
message UpdateGenericOAuthProviderResponse {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user