diff --git a/pkg/keystone/models/assignments.go b/pkg/keystone/models/assignments.go index 23a0e3e4d2..9fd30c2ad1 100644 --- a/pkg/keystone/models/assignments.go +++ b/pkg/keystone/models/assignments.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/appsrv" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/keystone/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/rbacutils" @@ -248,7 +249,7 @@ func (manager *SAssignmentManager) ProjectAddUser(ctx context.Context, userCred return err } if project.DomainId != user.DomainId { - if project.DomainId != api.DEFAULT_DOMAIN_ID { + if project.DomainId != api.DEFAULT_DOMAIN_ID && !options.Options.AllowJoinProjectsAcrossDomains { return httperrors.NewInputParameterError("join user into project of default domain or identical domain") } else if !db.IsAllowPerform(rbacutils.ScopeSystem, userCred, user, "join-project") { return httperrors.NewForbiddenError("not enough privilege") @@ -348,7 +349,7 @@ func (manager *SAssignmentManager) projectAddGroup(ctx context.Context, userCred return err } if project.DomainId != group.DomainId { - if project.DomainId != api.DEFAULT_DOMAIN_ID { + if project.DomainId != api.DEFAULT_DOMAIN_ID && !options.Options.AllowJoinProjectsAcrossDomains { return httperrors.NewInputParameterError("join group into project of default domain or identical domain") } else if !db.IsAllowPerform(rbacutils.ScopeSystem, userCred, group, "join-project") { return httperrors.NewForbiddenError("not enough privilege") diff --git a/pkg/keystone/models/roles.go b/pkg/keystone/models/roles.go index b57e20fd46..b154a536c9 100644 --- a/pkg/keystone/models/roles.go +++ b/pkg/keystone/models/roles.go @@ -351,8 +351,14 @@ func (role *SRole) UpdateInContext(ctx context.Context, userCred mcclient.TokenC if !ok { return nil, httperrors.NewInputParameterError("not supported update context %s", ctxObjs[0].Keyword()) } - if project.DomainId != role.DomainId && !role.GetIsPublic() { - return nil, httperrors.NewInputParameterError("inconsistent domain for project and roles") + if project.DomainId != role.DomainId { + projectOwner := &db.SOwnerId{ + ProjectId: project.Id, + DomainId: project.DomainId, + } + if !role.IsSharable(projectOwner) { + return nil, httperrors.NewInputParameterError("inconsistent domain for project and roles") + } } err := validateJoinProject(userCred, project, []string{role.Id}) if err != nil { diff --git a/pkg/keystone/options/options.go b/pkg/keystone/options/options.go index 5a123dabd5..bea97f7323 100644 --- a/pkg/keystone/options/options.go +++ b/pkg/keystone/options/options.go @@ -52,6 +52,8 @@ type SKeystoneOptions struct { DefaultPolicyQuota int `default:"500" help:"default quota for policy per domain, default is 500"` SessionEndpointType string `help:"Client session end point type"` + + AllowJoinProjectsAcrossDomains bool `help:"allow users/groups to join projects across domains" default:"false"` } var (