fix: assert roles when using refresh token (#2868)

This commit is contained in:
Livio Amstutz 2021-12-17 16:11:18 +01:00 committed by GitHub
parent 8b0c3e63d6
commit 57368d151b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 39 deletions

View File

@ -25,17 +25,9 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest
if !ok {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
}
projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, req.ClientID)
req.Scopes, err = o.assertProjectRoleScopes(ctx, req.ClientID, req.Scopes)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal")
}
project, err := o.query.ProjectByID(ctx, projectID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-w4wIn", "Errors.Internal")
}
req.Scopes, err = o.assertProjectRoleScopes(project, req.Scopes)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-Gqrfg", "Errors.Internal")
return nil, errors.ThrowPreconditionFailed(err, "OIDC-Gqrfg", "Errors.Internal")
}
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
//TODO: ensure splitting of command and query side durring auth request and login refactoring
@ -117,8 +109,15 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
userAgentID, applicationID, userOrgID, authTime, authMethodsReferences := getInfoFromRequest(req)
scopes, err := o.assertProjectRoleScopes(ctx, applicationID, req.GetScopes())
if err != nil {
return "", "", time.Time{}, errors.ThrowPreconditionFailed(err, "OIDC-Df2fq", "Errors.Internal")
}
if request, ok := req.(op.RefreshTokenRequest); ok {
request.SetCurrentScopes(scopes)
}
resp, token, err := o.command.AddAccessAndRefreshToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(),
refreshToken, req.GetAudience(), req.GetScopes(), authMethodsReferences, o.defaultAccessTokenLifetime,
refreshToken, req.GetAudience(), scopes, authMethodsReferences, o.defaultAccessTokenLifetime,
o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client
if err != nil {
if errors.IsErrorInvalidArgument(err) {
@ -209,15 +208,23 @@ func (o *OPStorage) GetKeySet(ctx context.Context) (_ *jose.JSONWebKeySet, err e
return o.repo.GetKeySet(ctx)
}
func (o *OPStorage) assertProjectRoleScopes(project *query.Project, scopes []string) ([]string, error) {
if !project.ProjectRoleAssertion {
return scopes, nil
}
func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string, scopes []string) ([]string, error) {
for _, scope := range scopes {
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
return scopes, nil
}
}
projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, clientID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal")
}
project, err := o.query.ProjectByID(ctx, projectID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-w4wIn", "Errors.Internal")
}
if !project.ProjectRoleAssertion {
return scopes, nil
}
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(project.ID)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")

View File

@ -129,10 +129,51 @@ func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.User
return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
}
}
return o.SetUserinfoFromScopes(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes)
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) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if applicationID != "" {
app, err := o.query.AppByOIDCClientID(ctx, applicationID)
if err != nil {
return err
}
if app.OIDCConfig.AssertIDTokenRole {
scopes, err = o.assertProjectRoleScopes(ctx, applicationID, scopes)
if err != nil {
return errors.ThrowPreconditionFailed(err, "OIDC-Dfe2s", "Errors.Internal")
}
}
}
return o.setUserinfo(ctx, userInfo, userID, applicationID, scopes)
}
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
projectID, err := o.query.ProjectIDFromClientID(ctx, clientID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
for _, aud := range token.Audience {
if aud == clientID || aud == projectID {
err := o.setUserinfo(ctx, introspection, token.UserID, clientID, token.Scopes)
if err != nil {
return err
}
introspection.SetScopes(token.Scopes)
introspection.SetClientID(token.ApplicationID)
return nil
}
}
return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client")
}
func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
user, err := o.repo.UserByID(ctx, userID)
@ -216,29 +257,6 @@ func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.Use
return nil
}
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
projectID, err := o.query.ProjectIDFromClientID(ctx, clientID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
for _, aud := range token.Audience {
if aud == clientID || aud == projectID {
err := o.SetUserinfoFromScopes(ctx, introspection, token.UserID, clientID, token.Scopes)
if err != nil {
return err
}
introspection.SetScopes(token.Scopes)
introspection.SetClientID(token.ApplicationID)
return nil
}
}
return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client")
}
func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]interface{}, err error) {
roles := make([]string, 0)
for _, scope := range scopes {