|
|
|
|
@@ -67,7 +67,7 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl
|
|
|
|
|
return ClientFromBusiness(client, o.defaultLoginURL, accessTokenLifetime, idTokenLifetime, allowedScopes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) {
|
|
|
|
|
func (o *OPStorage) GetKeyByIDAndClientID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) {
|
|
|
|
|
return o.GetKeyByIDAndIssuer(ctx, keyID, userID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -114,7 +114,7 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
|
|
|
|
|
return o.command.VerifyAPIClientSecret(ctx, app.ProjectID, app.ID, secret)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.UserInfoSetter, tokenID, subject, origin string) (err error) {
|
|
|
|
|
func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo *oidc.UserInfo, tokenID, subject, origin string) (err error) {
|
|
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
|
token, err := o.repo.TokenByIDs(ctx, subject, tokenID)
|
|
|
|
|
@@ -133,7 +133,7 @@ func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.User
|
|
|
|
|
return o.setUserinfo(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) {
|
|
|
|
|
func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo *oidc.UserInfo, userID, applicationID string, scopes []string) (err error) {
|
|
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
|
if applicationID != "" {
|
|
|
|
|
@@ -151,7 +151,7 @@ func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.Use
|
|
|
|
|
return o.setUserinfo(ctx, userInfo, userID, applicationID, scopes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
|
|
|
|
|
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection *oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
|
|
|
|
|
token, err := o.repo.TokenByIDs(ctx, subject, tokenID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
|
|
|
|
|
@@ -168,19 +168,21 @@ func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection
|
|
|
|
|
}
|
|
|
|
|
for _, aud := range token.Audience {
|
|
|
|
|
if aud == clientID || aud == projectID {
|
|
|
|
|
err := o.setUserinfo(ctx, introspection, token.UserID, clientID, token.Scopes)
|
|
|
|
|
userInfo := new(oidc.UserInfo)
|
|
|
|
|
err := o.setUserinfo(ctx, userInfo, subject, clientID, token.Scopes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
introspection.SetScopes(token.Scopes)
|
|
|
|
|
introspection.SetClientID(token.ApplicationID)
|
|
|
|
|
introspection.SetTokenType(oidc.BearerToken)
|
|
|
|
|
introspection.SetExpiration(token.Expiration)
|
|
|
|
|
introspection.SetIssuedAt(token.CreationDate)
|
|
|
|
|
introspection.SetNotBefore(token.CreationDate)
|
|
|
|
|
introspection.SetAudience(token.Audience)
|
|
|
|
|
introspection.SetIssuer(op.IssuerFromContext(ctx))
|
|
|
|
|
introspection.SetJWTID(token.ID)
|
|
|
|
|
introspection.SetUserInfo(userInfo)
|
|
|
|
|
introspection.Scope = token.Scopes
|
|
|
|
|
introspection.ClientID = token.ApplicationID
|
|
|
|
|
introspection.TokenType = oidc.BearerToken
|
|
|
|
|
introspection.Expiration = oidc.FromTime(token.Expiration)
|
|
|
|
|
introspection.IssuedAt = oidc.FromTime(token.CreationDate)
|
|
|
|
|
introspection.NotBefore = oidc.FromTime(token.CreationDate)
|
|
|
|
|
introspection.Audience = token.Audience
|
|
|
|
|
introspection.Issuer = op.IssuerFromContext(ctx)
|
|
|
|
|
introspection.JWTID = token.ID
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -252,7 +254,7 @@ func (o *OPStorage) checkOrgScopes(ctx context.Context, user *query.User, scopes
|
|
|
|
|
return scopes, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) {
|
|
|
|
|
func (o *OPStorage) setUserinfo(ctx context.Context, userInfo *oidc.UserInfo, userID, applicationID string, scopes []string) (err error) {
|
|
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
|
user, err := o.query.GetUserByID(ctx, true, userID, false)
|
|
|
|
|
@@ -263,50 +265,23 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette
|
|
|
|
|
for _, scope := range scopes {
|
|
|
|
|
switch scope {
|
|
|
|
|
case oidc.ScopeOpenID:
|
|
|
|
|
userInfo.SetSubject(user.ID)
|
|
|
|
|
userInfo.Subject = user.ID
|
|
|
|
|
case oidc.ScopeEmail:
|
|
|
|
|
if user.Human == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
userInfo.SetEmail(string(user.Human.Email), user.Human.IsEmailVerified)
|
|
|
|
|
setUserInfoEmail(userInfo, user)
|
|
|
|
|
case oidc.ScopeProfile:
|
|
|
|
|
userInfo.SetPreferredUsername(user.PreferredLoginName)
|
|
|
|
|
userInfo.SetUpdatedAt(user.ChangeDate)
|
|
|
|
|
if user.Human != nil {
|
|
|
|
|
userInfo.SetName(user.Human.DisplayName)
|
|
|
|
|
userInfo.SetFamilyName(user.Human.LastName)
|
|
|
|
|
userInfo.SetGivenName(user.Human.FirstName)
|
|
|
|
|
userInfo.SetNickname(user.Human.NickName)
|
|
|
|
|
userInfo.SetGender(getGender(user.Human.Gender))
|
|
|
|
|
userInfo.SetLocale(user.Human.PreferredLanguage)
|
|
|
|
|
userInfo.SetPicture(domain.AvatarURL(o.assetAPIPrefix(ctx), user.ResourceOwner, user.Human.AvatarKey))
|
|
|
|
|
} else {
|
|
|
|
|
userInfo.SetName(user.Machine.Name)
|
|
|
|
|
}
|
|
|
|
|
o.setUserInfoProfile(ctx, userInfo, user)
|
|
|
|
|
case oidc.ScopePhone:
|
|
|
|
|
if user.Human == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
userInfo.SetPhone(string(user.Human.Phone), user.Human.IsPhoneVerified)
|
|
|
|
|
setUserInfoPhone(userInfo, user)
|
|
|
|
|
case oidc.ScopeAddress:
|
|
|
|
|
//TODO: handle address for human users as soon as implemented
|
|
|
|
|
case ScopeUserMetaData:
|
|
|
|
|
userMetaData, err := o.assertUserMetaData(ctx, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err := o.setUserInfoMetadata(ctx, userInfo, userID); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if len(userMetaData) > 0 {
|
|
|
|
|
userInfo.AppendClaims(ClaimUserMetaData, userMetaData)
|
|
|
|
|
}
|
|
|
|
|
case ScopeResourceOwner:
|
|
|
|
|
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err := o.setUserInfoResourceOwner(ctx, userInfo, userID); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for claim, value := range resourceOwnerClaims {
|
|
|
|
|
userInfo.AppendClaims(claim, value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
|
|
|
|
|
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
|
|
|
|
|
@@ -316,13 +291,9 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(scope, domain.OrgIDScope) {
|
|
|
|
|
userInfo.AppendClaims(domain.OrgIDClaim, strings.TrimPrefix(scope, domain.OrgIDScope))
|
|
|
|
|
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err := o.setUserInfoResourceOwner(ctx, userInfo, userID); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for claim, value := range resourceOwnerClaims {
|
|
|
|
|
userInfo.AppendClaims(claim, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -339,7 +310,64 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette
|
|
|
|
|
return o.userinfoFlows(ctx, user.ResourceOwner, userGrants, userInfo)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, userGrants *query.UserGrants, userInfo oidc.UserInfoSetter) error {
|
|
|
|
|
func (o *OPStorage) setUserInfoProfile(ctx context.Context, userInfo *oidc.UserInfo, user *query.User) {
|
|
|
|
|
userInfo.PreferredUsername = user.PreferredLoginName
|
|
|
|
|
userInfo.UpdatedAt = oidc.FromTime(user.ChangeDate)
|
|
|
|
|
if user.Machine != nil {
|
|
|
|
|
userInfo.Name = user.Machine.Name
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
userInfo.Name = user.Human.DisplayName
|
|
|
|
|
userInfo.FamilyName = user.Human.LastName
|
|
|
|
|
userInfo.GivenName = user.Human.FirstName
|
|
|
|
|
userInfo.Nickname = user.Human.NickName
|
|
|
|
|
userInfo.Gender = getGender(user.Human.Gender)
|
|
|
|
|
userInfo.Locale = oidc.NewLocale(user.Human.PreferredLanguage)
|
|
|
|
|
userInfo.Picture = domain.AvatarURL(o.assetAPIPrefix(ctx), user.ResourceOwner, user.Human.AvatarKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setUserInfoEmail(userInfo *oidc.UserInfo, user *query.User) {
|
|
|
|
|
if user.Human == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
userInfo.UserInfoEmail = oidc.UserInfoEmail{
|
|
|
|
|
Email: string(user.Human.Email),
|
|
|
|
|
EmailVerified: oidc.Bool(user.Human.IsEmailVerified)}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setUserInfoPhone(userInfo *oidc.UserInfo, user *query.User) {
|
|
|
|
|
if user.Human == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
userInfo.UserInfoPhone = oidc.UserInfoPhone{
|
|
|
|
|
PhoneNumber: string(user.Human.Phone),
|
|
|
|
|
PhoneNumberVerified: user.Human.IsPhoneVerified,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) setUserInfoMetadata(ctx context.Context, userInfo *oidc.UserInfo, userID string) error {
|
|
|
|
|
userMetaData, err := o.assertUserMetaData(ctx, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if len(userMetaData) > 0 {
|
|
|
|
|
userInfo.AppendClaims(ClaimUserMetaData, userMetaData)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) setUserInfoResourceOwner(ctx context.Context, userInfo *oidc.UserInfo, userID string) error {
|
|
|
|
|
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for claim, value := range resourceOwnerClaims {
|
|
|
|
|
userInfo.AppendClaims(claim, value)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, userGrants *query.UserGrants, userInfo *oidc.UserInfo) error {
|
|
|
|
|
queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreUserinfoCreation, resourceOwner, false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
@@ -350,7 +378,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use
|
|
|
|
|
actions.SetFields("claims", userinfoClaims(userInfo)),
|
|
|
|
|
actions.SetFields("getUser", func(c *actions.FieldConfig) interface{} {
|
|
|
|
|
return func(call goja.FunctionCall) goja.Value {
|
|
|
|
|
user, err := o.query.GetUserByID(ctx, true, userInfo.GetSubject(), false)
|
|
|
|
|
user, err := o.query.GetUserByID(ctx, true, userInfo.Subject, false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
@@ -368,7 +396,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use
|
|
|
|
|
metadata, err := o.query.SearchUserMetadata(
|
|
|
|
|
ctx,
|
|
|
|
|
true,
|
|
|
|
|
userInfo.GetSubject(),
|
|
|
|
|
userInfo.Subject,
|
|
|
|
|
&query.UserMetadataSearchQueries{Queries: []query.SearchQuery{resourceOwnerQuery}},
|
|
|
|
|
false,
|
|
|
|
|
)
|
|
|
|
|
@@ -394,7 +422,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use
|
|
|
|
|
actions.SetFields("v1",
|
|
|
|
|
actions.SetFields("userinfo",
|
|
|
|
|
actions.SetFields("setClaim", func(key string, value interface{}) {
|
|
|
|
|
if userInfo.GetClaim(key) == nil {
|
|
|
|
|
if userInfo.Claims[key] == nil {
|
|
|
|
|
userInfo.AppendClaims(key, value)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
@@ -406,7 +434,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use
|
|
|
|
|
),
|
|
|
|
|
actions.SetFields("claims",
|
|
|
|
|
actions.SetFields("setClaim", func(key string, value interface{}) {
|
|
|
|
|
if userInfo.GetClaim(key) == nil {
|
|
|
|
|
if userInfo.Claims[key] == nil {
|
|
|
|
|
userInfo.AppendClaims(key, value)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
@@ -434,7 +462,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use
|
|
|
|
|
Key: key,
|
|
|
|
|
Value: value,
|
|
|
|
|
}
|
|
|
|
|
if _, err = o.command.SetUserMetadata(ctx, metadata, userInfo.GetSubject(), resourceOwner); err != nil {
|
|
|
|
|
if _, err = o.command.SetUserMetadata(ctx, metadata, userInfo.Subject, resourceOwner); err != nil {
|
|
|
|
|
logging.WithError(err).Info("unable to set md in action")
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
@@ -729,7 +757,7 @@ func appendClaim(claims map[string]interface{}, claim string, value interface{})
|
|
|
|
|
return claims
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func userinfoClaims(userInfo oidc.UserInfoSetter) func(c *actions.FieldConfig) interface{} {
|
|
|
|
|
func userinfoClaims(userInfo *oidc.UserInfo) func(c *actions.FieldConfig) interface{} {
|
|
|
|
|
return func(c *actions.FieldConfig) interface{} {
|
|
|
|
|
marshalled, err := json.Marshal(userInfo)
|
|
|
|
|
if err != nil {
|
|
|
|
|
|