From fea61697e9a8cc36593edb56a4d4cc215f2d6e69 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 27 Jul 2019 09:55:57 +0800 Subject: [PATCH] fix: allow turn off non-default domain projects --- pkg/cloudcommon/app/auth.go | 1 + pkg/cloudcommon/consts/consts.go | 10 ++++++++ pkg/cloudcommon/db/domain.go | 10 ++++++++ pkg/cloudcommon/options/options.go | 2 ++ pkg/cloudcommon/policy/defaults.go | 24 +++++++++++++++++++ pkg/compute/models/cloudaccounts.go | 5 ++++ pkg/compute/models/cloudproviders.go | 1 - pkg/keystone/driver/ldap/sync.go | 3 ++- pkg/keystone/models/assignments.go | 12 ++++++++-- pkg/keystone/models/policies.go | 4 ++++ pkg/keystone/models/projects.go | 8 +++++++ pkg/keystone/models/roles.go | 8 +++++++ pkg/keystone/options/options.go | 1 - pkg/mcclient/options/cloudaccounts.go | 2 ++ pkg/util/aws/region.go | 12 +++++----- pkg/util/huawei/client/modules/mod_servers.go | 2 +- pkg/util/huawei/instance.go | 4 ++-- pkg/util/huawei/shell/instance.go | 2 +- 18 files changed, 96 insertions(+), 15 deletions(-) diff --git a/pkg/cloudcommon/app/auth.go b/pkg/cloudcommon/app/auth.go index 83ab5efa7c..c219e8183f 100644 --- a/pkg/cloudcommon/app/auth.go +++ b/pkg/cloudcommon/app/auth.go @@ -83,4 +83,5 @@ func InitBaseAuth(options *common_options.BaseOptions) { options.RbacDebug, ) } + consts.SetNonDefaultDomainProjects(options.NonDefaultDomainProjects) } diff --git a/pkg/cloudcommon/consts/consts.go b/pkg/cloudcommon/consts/consts.go index 65dc74f4e5..b59a671d15 100644 --- a/pkg/cloudcommon/consts/consts.go +++ b/pkg/cloudcommon/consts/consts.go @@ -24,6 +24,8 @@ var ( globalServiceType = "" tenantCacheExpireSeconds = 900 + + nonDefaultDomainProjects = false ) func SetRegion(region string) { @@ -49,3 +51,11 @@ func SetTenantCacheExpireSeconds(sec int) { func GetTenantCacheExpireSeconds() time.Duration { return time.Duration(tenantCacheExpireSeconds) * time.Second } + +func SetNonDefaultDomainProjects(val bool) { + nonDefaultDomainProjects = val +} + +func GetNonDefaultDomainProjects() bool { + return nonDefaultDomainProjects +} diff --git a/pkg/cloudcommon/db/domain.go b/pkg/cloudcommon/db/domain.go index 30745c5372..9427116f5c 100644 --- a/pkg/cloudcommon/db/domain.go +++ b/pkg/cloudcommon/db/domain.go @@ -20,6 +20,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis/identity" + "yunion.io/x/onecloud/pkg/cloudcommon/consts" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" ) @@ -55,3 +58,10 @@ func (model *SDomainizedResourceBase) GetOwnerId() mcclient.IIdentityProvider { owner := SOwnerId{DomainId: model.DomainId} return &owner } + +func ValidateCreateDomainId(domainId string) error { + if !consts.GetNonDefaultDomainProjects() && domainId != identity.DEFAULT_DOMAIN_ID { + return httperrors.NewForbiddenError("project in non-default domain is prohibited") + } + return nil +} diff --git a/pkg/cloudcommon/options/options.go b/pkg/cloudcommon/options/options.go index 165bf763ee..d75db514b7 100644 --- a/pkg/cloudcommon/options/options.go +++ b/pkg/cloudcommon/options/options.go @@ -67,6 +67,8 @@ type BaseOptions struct { CalculateQuotaUsageIntervalSeconds int `help:"interval to calculate quota usages, default 30 minutes" default:"900"` + NonDefaultDomainProjects bool `help:"allow projects in non-default domains" default:"false"` + structarg.BaseOptions } diff --git a/pkg/cloudcommon/policy/defaults.go b/pkg/cloudcommon/policy/defaults.go index 39b9ab3ed3..ee339f9786 100644 --- a/pkg/cloudcommon/policy/defaults.go +++ b/pkg/cloudcommon/policy/defaults.go @@ -66,6 +66,30 @@ var ( Action: PolicyActionGet, Result: rbacutils.Allow, }, + { + Service: "compute", + Resource: "vpcs", + Action: PolicyActionList, + Result: rbacutils.Allow, + }, + { + Service: "compute", + Resource: "vpcs", + Action: PolicyActionGet, + Result: rbacutils.Allow, + }, + { + Service: "compute", + Resource: "wires", + Action: PolicyActionList, + Result: rbacutils.Allow, + }, + { + Service: "compute", + Resource: "wires", + Action: PolicyActionGet, + Result: rbacutils.Allow, + }, { Service: "compute", Resource: "schedtags", diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index 24d3cc1b8a..e686b0ce60 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -248,6 +248,11 @@ func (self *SCloudaccount) ValidateUpdateData(ctx context.Context, userCred mccl } func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + // check domainId + err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId()) + if err != nil { + return nil, err + } // check provider // name, _ := data.GetString("name") provider, _ := data.GetString("provider") diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index b9033bdbc3..22723b04fb 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -955,7 +955,6 @@ func (manager *SCloudproviderManager) ListItemFilter(ctx context.Context, q *sql sq = sq.Filter(sqlchemy.In(providers.Field("health_status"), api.CLOUD_PROVIDER_VALID_HEALTH_STATUS)) sq = sq.Filter(sqlchemy.Equals(vpcs.Field("status"), api.VPC_STATUS_AVAILABLE)) - sq2 := providers.Query(sqlchemy.DISTINCT("id", providers.Field("id"))) sq2 = sq2.Join(vpcs, sqlchemy.Equals(vpcs.Field("manager_id"), providers.Field("id"))) sq2 = sq2.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) diff --git a/pkg/keystone/driver/ldap/sync.go b/pkg/keystone/driver/ldap/sync.go index 8f2905c783..1b4c976528 100644 --- a/pkg/keystone/driver/ldap/sync.go +++ b/pkg/keystone/driver/ldap/sync.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/pkg/tristate" api "yunion.io/x/onecloud/pkg/apis/identity" + "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/keystone/models" @@ -213,7 +214,7 @@ func (self *SLDAPDriver) syncDomainInfo(ctx context.Context, info SDomainInfo) ( return nil, errors.Wrap(err, "insert") } - if self.AutoCreateProject { + if self.AutoCreateProject && consts.GetNonDefaultDomainProjects() { project := &models.SProject{} project.SetModelManager(models.ProjectManager, project) projectName := models.NormalizeProjectName(fmt.Sprintf("%s_default_project", info.Name)) diff --git a/pkg/keystone/models/assignments.go b/pkg/keystone/models/assignments.go index 8146a43668..41329e7df5 100644 --- a/pkg/keystone/models/assignments.go +++ b/pkg/keystone/models/assignments.go @@ -243,6 +243,10 @@ func (manager *SAssignmentManager) fetchProjectUserIdsQuery(projId string) *sqlc } func (manager *SAssignmentManager) projectAddUser(ctx context.Context, userCred mcclient.TokenCredential, project *SProject, user *SUser, role *SRole) error { + err := db.ValidateCreateDomainId(project.DomainId) + if err != nil { + return err + } if project.DomainId != user.DomainId { if project.DomainId != api.DEFAULT_DOMAIN_ID { return httperrors.NewInputParameterError("join user into project of default domain or identical domain") @@ -254,7 +258,7 @@ func (manager *SAssignmentManager) projectAddUser(ctx context.Context, userCred return httperrors.NewForbiddenError("not enough privilege") } } - err := manager.add(api.AssignmentUserProject, user.Id, project.Id, role.Id) + err = manager.add(api.AssignmentUserProject, user.Id, project.Id, role.Id) if err == nil { db.OpsLog.LogEvent(user, db.ACT_ATTACH, project.GetShortDesc(ctx), userCred) db.OpsLog.LogEvent(project, db.ACT_ATTACH, user.GetShortDesc(ctx), userCred) @@ -337,6 +341,10 @@ func (manager *SAssignmentManager) projectRemoveUser(ctx context.Context, userCr } func (manager *SAssignmentManager) projectAddGroup(ctx context.Context, userCred mcclient.TokenCredential, project *SProject, group *SGroup, role *SRole) error { + err := db.ValidateCreateDomainId(project.DomainId) + if err != nil { + return err + } if project.DomainId != group.DomainId { if project.DomainId != api.DEFAULT_DOMAIN_ID { return httperrors.NewInputParameterError("join group into project of default domain or identical domain") @@ -348,7 +356,7 @@ func (manager *SAssignmentManager) projectAddGroup(ctx context.Context, userCred return httperrors.NewForbiddenError("not enough privilege") } } - err := manager.add(api.AssignmentGroupProject, group.Id, project.Id, role.Id) + err = manager.add(api.AssignmentGroupProject, group.Id, project.Id, role.Id) if err == nil { db.OpsLog.LogEvent(group, db.ACT_ATTACH, project.GetShortDesc(ctx), userCred) db.OpsLog.LogEvent(project, db.ACT_ATTACH, group.GetShortDesc(ctx), userCred) diff --git a/pkg/keystone/models/policies.go b/pkg/keystone/models/policies.go index 8b76cdc526..bcdabb9c40 100644 --- a/pkg/keystone/models/policies.go +++ b/pkg/keystone/models/policies.go @@ -113,6 +113,10 @@ func (manager *SPolicyManager) ValidateCreateData(ctx context.Context, userCred /*if policy.IsSystemWidePolicy() && policyman.PolicyManager.Allow(rbacutils.ScopeSystem, userCred, consts.GetServiceType(), manager.KeywordPlural(), policyman.PolicyActionCreate) == rbacutils.Deny { return nil, httperrors.NewNotSufficientPrivilegeError("not allow to create system-wide policy") }*/ + err = db.ValidateCreateDomainId(ownerId.GetProjectDomainId()) + if err != nil { + return nil, err + } return manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, data) } diff --git a/pkg/keystone/models/projects.go b/pkg/keystone/models/projects.go index b97d1766ea..e1f0d3b3d6 100644 --- a/pkg/keystone/models/projects.go +++ b/pkg/keystone/models/projects.go @@ -353,3 +353,11 @@ func (manager *SProjectManager) FetchUserProjects(userId string) ([]SProjectExte } return ret, nil } + +func (manager *SProjectManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId()) + if err != nil { + return nil, err + } + return manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, data) +} diff --git a/pkg/keystone/models/roles.go b/pkg/keystone/models/roles.go index deb2d67171..c3674ea5f7 100644 --- a/pkg/keystone/models/roles.go +++ b/pkg/keystone/models/roles.go @@ -376,3 +376,11 @@ func (role *SRole) PerformPrivate(ctx context.Context, userCred mcclient.TokenCr } return res, err } + +func (manager *SRoleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId()) + if err != nil { + return nil, err + } + return manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, data) +} diff --git a/pkg/keystone/options/options.go b/pkg/keystone/options/options.go index 121354d50b..55e5f0492d 100644 --- a/pkg/keystone/options/options.go +++ b/pkg/keystone/options/options.go @@ -28,7 +28,6 @@ type SKeystoneOptions struct { TokenExpirationSeconds int `default:"86400" help:"token expiration seconds" token:"expiration"` FernetKeyRepository string `help:"fernet key repo directory" token:"key_repository" default:"/etc/yunion/keystone/fernet-keys"` SetupCredentialKeys bool `help:"setup standalone fernet keys for credentials" token:"setup_credential_key" default:"false"` - // SetupStateKey bool `help:"setup standalone fernet keys for openid state" token:"setup_state_key"` BootstrapAdminUserPassword string `help:"bootstreap sysadmin user password" default:"sysadmin"` ResetAdminUserPassword bool `help:"reset sysadmin password if exists and this option is true"` diff --git a/pkg/mcclient/options/cloudaccounts.go b/pkg/mcclient/options/cloudaccounts.go index 0f1350e43f..6a84efa718 100644 --- a/pkg/mcclient/options/cloudaccounts.go +++ b/pkg/mcclient/options/cloudaccounts.go @@ -81,6 +81,8 @@ type SCloudAccountCreateBaseOptions struct { EnableAutoSync bool `help:"Enable automatically synchronize resources of this account"` SyncIntervalSeconds int `help:"Interval to synchronize if auto sync is enable" metavar:"SECONDS"` + + ProjectDomain string `help:"domain for this account, default is Default" default:"Default"` } type SVMwareCloudAccountCreateOptions struct { diff --git a/pkg/util/aws/region.go b/pkg/util/aws/region.go index 3a01758a1f..880d747fae 100644 --- a/pkg/util/aws/region.go +++ b/pkg/util/aws/region.go @@ -164,12 +164,12 @@ func (self *SRegion) fetchIVpcs() error { } self.ivpcs = append(self.ivpcs, &SVpc{region: self, - CidrBlock: *vpc.CidrBlock, - Tags: tags, - IsDefault: *vpc.IsDefault, - RegionId: self.RegionId, - Status: *vpc.State, - VpcId: *vpc.VpcId, + CidrBlock: *vpc.CidrBlock, + Tags: tags, + IsDefault: *vpc.IsDefault, + RegionId: self.RegionId, + Status: *vpc.State, + VpcId: *vpc.VpcId, InstanceTenancy: *vpc.InstanceTenancy, }) } diff --git a/pkg/util/huawei/client/modules/mod_servers.go b/pkg/util/huawei/client/modules/mod_servers.go index ac7c99c7e6..cf967398b9 100644 --- a/pkg/util/huawei/client/modules/mod_servers.go +++ b/pkg/util/huawei/client/modules/mod_servers.go @@ -121,4 +121,4 @@ func NewServerV2Manager(regionId, projectId string, signer auth.Signer, debug bo ResourceKeyword: "cloudservers", }} -} \ No newline at end of file +} diff --git a/pkg/util/huawei/instance.go b/pkg/util/huawei/instance.go index c3711cfb72..5649fd1ee9 100644 --- a/pkg/util/huawei/instance.go +++ b/pkg/util/huawei/instance.go @@ -31,10 +31,10 @@ import ( billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/util/cloudinit" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" "yunion.io/x/onecloud/pkg/util/huawei/client/modules" ) @@ -1295,4 +1295,4 @@ func updateUserData(userData, username, password string) (string, error) { } return config.UserDataBase64(), nil -} \ No newline at end of file +} diff --git a/pkg/util/huawei/shell/instance.go b/pkg/util/huawei/shell/instance.go index 0ca0a46b86..1e0b81b7cb 100644 --- a/pkg/util/huawei/shell/instance.go +++ b/pkg/util/huawei/shell/instance.go @@ -125,7 +125,7 @@ func init() { shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *huawei.SRegion, args *InstanceRebuildRootOptions) error { ctx := context.Background() - jobId, err := cli.ChangeRoot(ctx, args.UserId,args.ID, args.Image, args.Password, args.PublicKey, args.UserData) + jobId, err := cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKey, args.UserData) if err != nil { return err }