diff --git a/pkg/keystone/tokens/assume.go b/pkg/keystone/tokens/assume.go index 3893a4b18f..24fd5be19c 100644 --- a/pkg/keystone/tokens/assume.go +++ b/pkg/keystone/tokens/assume.go @@ -55,18 +55,6 @@ func authUserByAssume(ctx context.Context, input mcclient.SAuthenticationInputV3 return nil, errors.Wrap(err, "fetch scoped project") } - var requireScope rbacscope.TRbacScope - if adminToken.ProjectId == scopedProject.Id { - requireScope = rbacscope.ScopeProject - } else if adminToken.DomainId == scopedProject.DomainId { - requireScope = rbacscope.ScopeDomain - } else { - requireScope = rbacscope.ScopeSystem - } - - adminToken.ProjectId = scopedProject.Id - adminToken.DomainId = scopedProject.DomainId - adminTokenCred, err := adminToken.GetSimpleUserCred(input.Auth.Identity.Token.Id) if err != nil { return nil, errors.Wrap(err, "get admin token credential") @@ -90,8 +78,8 @@ func authUserByAssume(ctx context.Context, input mcclient.SAuthenticationInputV3 } if adminTokenCred.GetUserId() != targetUser.Id { - if policy.PolicyManager.Allow(requireScope, adminTokenCred, api.SERVICE_TYPE, "tokens", "perform", "assume").Result.IsDeny() { - return nil, httperrors.NewForbiddenError("%s not allow to assume user in project %s", adminTokenCred.GetUserName(), scopedProject.Name) + if err := checkAssumeAllowed(adminTokenCred, targetUser.Id, scopedProject); err != nil { + return nil, err } } @@ -100,3 +88,21 @@ func authUserByAssume(ctx context.Context, input mcclient.SAuthenticationInputV3 return targetUser, nil } + +func checkAssumeAllowed(adminTokenCred mcclient.TokenCredential, targetUserId string, scopedProject *models.SProject) error { + if policy.PolicyManager.Allow(rbacscope.ScopeSystem, adminTokenCred, api.SERVICE_TYPE, "tokens", "perform", "assume").Result.IsDeny() { + return httperrors.NewForbiddenError("%s not allow to assume user in project %s", adminTokenCred.GetUserName(), scopedProject.Name) + } + roles, err := models.AssignmentManager.FetchUserProjectRoles(targetUserId, scopedProject.Id) + if err != nil { + return errors.Wrap(err, "fetch target user roles") + } + roleIds := make([]string, len(roles)) + for i := range roles { + roleIds[i] = roles[i].Id + } + if err := models.ValidateJoinProjectRoles(adminTokenCred, scopedProject.Id, roleIds); err != nil { + return errors.Wrap(err, "validate assume target roles") + } + return nil +} diff --git a/pkg/keystone/tokens/assume_test.go b/pkg/keystone/tokens/assume_test.go new file mode 100644 index 0000000000..3685acca97 --- /dev/null +++ b/pkg/keystone/tokens/assume_test.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tokens + +import ( + "context" + "testing" + + "yunion.io/x/onecloud/pkg/mcclient" +) + +func TestAuthUserByAssumeRequiresAdminToken(t *testing.T) { + _, err := authUserByAssume(context.Background(), mcclient.SAuthenticationInputV3{}) + if err == nil { + t.Fatal("expected error when admin token is missing") + } +}