feature: saml for cloudid

This commit is contained in:
Qu Xuan
2020-09-07 15:28:43 +08:00
parent 7123a8fc28
commit d4edbbb610
101 changed files with 4505 additions and 486 deletions
+14 -14
View File
@@ -17,22 +17,22 @@ package cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Cloudgroups).WithKeyword("cloud-group")
cmd.List(&options.CloudgroupListOptions{})
cmd.Create(&options.CloudgroupCreateOptions{})
cmd.Show(&options.CloudgroupIdOptions{})
cmd.Delete(&options.CloudgroupIdOptions{})
cmd.Perform("syncstatus", &options.CloudgroupIdOptions{})
cmd.Perform("attach-policy", &options.CloudgroupPolicyOptions{})
cmd.Perform("detach-policy", &options.CloudgroupPolicyOptions{})
cmd.Perform("add-user", &options.CloudgroupUserOptions{})
cmd.Perform("remove-user", &options.CloudgroupUserOptions{})
cmd.Perform("set-policies", &options.CloudgroupPolicyOptions{})
cmd.Perform("set-users", &options.CloudgroupUserOptions{})
cmd.Perform("public", &options.CloudgroupPublicOptions{})
cmd.Perform("private", &options.CloudgroupIdOptions{})
cmd.List(&cloudid.CloudgroupListOptions{})
cmd.Create(&cloudid.CloudgroupCreateOptions{})
cmd.Show(&cloudid.CloudgroupIdOptions{})
cmd.Delete(&cloudid.CloudgroupIdOptions{})
cmd.Perform("syncstatus", &cloudid.CloudgroupIdOptions{})
cmd.Perform("attach-policy", &cloudid.CloudgroupPolicyOptions{})
cmd.Perform("detach-policy", &cloudid.CloudgroupPolicyOptions{})
cmd.Perform("add-user", &cloudid.CloudgroupUserOptions{})
cmd.Perform("remove-user", &cloudid.CloudgroupUserOptions{})
cmd.Perform("set-policies", &cloudid.CloudgroupPolicyOptions{})
cmd.Perform("set-users", &cloudid.CloudgroupUserOptions{})
cmd.Perform("public", &cloudid.CloudgroupPublicOptions{})
cmd.Perform("private", &cloudid.CloudgroupIdOptions{})
}
+7 -51
View File
@@ -15,59 +15,15 @@
package cloudid
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
type CloudgroupcacheListOptions struct {
options.BaseListOptions
CloudgroupId string `json:"cloudgroup_id"`
}
R(&CloudgroupcacheListOptions{}, "cloud-group-cache-list", "List cloud group caches", func(s *mcclient.ClientSession, opts *CloudgroupcacheListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.Cloudgroupcaches.List(s, params)
if err != nil {
return err
}
printList(result, modules.Cloudgroupcaches.GetColumns(s))
return nil
})
type CloudgroupcacheIdOption struct {
ID string `help:"Cloudgroup Id"`
}
R(&CloudgroupcacheIdOption{}, "cloud-group-cache-show", "Show cloud groupcache details", func(s *mcclient.ClientSession, opts *CloudgroupcacheIdOption) error {
result, err := modules.Cloudgroupcaches.Get(s, opts.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudgroupcacheIdOption{}, "cloud-group-cache-syncstatus", "Sync cloudgroupcache", func(s *mcclient.ClientSession, opts *CloudgroupcacheIdOption) error {
result, err := modules.Cloudgroupcaches.PerformAction(s, opts.ID, "syncstatus", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudgroupcacheIdOption{}, "cloud-group-cache-delete", "Delete cloudgroupcache", func(s *mcclient.ClientSession, opts *CloudgroupcacheIdOption) error {
result, err := modules.Cloudgroupcaches.Delete(s, opts.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
cmd := shell.NewResourceCmd(&modules.Cloudgroupcaches).WithKeyword("cloud-group-cache")
cmd.List(&cloudid.CloudgroupcacheListOptions{})
cmd.Show(&cloudid.CloudgroupcacheIdOption{})
cmd.Delete(&cloudid.CloudgroupcacheIdOption{})
cmd.Perform("syncstatus", &cloudid.CloudgroupcacheIdOption{})
}
+4 -50
View File
@@ -15,58 +15,12 @@
package cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
type CloudgroupPolicyListOptions struct {
options.BaseListOptions
Cloudgroup string `help:"ID or Name of Cloudgroup"`
Cloudpolicy string `help:"Policy ID or name"`
}
R(&CloudgroupPolicyListOptions{}, "cloud-group-policy-list", "List cloudgroup cloudpolicy pairs", func(s *mcclient.ClientSession, args *CloudgroupPolicyListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = args.BaseListOptions.Params()
if err != nil {
return err
}
}
var result *modulebase.ListResult
var err error
if len(args.Cloudgroup) > 0 {
result, err = modules.Cloudgrouppolicies.ListDescendent(s, args.Cloudgroup, params)
} else if len(args.Cloudpolicy) > 0 {
result, err = modules.Cloudgrouppolicies.ListDescendent2(s, args.Cloudpolicy, params)
} else {
result, err = modules.Cloudgrouppolicies.List(s, params)
}
if err != nil {
return err
}
printList(result, modules.Cloudgrouppolicies.GetColumns(s))
return nil
})
type CloudgroupPolicyDetailOptions struct {
CLOUDUSER string `help:"ID or Name of Cloudgroup"`
CLOUDPOLICY string `help:"ID or Name of Cloudpolicy"`
}
R(&CloudgroupPolicyDetailOptions{}, "cloud-group-policy-show", "Show cloudgrouppolicy details", func(s *mcclient.ClientSession, args *CloudgroupPolicyDetailOptions) error {
query := jsonutils.NewDict()
result, err := modules.Cloudgrouppolicies.Get(s, args.CLOUDUSER, args.CLOUDPOLICY, query)
if err != nil {
return err
}
printObject(result)
return nil
})
cmd := shell.NewResourceCmd(&modules.Cloudgrouppolicies).WithKeyword("cloud-group-policy").WithContextManager(&modules.Cloudgroups)
cmd.List(&cloudid.CloudgroupPolicyListOptions{})
}
+4 -50
View File
@@ -15,58 +15,12 @@
package cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
type CloudgroupUserListOptions struct {
options.BaseListOptions
Cloudgroup string `help:"ID or Name of Cloudgroup"`
Clouduser string `help:"User ID or name"`
}
R(&CloudgroupUserListOptions{}, "cloud-group-user-list", "List cloudgroup clouduser pairs", func(s *mcclient.ClientSession, args *CloudgroupUserListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = args.BaseListOptions.Params()
if err != nil {
return err
}
}
var result *modulebase.ListResult
var err error
if len(args.Cloudgroup) > 0 {
result, err = modules.Cloudgroupusers.ListDescendent(s, args.Cloudgroup, params)
} else if len(args.Clouduser) > 0 {
result, err = modules.Cloudgroupusers.ListDescendent2(s, args.Clouduser, params)
} else {
result, err = modules.Cloudgroupusers.List(s, params)
}
if err != nil {
return err
}
printList(result, modules.Cloudgroupusers.GetColumns(s))
return nil
})
type CloudgroupUserDetailOptions struct {
CLOUDUSER string `help:"ID or Name of Cloudgroup"`
CLOUDPOLICY string `help:"ID or Name of Clouduser"`
}
R(&CloudgroupUserDetailOptions{}, "cloud-group-user-show", "Show cloudgroupuser details", func(s *mcclient.ClientSession, args *CloudgroupUserDetailOptions) error {
query := jsonutils.NewDict()
result, err := modules.Cloudgroupusers.Get(s, args.CLOUDUSER, args.CLOUDPOLICY, query)
if err != nil {
return err
}
printObject(result)
return nil
})
cmd := shell.NewResourceCmd(&modules.Cloudgroupusers).WithKeyword("cloud-group-user").WithContextManager(&modules.Cloudusers)
cmd.List(&cloudid.CloudgroupUserListOptions{})
}
+10 -10
View File
@@ -17,18 +17,18 @@ package cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Cloudpolicies).WithKeyword("cloud-policy")
cmd.Create(&options.CloudpolicyListOptions{})
cmd.List(&options.CloudpolicyListOptions{})
cmd.Show(&options.CloudpolicyIdOptions{})
cmd.Update(&options.CloudpolicyUpdateOption{})
cmd.Perform("syncstauts", &options.CloudpolicyIdOptions{})
cmd.Perform("lock", &options.CloudpolicyIdOptions{})
cmd.Perform("unlock", &options.CloudpolicyIdOptions{})
cmd.Perform("assign-group", &options.CloudpolicyGroupOptions{})
cmd.Perform("revoke-group", &options.CloudpolicyGroupOptions{})
cmd.Create(&cloudid.CloudpolicyListOptions{})
cmd.List(&cloudid.CloudpolicyListOptions{})
cmd.Show(&cloudid.CloudpolicyIdOptions{})
cmd.Update(&cloudid.CloudpolicyUpdateOption{})
cmd.Perform("syncstauts", &cloudid.CloudpolicyIdOptions{})
cmd.Perform("lock", &cloudid.CloudpolicyIdOptions{})
cmd.Perform("unlock", &cloudid.CloudpolicyIdOptions{})
cmd.Perform("assign-group", &cloudid.CloudpolicyGroupOptions{})
cmd.Perform("revoke-group", &cloudid.CloudpolicyGroupOptions{})
}
+4 -20
View File
@@ -15,28 +15,12 @@
package cloudid
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
type CloudpolicycacheListOptions struct {
options.BaseListOptions
CloudpolyId string
CloudaccountId string
}
R(&CloudpolicycacheListOptions{}, "cloud-policy-cache-list", "List cloud policy caches", func(s *mcclient.ClientSession, opts *CloudpolicycacheListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.Cloudpolicycaches.List(s, params)
if err != nil {
return err
}
printList(result, modules.Cloudpolicycaches.GetColumns(s))
return nil
})
cmd := shell.NewResourceCmd(&modules.Cloudpolicycaches).WithKeyword("cloud-policy-cache")
cmd.List(&cloudid.CloudpolicycacheListOptions{})
}
+29
View File
@@ -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 cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Cloudroles).WithKeyword("cloud-role")
cmd.List(&cloudid.CloudroleListOptions{})
cmd.Delete(&cloudid.CloudroleIdOptions{})
cmd.Show(&cloudid.CloudroleIdOptions{})
cmd.Perform("purge", &cloudid.CloudroleIdOptions{})
}
+4 -50
View File
@@ -15,58 +15,12 @@
package cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
type ClouduserPolicyListOptions struct {
options.BaseListOptions
Clouduser string `help:"ID or Name of Clouduser"`
Cloudpolicy string `help:"Policy ID or name"`
}
R(&ClouduserPolicyListOptions{}, "cloud-user-policy-list", "List clouduser cloudpolicy pairs", func(s *mcclient.ClientSession, args *ClouduserPolicyListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = args.BaseListOptions.Params()
if err != nil {
return err
}
}
var result *modulebase.ListResult
var err error
if len(args.Clouduser) > 0 {
result, err = modules.Clouduserpolicies.ListDescendent(s, args.Clouduser, params)
} else if len(args.Cloudpolicy) > 0 {
result, err = modules.Clouduserpolicies.ListDescendent2(s, args.Cloudpolicy, params)
} else {
result, err = modules.Clouduserpolicies.List(s, params)
}
if err != nil {
return err
}
printList(result, modules.Clouduserpolicies.GetColumns(s))
return nil
})
type ClouduserPolicyDetailOptions struct {
CLOUDUSER string `help:"ID or Name of Clouduser"`
CLOUDPOLICY string `help:"ID or Name of Cloudpolicy"`
}
R(&ClouduserPolicyDetailOptions{}, "cloud-user-policy-show", "Show clouduserpolicy details", func(s *mcclient.ClientSession, args *ClouduserPolicyDetailOptions) error {
query := jsonutils.NewDict()
result, err := modules.Clouduserpolicies.Get(s, args.CLOUDUSER, args.CLOUDPOLICY, query)
if err != nil {
return err
}
printObject(result)
return nil
})
cmd := shell.NewResourceCmd(&modules.Clouduserpolicies).WithKeyword("cloud-user-policy").WithContextManager(&modules.Cloudpolicies)
cmd.List(&cloudid.ClouduserPolicyListOptions{})
}
+14 -14
View File
@@ -17,22 +17,22 @@ package cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Cloudusers).WithKeyword("cloud-user")
cmd.List(&options.ClouduserListOptions{})
cmd.Create(&options.ClouduserCreateOptions{})
cmd.Show(&options.ClouduserIdOption{})
cmd.Custom(shell.CustomActionGet, "login-info", &options.ClouduserIdOption{})
cmd.Delete(&options.ClouduserIdOption{})
cmd.Perform("sync", &options.ClouduserSyncOptions{})
cmd.Perform("syncstatus", &options.ClouduserIdOption{})
cmd.Perform("attach-policy", &options.ClouduserPolicyOptions{})
cmd.Perform("detach-policy", &options.ClouduserPolicyOptions{})
cmd.Perform("change-owner", &options.ClouduserChangeOwnerOptions{})
cmd.Perform("reset-password", &options.ClouduserResetPasswordOptions{})
cmd.Perform("cloud-user-join-group", &options.ClouduserGroupOptions{})
cmd.Perform("cloud-user-leave-group", &options.ClouduserGroupOptions{})
cmd.List(&cloudid.ClouduserListOptions{})
cmd.Create(&cloudid.ClouduserCreateOptions{})
cmd.Show(&cloudid.ClouduserIdOption{})
cmd.Custom(shell.CustomActionGet, "login-info", &cloudid.ClouduserIdOption{})
cmd.Delete(&cloudid.ClouduserIdOption{})
cmd.Perform("sync", &cloudid.ClouduserSyncOptions{})
cmd.Perform("syncstatus", &cloudid.ClouduserIdOption{})
cmd.Perform("attach-policy", &cloudid.ClouduserPolicyOptions{})
cmd.Perform("detach-policy", &cloudid.ClouduserPolicyOptions{})
cmd.Perform("change-owner", &cloudid.ClouduserChangeOwnerOptions{})
cmd.Perform("reset-password", &cloudid.ClouduserResetPasswordOptions{})
cmd.Perform("cloud-user-join-group", &cloudid.ClouduserGroupOptions{})
cmd.Perform("cloud-user-leave-group", &cloudid.ClouduserGroupOptions{})
}
+29
View File
@@ -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 cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.SAMLProviders).WithKeyword("saml-provider")
cmd.List(&cloudid.SAMLProviderListOptions{})
cmd.Create(&cloudid.SAMLProviderCreateOptions{})
cmd.Show(&cloudid.SAMLProviderIdOptions{})
cmd.Delete(&cloudid.SAMLProviderIdOptions{})
}
+29
View File
@@ -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 cloudid
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Samlusers).WithKeyword("saml-user")
cmd.List(&cloudid.SamluserListOptions{})
cmd.Create(&cloudid.SamluserCreateOptions{})
cmd.Show(&cloudid.SamluserIdOptions{})
cmd.Delete(&cloudid.SamluserIdOptions{})
}
+1 -2
View File
@@ -42,8 +42,7 @@ func NewProxyHandlerWithService(prefix string, serviceName string) *InfluxdbProx
}
func requestManipulator(ctx context.Context, r *http.Request) (*http.Request, error) {
r.Header.Del("Cookie")
token := AppContextToken(ctx)
token, _, _ := fetchAuthInfo(ctx, r)
if token != nil {
r.Header.Set("X-Auth-Token", token.GetTokenString())
}
+10
View File
@@ -162,3 +162,13 @@ type CloudgroupSyncInput struct {
type CloudgroupUpdateInput struct {
}
type CloudgroupResourceListInput struct {
// 根据权限组Id过滤资源
CloudgroupId string `json:"cloudgroup_id"`
}
type CloudgroupResourceDetails struct {
// 公有云用户名称
Cloudgroup string `json:"cloudgroup"`
}
+40
View File
@@ -0,0 +1,40 @@
// 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 cloudid
import "yunion.io/x/onecloud/pkg/apis"
const (
CLOUD_ROLE_STATUS_CREATING = "creating" // 创建中
CLOUD_ROLE_STATUS_AVAILABLE = "available" // 正常
CLOUD_ROLE_STATUS_DELETING = "deleting" // 删除中
CLOUD_ROLE_STATUS_DELETE_FAILED = "delete_failed" // 删除失败
)
type CloudroleListInput struct {
apis.StatusInfrasResourceBaseListInput
CloudaccountResourceListInput
}
type CloudroleDetails struct {
apis.StatusInfrasResourceBaseDetails
CloudaccountResourceDetails
SCloudrole
}
type CloudrolePurgeInput struct {
}
+52
View File
@@ -0,0 +1,52 @@
// 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 cloudid
import "yunion.io/x/onecloud/pkg/apis"
const (
SAML_PROVIDER_STATUS_AVAILABLE = "available"
SAML_PROVIDER_STATUS_NOT_MATCH = "not_match"
SAML_PROVIDER_STATUS_DELETING = "deleting"
SAML_PROVIDER_STATUS_DELETE_FAILED = "delete_failed"
SAML_PROVIDER_STATUS_UNKNOWN = "unknown"
SAML_PROVIDER_STATUS_CREATING = "creating"
SAML_PROVIDER_STATUS_CREATE_FAILED = "create_failed"
SAML_PROVIDER_STATUS_UNVALIABLE = "unavailable"
)
type SAMLProviderListInput struct {
apis.StatusInfrasResourceBaseListInput
CloudaccountResourceListInput
}
type SAMLProviderDetails struct {
apis.StatusInfrasResourceBaseDetails
CloudaccountResourceDetails
SSAMLProvider
}
type SAMLProviderCreateInput struct {
apis.StatusInfrasResourceBaseCreateInput
CloudaccountId string `json:"cloudaccount_id"`
// swagger:ignore
EntityId string `json:"entity_id"`
// swagger:ignore
MetadataDocument string `json:"metadata_document"`
}
+45
View File
@@ -0,0 +1,45 @@
// 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 cloudid
import "yunion.io/x/onecloud/pkg/apis"
const (
SAML_USER_STATUS_AVAILABLE = "available"
)
type SamluserCreateInput struct {
apis.StatusDomainLevelUserResourceCreateInput
// 权限组和账号必须是同一平台
CloudgroupId string `json:"cloudgroup_id"`
// 权限组和账号必须是同一平台
CloudaccountId string `json:"cloudaccount_id"`
}
type SamluserListInput struct {
apis.StatusDomainLevelUserResourceListInput
CloudgroupResourceListInput
CloudaccountResourceListInput
}
type SamluserDetails struct {
apis.StatusDomainLevelUserResourceDetails
CloudgroupResourceDetails
CloudaccountResourceDetails
SSamluser
}
+39
View File
@@ -18,13 +18,20 @@ import (
"yunion.io/x/onecloud/pkg/apis"
)
// SAMLProviderResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SAMLProviderResourceBase.
type SAMLProviderResourceBase struct {
SAMLProviderId string `json:"saml_provider_id"`
}
// SCloudaccount is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SCloudaccount.
type SCloudaccount struct {
apis.SStandaloneResourceBase
apis.SDomainizedResourceBase
AccountId string `json:"account_id"`
Provider string `json:"provider"`
Brand string `json:"brand"`
IamLoginUrl string `json:"iam_login_url"`
SAMLAuth *bool `json:"saml_auth,omitempty"`
}
// SCloudaccountResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SCloudaccountResourceBase.
@@ -52,6 +59,11 @@ type SCloudgroupPolicy struct {
SCloudpolicyResourceBase
}
// SCloudgroupResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SCloudgroupResourceBase.
type SCloudgroupResourceBase struct {
CloudgroupId string `json:"cloudgroup_id"`
}
// SCloudgroupUser is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SCloudgroupUser.
type SCloudgroupUser struct {
SCloudgroupJointsBase
@@ -121,6 +133,16 @@ type SCloudproviderResourceBase struct {
CloudproviderId string `json:"cloudprovider_id"`
}
// SCloudrole is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SCloudrole.
type SCloudrole struct {
apis.SEnabledStatusInfrasResourceBase
apis.SExternalizedResourceBase
SCloudaccountResourceBase
SAMLProviderResourceBase
Document interface{} `json:"document"`
OwnerId string `json:"owner_id"`
}
// SClouduser is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SClouduser.
type SClouduser struct {
apis.SStatusDomainLevelUserResourceBase
@@ -152,3 +174,20 @@ type SClouduserPolicy struct {
type SClouduserResourceBase struct {
ClouduserId string `json:"clouduser_id"`
}
// SSAMLProvider is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SSAMLProvider.
type SSAMLProvider struct {
apis.SStatusInfrasResourceBase
apis.SExternalizedResourceBase
SCloudaccountResourceBase
EntityId string `json:"entity_id"`
MetadataDocument string `json:"metadata_document"`
AuthUrl string `json:"auth_url"`
}
// SSamluser is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudid/models.SSamluser.
type SSamluser struct {
apis.SStatusDomainLevelUserResourceBase
SCloudgroupResourceBase
SCloudaccountResourceBase
}
+9 -5
View File
@@ -191,6 +191,10 @@ type CloudaccountCreateInput struct {
cloudprovider.SCloudaccount
cloudprovider.SCloudaccountCredential
// 是否启用SAML认证
// default: false
SAMLAuth *bool `json:"saml_auth"`
}
type CloudaccountShareModeInput struct {
@@ -404,13 +408,13 @@ type EnrollmentAccountQuery struct {
type GetCloudaccountSamlOutput struct {
// cloudaccount SAML ServiceProvider entity ID
EntityId string `json:"entity_id"`
EntityId string `json:"entity_id,allowempty"`
// redirect login URL for this cloudaccount
RedirectLoginUrl string `json:"redirect_login_url"`
RedirectLoginUrl string `json:"redirect_login_url,allowempty"`
// redirect logout URL for this cloudaccount
RedirectLogoutUrl string `json:"redirect_logout_url"`
RedirectLogoutUrl string `json:"redirect_logout_url,allowempty"`
// metadata URL for this cloudaccount
MetadataUrl string `json:"metadata_url"`
MetadataUrl string `json:"metadata_url,allowempty"`
// initial SAML SSO login URL for this cloudaccount
InitLoginUrl string `json:"init_login_url"`
InitLoginUrl string `json:"init_login_url,allowempty"`
}
+67 -3
View File
@@ -202,6 +202,7 @@ type SCloudaccount struct {
ProxySettingId string `json:"proxy_setting_id"`
// 公有云子账号登录地址
IamLoginUrl string `json:"iam_login_url"`
SAMLAuth *bool `json:"saml_auth,omitempty"`
}
// SCloudprovider is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudprovider.
@@ -257,6 +258,11 @@ type SCloudproviderQuota struct {
QuotaType string `json:"quota_type"`
}
// SCloudproviderResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudproviderResourceBase.
type SCloudproviderResourceBase struct {
CloudproviderId string `json:"cloudprovider_id"`
}
// SCloudproviderregion is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudproviderregion.
type SCloudproviderregion struct {
apis.SJointResourceBase
@@ -271,6 +277,12 @@ type SCloudproviderregion struct {
LastAutoSyncAt time.Time `json:"last_auto_sync_at"`
}
// SCloudproviderschedtag is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudproviderschedtag.
type SCloudproviderschedtag struct {
SSchedtagJointsBase
SCloudproviderResourceBase
}
// SCloudregion is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudregion.
type SCloudregion struct {
apis.SEnabledStatusStandaloneResourceBase
@@ -291,6 +303,12 @@ type SCloudregionResourceBase struct {
CloudregionId string `json:"cloudregion_id"`
}
// SCloudregionschedtag is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudregionschedtag.
type SCloudregionschedtag struct {
SSchedtagJointsBase
SCloudregionResourceBase
}
// SDBInstance is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstance.
type SDBInstance struct {
apis.SVirtualResourceBase
@@ -499,6 +517,8 @@ type SDisk struct {
// swap: 交换盘
// example: sys
DiskType string `json:"disk_type"`
// cpu架构
OsArch string `json:"os_arch"`
// # is persistent
Nonpersistent bool `json:"nonpersistent"`
// 是否标记为SSD磁盘
@@ -900,6 +920,9 @@ type SGuest struct {
// 虚拟化技术
// example: kvm
Hypervisor string `json:"hypervisor"`
// 虚拟机CPU架构
// example: x86 arm
OsArch string `json:"os_arch"`
// 套餐名称
InstanceType string `json:"instance_type"`
}
@@ -1182,6 +1205,8 @@ type SHuaweiCachedLbbg struct {
// SInstanceSnapshot is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SInstanceSnapshot.
type SInstanceSnapshot struct {
apis.SVirtualResourceBase
apis.SExternalizedResourceBase
SManagedResourceBase
// 云主机Id
GuestId string `json:"guest_id"`
// 云主机配置
@@ -1198,6 +1223,8 @@ type SInstanceSnapshot struct {
KeypairId string `json:"keypair_id"`
// 操作系统类型
OsType string `json:"os_type"`
// CPU架构
OsArch string `json:"os_arch"`
// 套餐名称
InstanceType string `json:"instance_type"`
}
@@ -1253,6 +1280,7 @@ type SLoadbalancer struct {
apis.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
SDeletePreventableResourceBase
// LB might optionally be in a VPC, vpc_id, manager_id, cloudregion_id
SVpcResourceBase
// zone_id
@@ -1814,6 +1842,33 @@ type SRouteTable struct {
Routes *SRoutes `json:"routes"`
}
// SRouteTableAssociation is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRouteTableAssociation.
type SRouteTableAssociation struct {
apis.SStatusStandaloneResourceBase
apis.SExternalizedResourceBase
SRouteTableResourceBase
AssociationType string `json:"association_type"`
AssociatedResourceId string `json:"associated_resource_id"`
ExtAssociatedResourceId string `json:"ext_associated_resource_id"`
}
// SRouteTableResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRouteTableResourceBase.
type SRouteTableResourceBase struct {
RouteTableId string `json:"route_table_id"`
}
// SRouteTableRouteSet is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRouteTableRouteSet.
type SRouteTableRouteSet struct {
apis.SStatusStandaloneResourceBase
apis.SExternalizedResourceBase
SRouteTableResourceBase
Type string `json:"type"`
Cidr string `json:"cidr"`
NextHopType string `json:"next_hop_type"`
NextHopId string `json:"next_hop_id"`
ExtNextHopId string `json:"ext_next_hop_id"`
}
// SScalingActivity is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SScalingActivity.
type SScalingActivity struct {
apis.SStatusStandaloneResourceBase
@@ -2085,6 +2140,7 @@ type SSnapshot struct {
DiskType string `json:"disk_type"`
// 操作系统类型
OsType string `json:"os_type"`
OsArch string `json:"os_arch"`
// create disk from snapshot, snapshot as disk backing file
RefCount int `json:"ref_count"`
BackingDiskId string `json:"backing_disk_id"`
@@ -2253,9 +2309,11 @@ type SVpcPeeringConnection struct {
apis.SEnabledStatusInfrasResourceBase
apis.SExternalizedResourceBase
SVpcResourceBase
PeerVpcId string `json:"peer_vpc_id"`
PeerAccountId string `json:"peer_account_id"`
Bandwidth int `json:"bandwidth"`
ExtPeerVpcId string `json:"ext_peer_vpc_id"`
ExtPeerAccountId string `json:"ext_peer_account_id"`
PeerVpcId string `json:"peer_vpc_id"`
PeerAccountId string `json:"peer_account_id"`
Bandwidth int `json:"bandwidth"`
}
// SVpcResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SVpcResourceBase.
@@ -2300,3 +2358,9 @@ type SZone struct {
type SZoneResourceBase struct {
ZoneId string `json:"zone_id"`
}
// SZoneschedtag is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SZoneschedtag.
type SZoneschedtag struct {
SSchedtagJointsBase
SZoneResourceBase
}
+4
View File
@@ -22,6 +22,8 @@ import (
type SGuestImage struct {
apis.SSharableVirtualResourceBase
Protected *bool `json:"protected,omitempty"`
// 操作系统CPU架构
OsArch string `json:"os_arch"`
}
// SGuestImageJoint is an autogenerated struct via yunion.io/x/onecloud/pkg/image/models.SGuestImageJoint.
@@ -57,6 +59,8 @@ type SImage struct {
IsGuestImage *bool `json:"is_guest_image,omitempty"`
// 是否是数据盘镜像
IsData *bool `json:"is_data,omitempty"`
// 操作系统CPU架构
OsArch string `json:"os_arch"`
// image copy from url, save origin checksum before probe
// 从镜像时长导入的镜像校验和
OssChecksum string `json:"oss_checksum"`
+16 -3
View File
@@ -53,9 +53,14 @@ type SAlertDashBoard struct {
apis.SEnabledResourceBase
apis.SStatusStandaloneResourceBase
apis.SScopedResourceBase
Refresh string `json:"refresh"`
Settings interface{} `json:"settings"`
Message string `json:"message"`
Refresh string `json:"refresh"`
}
// SAlertDashboardPanel is an autogenerated struct via yunion.io/x/onecloud/pkg/monitor/models.SAlertDashboardPanel.
type SAlertDashboardPanel struct {
apis.SVirtualJointResourceBase
DashboardId string `json:"dashboard_id"`
PanelId string `json:"panel_id"`
}
// SAlertJointsBase is an autogenerated struct via yunion.io/x/onecloud/pkg/monitor/models.SAlertJointsBase.
@@ -64,6 +69,14 @@ type SAlertJointsBase struct {
AlertId string `json:"alert_id"`
}
// SAlertPanel is an autogenerated struct via yunion.io/x/onecloud/pkg/monitor/models.SAlertPanel.
type SAlertPanel struct {
apis.SStatusStandaloneResourceBase
apis.SScopedResourceBase
Settings interface{} `json:"settings"`
Message string `json:"message"`
}
// SAlertRecord is an autogenerated struct via yunion.io/x/onecloud/pkg/monitor/models.SAlertRecord.
type SAlertRecord struct {
// db.SVirtualResourceBase
+448 -18
View File
@@ -17,8 +17,10 @@ package models
import (
"context"
"database/sql"
"fmt"
"net/http"
"net/url"
"strings"
"golang.org/x/net/http/httpproxy"
@@ -67,9 +69,11 @@ type SCloudaccount struct {
db.SStandaloneResourceBase
db.SDomainizedResourceBase
Provider string `width:"64" charset:"ascii" list:"domain"`
Brand string `width:"64" charset:"utf8" nullable:"true" list:"domain"`
IamLoginUrl string `width:"512" charset:"ascii"`
AccountId string `width:"128" charset:"utf8" nullable:"true" list:"domain" create:"domain_optional"`
Provider string `width:"64" charset:"ascii" list:"domain"`
Brand string `width:"64" charset:"utf8" nullable:"true" list:"domain"`
IamLoginUrl string `width:"512" charset:"ascii"`
SAMLAuth tristate.TriState `nullable:"false" list:"domain" default:"false"`
}
func (manager *SCloudaccountManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
@@ -206,6 +210,34 @@ func (self *SCloudaccount) removeCloudgroupcaches(ctx context.Context, userCred
return nil
}
func (self *SCloudaccount) removeSAMLProviders(ctx context.Context, userCred mcclient.TokenCredential) error {
samls, err := self.GetSAMLProviders()
if err != nil {
return errors.Wrap(err, "GetSAMLProviders")
}
for i := range samls {
err = samls[i].RealDelete(ctx, userCred)
if err != nil {
return errors.Wrap(err, "samls[i].RealDelete")
}
}
return nil
}
func (self *SCloudaccount) removeCloudroles(ctx context.Context, userCred mcclient.TokenCredential) error {
roles, err := self.GetCloudroles()
if err != nil {
return errors.Wrapf(err, "GetCloudroles")
}
for i := range roles {
err = roles[i].RealDelete(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "roles.RealDelete")
}
}
return nil
}
func (self *SCloudaccount) syncRemoveCloudaccount(ctx context.Context, userCred mcclient.TokenCredential) error {
err := self.syncRemoveClouduser(ctx, userCred)
if err != nil {
@@ -222,9 +254,48 @@ func (self *SCloudaccount) syncRemoveCloudaccount(ctx context.Context, userCred
return errors.Wrap(err, "removeCloudgroupcaches")
}
err = self.removeSAMLProviders(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "removeSAMLProviders")
}
err = self.removeCloudroles(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "removeCloudroles")
}
err = self.removeSamluser(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "syncRemoveSamluser")
}
return self.Delete(ctx, userCred)
}
func (self *SCloudaccount) GetSamlusers() ([]SSamluser, error) {
q := SamluserManager.Query().Equals("cloudaccount_id", self.Id)
users := []SSamluser{}
err := db.FetchModelObjects(SamluserManager, q, &users)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return users, nil
}
func (self *SCloudaccount) removeSamluser(ctx context.Context, userCred mcclient.TokenCredential) error {
users, err := self.GetSamlusers()
if err != nil {
return errors.Wrapf(err, "GetSamusers")
}
for i := range users {
err = users[i].Delete(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "delete %s(%s)", users[i].Name, users[i].Id)
}
}
return nil
}
func (self *SCloudaccount) syncRemoveClouduser(ctx context.Context, userCred mcclient.TokenCredential) error {
users, err := self.getCloudusers()
if err != nil {
@@ -248,6 +319,9 @@ func (manager *SCloudaccountManager) newFromICloudaccount(ctx context.Context, u
if err != nil {
return nil, errors.Wrap(err, "Insert")
}
if account.SAMLAuth.IsTrue() {
account.StartSAMLProviderCreateTask(ctx, userCred)
}
return account, nil
}
@@ -258,11 +332,14 @@ func (self *SCloudaccount) syncWithICloudaccount(ctx context.Context, userCred m
self.DomainId = account.DomainId
self.Brand = account.Brand
self.IamLoginUrl = account.IamLoginUrl
self.SAMLAuth = account.SAMLAuth
self.AccountId = account.AccountId
return nil
})
if err != nil {
return errors.Wrap(err, "db.UpdateWithLock")
}
self.StartSAMLProviderCreateTask(ctx, userCred)
return nil
}
@@ -278,6 +355,16 @@ func (manager *SCloudaccountManager) SyncCloudaccounts(ctx context.Context, user
}
}
func (self *SCloudaccount) StartSyncSamlProvidersTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
params := jsonutils.NewDict()
task, err := taskman.TaskManager.NewTask(ctx, "SyncSAMLProvidersTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
task.ScheduleRun(nil)
return nil
}
func (self SCloudaccount) GetGlobalId() string {
return self.Id
}
@@ -407,6 +494,8 @@ func (account *SCloudDelegate) GetProvider() (cloudprovider.ICloudProvider, erro
Account: account.Account,
Secret: passwd,
ProxyFunc: proxyFunc,
AccountId: account.Id,
})
}
@@ -463,14 +552,12 @@ func (self *SCloudaccount) SyncCloudusers(ctx context.Context, userCred mcclient
}
for i := 0; i < len(removed); i++ {
if len(removed[i].ExternalId) > 0 {
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i++ {
@@ -860,7 +947,7 @@ func (self *SCloudaccount) syncCloudprovider(ctx context.Context, userCred mccli
for i := 0; i < len(removed); i++ {
err = removed[i].Delete(ctx, userCred)
if err != nil {
result.AddError(err)
result.DeleteError(err)
continue
}
result.Delete()
@@ -970,6 +1057,180 @@ func (manager *SCloudaccountManager) SyncCloudidResources(ctx context.Context, u
}
}
func (self *SCloudaccount) IsSAMLProviderValid() (*SSAMLProvider, bool) {
provider, err := self.RegisterSAMProvider()
if err != nil {
return provider, false
}
if len(provider.ExternalId) == 0 {
return provider, false
}
return provider, true
}
func (self *SCloudaccount) RegisterSAMProvider() (*SSAMLProvider, error) {
if len(options.Options.ApiServer) == 0 {
return nil, fmt.Errorf("empty api server")
}
sps, err := self.GetSAMLProviders()
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProviders")
}
for i := range sps {
if sps[i].EntityId == options.Options.ApiServer {
return &sps[i], nil
}
}
sp := &SSAMLProvider{}
sp.SetModelManager(SAMLProviderManager, sp)
sp.Name = func() string {
name := strings.TrimPrefix(options.Options.ApiServer, "https://")
name = strings.TrimPrefix(name, "http://")
return name
}()
sp.EntityId = options.Options.ApiServer
sp.CloudaccountId = self.Id
sp.Status = api.SAML_PROVIDER_STATUS_CREATING
metadata := SamlIdpInstance().GetMetadata(self.Id).String()
sp.MetadataDocument = metadata
err = SAMLProviderManager.TableSpec().Insert(context.TODO(), sp)
if err != nil {
return nil, errors.Wrapf(err, "Insert")
}
return sp, nil
}
func (self *SCloudaccount) StartSAMLProviderCreateTask(ctx context.Context, userCred mcclient.TokenCredential) error {
if self.SAMLAuth.IsFalse() {
return nil
}
sp, valid := self.IsSAMLProviderValid()
if valid {
return nil
}
return sp.StartSAMLProviderCreateTask(ctx, userCred, "")
}
func (manager *SCloudaccountManager) SyncSAMLProviders(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
accounts, err := manager.GetSupportCloudIdAccounts()
if err != nil {
log.Errorf("GetSupportCloudIdAccounts error: %v", err)
return
}
for i := range accounts {
err = accounts[i].StartSyncSamlProvidersTask(ctx, userCred, "")
if err != nil {
log.Errorf("StartSyncSamlProvidersTask for account %s(%s) error: %v", accounts[i].Name, accounts[i].Provider, err)
}
}
}
func (manager *SCloudaccountManager) SyncCloudroles(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
accounts, err := manager.GetSupportCloudIdAccounts()
if err != nil {
log.Errorf("GetSupportCloudIdAccounts error: %v", err)
return
}
for i := range accounts {
err = accounts[i].StartSyncCloudrolesTask(ctx, userCred, "")
if err != nil {
log.Errorf("StartSyncCloudrolesTask for account %s(%s) error: %v", accounts[i].Name, accounts[i].Provider, err)
}
}
}
func (self *SCloudaccount) StartSyncCloudrolesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
params := jsonutils.NewDict()
task, err := taskman.TaskManager.NewTask(ctx, "SyncCloudrolesTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
task.ScheduleRun(nil)
return nil
}
func (self *SCloudaccount) GetSAMLProviders() ([]SSAMLProvider, error) {
q := SAMLProviderManager.Query().Equals("cloudaccount_id", self.Id)
samls := []SSAMLProvider{}
err := db.FetchModelObjects(SAMLProviderManager, q, &samls)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return samls, nil
}
func (self *SCloudaccount) SyncSAMLProviders(ctx context.Context, userCred mcclient.TokenCredential, samls []cloudprovider.ICloudSAMLProvider) compare.SyncResult {
result := compare.SyncResult{}
dbSamls, err := self.GetSAMLProviders()
if err != nil {
result.Error(errors.Wrap(err, "GetSAMLProviders"))
return result
}
removed := make([]SSAMLProvider, 0)
commondb := make([]SSAMLProvider, 0)
commonext := make([]cloudprovider.ICloudSAMLProvider, 0)
added := make([]cloudprovider.ICloudSAMLProvider, 0)
err = compare.CompareSets(dbSamls, samls, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrap(err, "compare.CompareSets"))
return result
}
for i := 0; i < len(removed); i++ {
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i++ {
err = commondb[i].SyncWithCloudSAMLProvider(ctx, userCred, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i++ {
err = self.newFromCloudSAMLProvider(ctx, userCred, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SCloudaccount) newFromCloudSAMLProvider(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSAMLProvider) error {
saml := &SSAMLProvider{}
saml.SetModelManager(SAMLProviderManager, saml)
saml.Name = ext.GetName()
saml.ExternalId = ext.GetGlobalId()
saml.DomainId = self.DomainId
saml.CloudaccountId = self.Id
metadata, err := ext.GetMetadataDocument()
if err != nil {
log.Errorf("failed to get metadata from %s(%s) error: %v", self.Name, self.Provider, err)
}
saml.Status = ext.GetStatus()
if metadata != nil {
saml.EntityId = metadata.EntityId
saml.MetadataDocument = metadata.String()
}
if saml.EntityId != options.Options.ApiServer {
saml.Status = api.SAML_PROVIDER_STATUS_NOT_MATCH
}
return SAMLProviderManager.TableSpec().Insert(ctx, saml)
}
func (self *SCloudaccount) StartSyncCloudIdResourcesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
params := jsonutils.NewDict()
task, err := taskman.TaskManager.NewTask(ctx, "SyncCloudIdResourcesTask", self, userCred, params, parentTaskId, "", nil)
@@ -999,14 +1260,12 @@ func (self *SCloudaccount) SyncCloudgroupcaches(ctx context.Context, userCred mc
}
for i := 0; i < len(removed); i++ {
if len(removed[i].ExternalId) > 0 { // 只删除云上已经删除过的组
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i++ {
@@ -1335,3 +1594,174 @@ func (self *SCloudaccount) SyncSystemCloudpoliciesForCloud(ctx context.Context,
log.Infof("Sync %s(%s) system policies for user %s result: %s", self.Name, self.Provider, clouduser.Name, result.Result())
return nil
}
func (self *SCloudaccount) GetLocalUserCloudroles(userId, spId string) ([]SCloudrole, error) {
roles := []SCloudrole{}
q := CloudroleManager.Query().Equals("cloudaccount_id", self.Id).Equals("owner_id", userId).Equals("saml_provider_id", spId)
err := db.FetchModelObjects(CloudroleManager, q, &roles)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return roles, nil
}
func (self *SCloudaccount) RegisterCloudrole(userId, spId string) (*SCloudrole, error) {
roles, err := self.GetLocalUserCloudroles(userId, spId)
if err != nil {
return nil, errors.Wrapf(err, "GetLocalUserCloudroles")
}
if len(roles) > 0 {
return &roles[0], nil
}
user, err := db.UserCacheManager.FetchById(userId)
if err != nil {
return nil, errors.Wrapf(err, "UserCacheManager.FetchById(%s)", userId)
}
role := &SCloudrole{}
role.SetModelManager(CloudroleManager, role)
role.CloudaccountId = self.Id
role.OwnerId = userId
role.SAMLProviderId = spId
role.Name = user.GetName()
role.Status = api.CLOUD_ROLE_STATUS_CREATING
role.DomainId = self.DomainId
return role, CloudroleManager.TableSpec().Insert(context.TODO(), role)
}
func (self *SCloudaccount) GetCloudrole(userId string) (*SCloudrole, error) {
sp, valid := self.IsSAMLProviderValid()
if !valid {
return nil, fmt.Errorf("SAMLProvider for account %s not ready", self.Id)
}
return self.RegisterCloudrole(userId, sp.Id)
}
func (self *SCloudaccount) SyncRole(userId string) (*SCloudrole, error) {
role, err := self.GetCloudrole(userId)
if err != nil {
return nil, errors.Wrapf(err, "GetCloudrole")
}
err = role.SyncRoles()
if err != nil {
return nil, errors.Wrapf(err, "SyncRoles")
}
return role, nil
}
func (self *SCloudaccount) GetCloudroles() ([]SCloudrole, error) {
roles := []SCloudrole{}
q := CloudroleManager.Query()
err := db.FetchModelObjects(CloudroleManager, q, &roles)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return roles, nil
}
func (self *SCloudaccount) newCloudrole(ctx context.Context, userCred mcclient.TokenCredential, iRole cloudprovider.ICloudrole) error {
role := &SCloudrole{}
role.SetModelManager(CloudroleManager, role)
role.Name = iRole.GetName()
role.ExternalId = iRole.GetGlobalId()
role.Document = iRole.GetDocument()
if spId := iRole.GetSAMLProvider(); len(spId) > 0 {
sp, _ := db.FetchByExternalIdAndManagerId(SAMLProviderManager, spId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("cloudaccount_id", self.Id)
})
if sp != nil {
role.SAMLProviderId = sp.GetId()
}
}
role.CloudaccountId = self.Id
role.Status = api.CLOUD_ROLE_STATUS_AVAILABLE
return CloudroleManager.TableSpec().Insert(ctx, role)
}
func (self *SCloudaccount) SyncCloudroles(ctx context.Context, userCred mcclient.TokenCredential, exts []cloudprovider.ICloudrole) compare.SyncResult {
result := compare.SyncResult{}
roles, err := self.GetCloudroles()
if err != nil {
result.Error(errors.Wrapf(err, "GetCloudroles"))
return result
}
removed := make([]SCloudrole, 0)
commondb := make([]SCloudrole, 0)
commonext := make([]cloudprovider.ICloudrole, 0)
added := make([]cloudprovider.ICloudrole, 0)
err = compare.CompareSets(roles, exts, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrapf(err, "compare.CompareSets"))
return result
}
for i := 0; i < len(removed); i++ {
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i++ {
err = commondb[i].syncWithCloudrole(ctx, userCred, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i++ {
err := self.newCloudrole(ctx, userCred, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SCloudaccount) GetUserCloudgroups(userId string) ([]string, error) {
ret := []string{}
q := CloudgroupManager.Query()
samlusers := SamluserManager.Query("cloudgroup_id").Equals("owner_id", userId).Equals("cloudaccount_id", self.Id).SubQuery()
q = q.In("id", samlusers)
groups := []SCloudgroup{}
err := db.FetchModelObjects(CloudgroupManager, q, &groups)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
if len(groups) == 0 {
return ret, nil
}
for i := range groups {
cache, err := CloudgroupcacheManager.Register(&groups[i], self)
if err != nil {
return []string{}, errors.Wrapf(err, "group cache Register")
}
if len(cache.ExternalId) > 0 {
ret = append(ret, cache.Name)
} else {
s := auth.GetAdminSession(context.TODO(), options.Options.Region, "")
_, err = cache.GetOrCreateICloudgroup(context.TODO(), s.GetToken())
if err != nil {
return []string{}, errors.Wrapf(err, "GetOrCreateICloudgroup")
}
cache, err := CloudgroupcacheManager.Register(&groups[i], self)
if err != nil {
return []string{}, errors.Wrapf(err, "group cache Register")
}
ret = append(ret, cache.Name)
}
}
return ret, nil
}
+28
View File
@@ -255,9 +255,37 @@ func (self *SCloudgroup) RealDelete(ctx context.Context, userCred mcclient.Token
if err != nil {
return errors.Wrap(err, "remoteUsers")
}
err = self.removeSamlusers()
if err != nil {
return errors.Wrapf(err, "removeSamlusers")
}
return self.SStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SCloudgroup) GetSamlusers() ([]SSamluser, error) {
q := SamluserManager.Query().Equals("cloudgroup_id", self.Id)
users := []SSamluser{}
err := db.FetchModelObjects(SamluserManager, q, &users)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return users, nil
}
func (self *SCloudgroup) removeSamlusers() error {
users, err := self.GetSamlusers()
if err != nil {
return errors.Wrap(err, "GetSamlusers")
}
for i := range users {
err = users[i].Delete(context.TODO(), nil)
if err != nil {
return errors.Wrapf(err, "rm saml user(%s)", users[i].Id)
}
}
return nil
}
func (self *SCloudgroup) removeUsers() error {
users, err := self.GetCloudusers()
if err != nil {
+1
View File
@@ -283,6 +283,7 @@ func (self *SCloudgroupcache) GetOrCreateICloudgroup(ctx context.Context, userCr
return nil, errors.Wrap(err, "CreateICloudgroup")
}
_, err = db.Update(self, func() error {
self.Name = groupName
self.ExternalId = iGroup.GetGlobalId()
self.Status = api.CLOUD_GROUP_CACHE_STATUS_AVAILABLE
return nil
+90
View File
@@ -0,0 +1,90 @@
// 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 models
import (
"context"
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/reflectutils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SCloudgroupResourceBaseManager struct {
}
type SCloudgroupResourceBase struct {
CloudgroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
}
func (self *SCloudgroupJointsBase) GetCloudgroup() (*SCloudgroup, error) {
group, err := CloudgroupManager.FetchById(self.CloudgroupId)
if err != nil {
return nil, errors.Wrap(err, "FetchById")
}
return group.(*SCloudgroup), nil
}
func (manager *SCloudgroupResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, groupCred mcclient.TokenCredential, query api.CloudgroupResourceListInput) (*sqlchemy.SQuery, error) {
if len(query.CloudgroupId) > 0 {
group, err := CloudgroupManager.FetchByIdOrName(nil, query.CloudgroupId)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("cloudgroup", query.CloudgroupId)
}
return nil, httperrors.NewGeneralError(err)
}
q = q.Equals("cloudgroup_id", group.GetId())
}
return q, nil
}
func (manager *SCloudgroupResourceBaseManager) FetchCustomizeColumns(
ctx context.Context,
groupCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.CloudgroupResourceDetails {
rows := make([]api.CloudgroupResourceDetails, len(objs))
groupIds := make([]string, len(objs))
for i := range objs {
var base *SCloudgroupResourceBase
err := reflectutils.FindAnonymouStructPointer(objs[i], &base)
if err != nil {
log.Errorf("Cannot find SCloudgroupResourceBase in %#v: %s", objs[i], err)
} else if base != nil && len(base.CloudgroupId) > 0 {
groupIds[i] = base.CloudgroupId
}
}
groupMaps, err := db.FetchIdNameMap2(CloudgroupManager, groupIds)
if err != nil {
return rows
}
for i := range rows {
rows[i].Cloudgroup, _ = groupMaps[groupIds[i]]
}
return rows
}
+261
View File
@@ -0,0 +1,261 @@
// 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 models
import (
"context"
"fmt"
"strconv"
"strings"
"gopkg.in/fatih/set.v0"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SCloudroleManager struct {
db.SStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudaccountResourceBaseManager
SAMLProviderResourceBaseManager
}
var CloudroleManager *SCloudroleManager
func init() {
CloudroleManager = &SCloudroleManager{
SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
SCloudrole{},
"cloudroles_tbl",
"cloudrole",
"cloudroles",
),
}
CloudroleManager.SetVirtualObject(CloudroleManager)
}
type SCloudrole struct {
db.SEnabledStatusInfrasResourceBase
db.SExternalizedResourceBase
SCloudaccountResourceBase
SAMLProviderResourceBase
Document *jsonutils.JSONDict `length:"long" charset:"ascii" list:"domain" update:"domain" create:"domain_required"`
OwnerId string `width:"128" charset:"ascii" index:"true" list:"user" nullable:"false" create:"optional"`
}
// 公有云角色列表
func (manager *SCloudroleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudroleListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, err
}
q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
if err != nil {
return nil, err
}
return q, nil
}
// 获取公有云角色详情
func (self *SCloudrole) GetExtraDetails(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
isList bool,
) (api.CloudroleDetails, error) {
return api.CloudroleDetails{}, nil
}
func (manager *SCloudroleManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.CloudroleDetails {
rows := make([]api.CloudroleDetails, len(objs))
infRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.CloudroleDetails{
StatusInfrasResourceBaseDetails: infRows[i],
CloudaccountResourceDetails: acRows[i],
}
}
return rows
}
// 删除公有云角色
func (self *SCloudrole) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartCloudroleDeleteTask(ctx, userCred, false, "")
}
func (self *SCloudrole) StartCloudroleDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, purge bool, parentTaskId string) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewBool(purge), "purge")
task, err := taskman.TaskManager.NewTask(ctx, "CloudroleDeleteTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.CLOUD_ROLE_STATUS_DELETING, "")
task.ScheduleRun(nil)
return nil
}
func (self *SCloudrole) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowPerform(userCred, self, "purge")
}
// 清除角色(不删除云上资源)
func (self *SCloudrole) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudrolePurgeInput) (jsonutils.JSONObject, error) {
return nil, self.StartCloudroleDeleteTask(ctx, userCred, true, "")
}
func (self *SCloudrole) GetICloudrole() (cloudprovider.ICloudrole, error) {
account, err := self.GetCloudaccount()
if err != nil {
return nil, errors.Wrapf(err, "GetCloudaccount")
}
provider, err := account.GetProvider()
if err != nil {
return nil, errors.Wrapf(err, "GetProvider")
}
if len(self.ExternalId) > 0 {
iRole, err := provider.GetICloudroleById(self.ExternalId)
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, errors.Wrapf(err, "GetICloudroleById(%s)", self.ExternalId)
}
if err == nil {
return iRole, nil
}
}
sp, err := self.GetSAMLProvider()
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProvider")
}
for i := 0; i < 10; i++ {
_, err := provider.GetICloudroleByName(self.Name)
if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound {
break
}
info := strings.Split(self.Name, "-")
num, err := strconv.Atoi(info[len(info)-1])
if err != nil {
info = append(info, "1")
} else {
info[len(info)-1] = fmt.Sprintf("%d", num+1)
}
self.Name = strings.Join(info, "-")
}
opts := &cloudprovider.SRoleCreateOptions{
Name: self.Name,
Desc: self.Description,
SAMLProvider: sp.ExternalId,
}
iRole, err := provider.CreateICloudrole(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateICloudrole")
}
db.Update(self, func() error {
self.ExternalId = iRole.GetGlobalId()
self.Name = iRole.GetName()
self.Document = iRole.GetDocument()
self.Status = api.CLOUD_ROLE_STATUS_AVAILABLE
return nil
})
return iRole, nil
}
func (self *SCloudrole) GetCloudpolicies() ([]SCloudpolicy, error) {
q := CloudpolicyManager.Query()
samlUsers := SamluserManager.Query("cloudgroup_id").Equals("owner_id", self.OwnerId).Equals("cloudaccount_id", self.CloudaccountId).SubQuery()
groups := CloudgroupManager.Query("id").In("id", samlUsers)
gp := CloudgroupPolicyManager.Query("cloudpolicy_id").In("cloudgroup_id", groups).SubQuery()
q = q.In("id", gp)
policies := []SCloudpolicy{}
err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return policies, nil
}
func (self *SCloudrole) SyncRoles() error {
iRole, err := self.GetICloudrole()
if err != nil {
return errors.Wrapf(err, "GetICloudrole")
}
policies, err := self.GetCloudpolicies()
if err != nil {
return errors.Wrapf(err, "GetICloudpolicies")
}
local := set.New(set.ThreadSafe)
for i := range policies {
if policies[i].PolicyType == api.CLOUD_POLICY_TYPE_SYSTEM {
local.Add(policies[i].ExternalId)
} else {
}
}
iPolicies, err := iRole.GetICloudpolicies()
if err != nil {
return errors.Wrapf(err, "GetICloudpolicies")
}
remote := set.New(set.ThreadSafe)
for i := range iPolicies {
remote.Add(iPolicies[i].GetGlobalId())
}
for _, id := range set.Difference(remote, local).List() {
err = iRole.DetachPolicy(id.(string))
if err != nil {
return errors.Wrapf(err, "DetachPolicy(%s)", id)
}
}
for _, id := range set.Difference(local, remote).List() {
err = iRole.AttachPolicy(id.(string))
if err != nil {
return errors.Wrapf(err, "AttachPolicy(%s)", id)
}
}
return nil
}
func (self *SCloudrole) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SCloudrole) syncWithCloudrole(ctx context.Context, userCred mcclient.TokenCredential, iRole cloudprovider.ICloudrole) error {
_, err := db.Update(self, func() error {
self.Name = self.GetName()
self.Document = iRole.GetDocument()
self.Status = api.CLOUD_ROLE_STATUS_AVAILABLE
return nil
})
return err
}
+212
View File
@@ -0,0 +1,212 @@
// 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 models
import (
"context"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudid/options"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SSAMLProviderManager struct {
db.SStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudaccountResourceBaseManager
}
var SAMLProviderManager *SSAMLProviderManager
func init() {
SAMLProviderManager = &SSAMLProviderManager{
SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
SSAMLProvider{},
"saml_provider_tbl",
"saml_provider",
"saml_providers",
),
}
SAMLProviderManager.SetVirtualObject(SAMLProviderManager)
}
type SSAMLProvider struct {
db.SStatusInfrasResourceBase
db.SExternalizedResourceBase
SCloudaccountResourceBase
EntityId string `get:"domain" create:"domain_optional" list:"domain"`
MetadataDocument string `get:"domain" create:"domain_optional"`
AuthUrl string `width:"512" charset:"ascii" get:"domain" list:"domain"`
}
func (manager *SSAMLProviderManager) GetIVirtualModelManager() db.IVirtualModelManager {
return manager.GetVirtualObject().(db.IVirtualModelManager)
}
func (manager *SSAMLProviderManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
return nil, nil
}
func (manager *SSAMLProviderManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
accountId, _ := data.GetString("cloudaccount_id")
return jsonutils.Marshal(map[string]string{"cloudaccount_id": accountId})
}
func (manager *SSAMLProviderManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
accountId, _ := values.GetString("cloudaccount_id")
if len(accountId) > 0 {
q = q.Equals("cloudaccount_id", accountId)
}
return q
}
// 创建云账号的身份提供商
func (manager *SSAMLProviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.SAMLProviderCreateInput) (api.SAMLProviderCreateInput, error) {
if len(input.CloudaccountId) == 0 {
return input, httperrors.NewMissingParameterError("cloudaccount_id")
}
_, err := validators.ValidateModel(userCred, CloudaccountManager, &input.CloudaccountId)
if err != nil {
return input, err
}
input.EntityId = options.Options.ApiServer
if len(input.EntityId) == 0 {
return input, httperrors.NewResourceNotReadyError("not set api_server")
}
input.Name = strings.TrimPrefix(input.EntityId, "https://")
input.Name = strings.TrimPrefix(input.Name, "http://")
input.MetadataDocument = SamlIdpInstance().GetMetadata(input.CloudaccountId).String()
input.StatusInfrasResourceBaseCreateInput, err = manager.SStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusInfrasResourceBaseCreateInput)
if err != nil {
return input, err
}
return input, nil
}
func (self *SSAMLProvider) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.StartSAMLProviderCreateTask(ctx, userCred, "")
}
// 公有云身份提供商列表
func (manager *SSAMLProviderManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SAMLProviderListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, err
}
q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
if err != nil {
return nil, err
}
return q, nil
}
// 删除
func (self *SSAMLProvider) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
params := jsonutils.NewDict()
return self.StartSAMLProviderDeleteTask(ctx, userCred, params, "")
}
func (self *SSAMLProvider) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SSAMLProvider) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SSAMLProvider) StartSAMLProviderDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "SAMLProviderDeleteTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.SAML_PROVIDER_STATUS_DELETING, "")
task.ScheduleRun(nil)
return nil
}
func (self *SSAMLProvider) StartSAMLProviderCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "SAMLProviderCreateTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.SAML_PROVIDER_STATUS_CREATING, "")
task.ScheduleRun(nil)
return nil
}
func (self *SSAMLProvider) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.RealDelete(ctx, userCred)
}
func (self *SSAMLProvider) SyncWithCloudSAMLProvider(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSAMLProvider) error {
_, err := db.Update(self, func() error {
self.ExternalId = ext.GetGlobalId()
self.AuthUrl = ext.GetAuthUrl()
self.Status = ext.GetStatus()
metadata, err := ext.GetMetadataDocument()
if err != nil {
log.Errorf("failed to get metadata for %s error: %v", self.Name, err)
}
if metadata != nil {
self.EntityId = metadata.EntityId
self.MetadataDocument = metadata.String()
}
if self.EntityId != options.Options.ApiServer {
self.Status = api.SAML_PROVIDER_STATUS_NOT_MATCH
}
return nil
})
return err
}
func (self *SSAMLProvider) GetMetadataDocument() (samlutils.EntityDescriptor, error) {
return samlutils.ParseMetadata([]byte(self.MetadataDocument))
}
func (manager *SSAMLProviderManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.SAMLProviderDetails {
rows := make([]api.SAMLProviderDetails, len(objs))
infRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.SAMLProviderDetails{
StatusInfrasResourceBaseDetails: infRows[i],
CloudaccountResourceDetails: acRows[i],
}
}
return rows
}
+58
View File
@@ -0,0 +1,58 @@
// 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 models
import (
"context"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
type SamlInstance func() *idp.SSAMLIdpInstance
var (
SamlIdpInstance SamlInstance = nil
)
type ICloudSAMLLoginDriver interface {
GetEntityID() string
GetMetadataFilename() string
GetMetadataUrl() string
GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error)
GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccoutId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error)
}
var (
driverTable = make(map[string]ICloudSAMLLoginDriver)
)
func Register(driver ICloudSAMLLoginDriver) {
driverTable[driver.GetEntityID()] = driver
}
func FindDriver(entityId string) ICloudSAMLLoginDriver {
if driver, ok := driverTable[entityId]; ok {
return driver
}
return nil
}
func AllDrivers() map[string]ICloudSAMLLoginDriver {
return driverTable
}
@@ -0,0 +1,32 @@
// 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 models
import "yunion.io/x/pkg/errors"
type SAMLProviderResourceBaseManager struct {
}
type SAMLProviderResourceBase struct {
SAMLProviderId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" json:"saml_provider_id"`
}
func (self *SAMLProviderResourceBase) GetSAMLProvider() (*SSAMLProvider, error) {
sp, err := SAMLProviderManager.FetchById(self.SAMLProviderId)
if err != nil {
return nil, errors.Wrap(err, "SAMLProviderManager.FetchById")
}
return sp.(*SSAMLProvider), nil
}
+172
View File
@@ -0,0 +1,172 @@
// 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 models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SSamluserManager struct {
db.SStatusDomainLevelUserResourceBaseManager
SCloudgroupResourceBaseManager
SCloudaccountResourceBaseManager
}
var SamluserManager *SSamluserManager
func init() {
SamluserManager = &SSamluserManager{
SStatusDomainLevelUserResourceBaseManager: db.NewStatusDomainLevelUserResourceBaseManager(
SSamluser{},
"samlusers_tbl",
"samluser",
"samlusers",
),
}
SamluserManager.SetVirtualObject(SamluserManager)
}
type SSamluser struct {
db.SStatusDomainLevelUserResourceBase
SCloudgroupResourceBase
SCloudaccountResourceBase
}
func (manager *SSamluserManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
q := manager.Query()
domainCnt, err := db.CalculateResourceCount(q, "domain_id")
if err != nil {
return nil, errors.Wrap(err, "CalculateResourceCount.domain_id")
}
q = manager.Query()
userCnt, err := db.CalculateResourceCount(q, "owner_id")
if err != nil {
return nil, errors.Wrap(err, "CalculateResourceCount.owner_id")
}
return append(domainCnt, userCnt...), nil
}
func (manager *SSamluserManager) GetIVirtualModelManager() db.IVirtualModelManager {
return manager.GetVirtualObject().(db.IVirtualModelManager)
}
func (manager *SSamluserManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
groupId, _ := data.GetString("cloudgroup_id")
accountId, _ := data.GetString("cloudaccount_id")
return jsonutils.Marshal(map[string]string{"cloudgroup_id": groupId, "cloudaccount_id": accountId})
}
func (manager *SSamluserManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
groupId, _ := values.GetString("cloudgroup_id")
accountId, _ := values.GetString("cloudaccount_id")
if len(groupId) > 0 {
q = q.Equals("cloudgroup_id", groupId)
}
if len(accountId) > 0 {
q = q.Equals("cloudaccount_id", accountId)
}
return q
}
// SAML认证用户列表
func (manager *SSamluserManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SamluserListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusDomainLevelUserResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusDomainLevelUserResourceListInput)
if err != nil {
return nil, err
}
q, err = manager.SCloudgroupResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudgroupResourceListInput)
if err != nil {
return nil, err
}
q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
if err != nil {
return nil, err
}
return q, nil
}
// 创建SAML认证用户
func (manager *SSamluserManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.SamluserCreateInput) (api.SamluserCreateInput, error) {
if len(input.OwnerId) > 0 {
user, err := db.UserCacheManager.FetchUserById(ctx, input.OwnerId)
if err != nil {
return input, errors.Wrapf(err, "FetchUserById")
}
input.OwnerId = user.Id
input.Name = user.Name
} else {
input.OwnerId = userCred.GetUserId()
input.Name = userCred.GetUserName()
}
_group, err := validators.ValidateModel(userCred, CloudgroupManager, &input.CloudgroupId)
if err != nil {
return input, err
}
group := _group.(*SCloudgroup)
sq := CloudgroupManager.Query("id").Equals("provider", group.Provider).SubQuery()
q := manager.Query().Equals("owner_id", input.OwnerId).In("cloudgroup_id", sq)
groups := []SCloudgroup{}
err = db.FetchModelObjects(CloudgroupManager, q, &groups)
if err != nil {
return input, httperrors.NewGeneralError(errors.Wrapf(err, "db.FetchModelObjects"))
}
if len(groups) > 0 {
return input, httperrors.NewConflictError("user %s has already in other %s group", input.Name, group.Provider)
}
_account, err := validators.ValidateModel(userCred, CloudaccountManager, &input.CloudaccountId)
if err != nil {
return input, err
}
account := _account.(*SCloudaccount)
if account.Provider != group.Provider {
return input, httperrors.NewConflictError("account %s and group %s not with same provider %s", account.Name, group.Name)
}
input.Status = api.SAML_USER_STATUS_AVAILABLE
return input, nil
}
func (manager *SSamluserManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.SamluserDetails {
rows := make([]api.SamluserDetails, len(objs))
userRows := manager.SStatusDomainLevelUserResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
groupRows := manager.SCloudgroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.SamluserDetails{
StatusDomainLevelUserResourceDetails: userRows[i],
CloudgroupResourceDetails: groupRows[i],
CloudaccountResourceDetails: acRows[i],
}
}
return rows
}
+2
View File
@@ -23,8 +23,10 @@ type SCloudIdOptions struct {
common_options.DBOptions
CloudaccountSyncIntervalMinutes int `help:"frequency to sync region cloudaccount task" default:"3"`
SAMLProviderSyncIntervalHours int `help:"frequency to sync account saml provider task" default:"3"`
SystemPoliciesSyncIntervalHours int `help:"frequency to sync region cloudaccount task" default:"24"`
CloudIdResourceSyncIntervalHours int `help:"frequency to sync region cloudpolicy task" default:"3"`
CloudroleSyncIntervalHours int `help:"frequency to sync region cloudroles task" default:"12"`
CloudSAMLMetadataPath string `help:"path to store SAML sp metadata file of cloud providers" default:"/opt/yunion/share/saml/sp-metadata"`
}
+106
View File
@@ -13,3 +13,109 @@
// limitations under the License.
package saml // import "yunion.io/x/onecloud/pkg/cloudid/saml"
/*
+-----------------+ +----------------+
| CloudId Service | | Region Service |
+-----------------+ +----------------+
+----------+
|EnableSaml|
+-------------------+ +------------+ +----------+
| Cloudaccount | |Cloudaccount|
| (enabled|disable) | +------------+ +-----------+
+----________-------+ |DisableSaml|
_______/ \_______ +-----------+
___/ \____
+--------------+ +--------------+
| SamlProvider | | SamlProvider |
| (available) | | (not match) |
+--------------+ +--------------+
Saml Check CronJob Task
+-------+
| Start |
+---|---+
|
|
v
+------------------------+ Yes +----------------------------------------+ No +---------------------+
| Is account enable saml | ----------------> | Is account has available saml provider |----------------> | Create saml provider|
+------------------------+ +----------------------------------------+ +---------------------+
| | |
| No | Yes |
| | |
v | |
+------+ | |
| End | <-----------------------------------------------<----------------------------------------------------
+------+
Saml Auth Login
+-------+
| Start |
+-------+
|
|
v
+-----------------------+ Yes +-----------------------------------------------+
|Is account enable saml |-------------> |Prepare tmp Role and set expired time for user |
+-----------------------+ +-----------------------------------------------+
| No |
| |
| |
| v
| +------------------+
| | Auth for console |
| +------------------+
| |
| |
v |
+------+ |
| End |<----------------------------------------------
+------+
*/
+6
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudid/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/util/samlutils"
@@ -55,6 +56,7 @@ func initSAMLInstance() error {
return errors.Wrap(err, "samlutils.NewSAMLInstance")
}
models.SamlIdpInstance = SAMLIdpInstance
return nil
}
@@ -65,6 +67,10 @@ func SAMLInstance() *samlutils.SSAMLInstance {
return saml
}
func SAMLIdpInstance() *idp.SSAMLIdpInstance {
return idpInstance
}
func IsSAMLEnabled() bool {
return saml != nil
}
+6 -6
View File
@@ -24,8 +24,8 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudid/options"
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/httputils"
@@ -38,11 +38,11 @@ func initSAMLIdp(app *appsrv.Application, prefix string) error {
token := auth.FetchUserCredential(ctx, nil)
log.Debugf("Recive SP initiated Login: %s", sp.GetEntityId())
data := samlutils.SSAMLSpInitiatedLoginData{}
driver := providers.FindDriver(sp.GetEntityId())
driver := models.FindDriver(sp.GetEntityId())
if driver == nil {
return data, errors.Wrapf(httperrors.ErrResourceNotFound, "entityID %s not found", sp.GetEntityId())
}
data, err := driver.GetSpInitiatedLoginData(idpId, token.GetUserId(), sp)
data, err := driver.GetSpInitiatedLoginData(ctx, token, idpId, sp)
if err != nil {
return data, errors.Wrap(err, "driver.GetSpInitiatedLoginData")
}
@@ -62,11 +62,11 @@ func initSAMLIdp(app *appsrv.Application, prefix string) error {
token := auth.FetchUserCredential(ctx, nil)
log.Debugf("Recive IDP initiated Login: %s", sp.GetEntityId())
data := samlutils.SSAMLIdpInitiatedLoginData{}
driver := providers.FindDriver(sp.GetEntityId())
driver := models.FindDriver(sp.GetEntityId())
if driver == nil {
return data, errors.Wrapf(httperrors.ErrResourceNotFound, "entityID %s not found", sp.GetEntityId())
}
data, err := driver.GetIdpInitiatedLoginData(idpId, token.GetUserId(), sp)
data, err := driver.GetIdpInitiatedLoginData(ctx, token, idpId, sp)
if err != nil {
return data, errors.Wrap(err, "driver.GetIdpInitiatedLoginData")
}
@@ -78,7 +78,7 @@ func initSAMLIdp(app *appsrv.Application, prefix string) error {
}
idpInst := idp.NewIdpInstance(saml, spFunc, idpFunc, logoutFunc)
for entityId, drvFactory := range providers.AllDrivers() {
for entityId, drvFactory := range models.AllDrivers() {
filePath := path.Join(options.Options.CloudSAMLMetadataPath, drvFactory.GetMetadataFilename())
metaBytes, err := ioutil.ReadFile(filePath)
if err != nil || len(metaBytes) == 0 {
+5 -2
View File
@@ -15,13 +15,16 @@
package aliyun
import (
"context"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SAliyunSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
func (d *SAliyunSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// TODO
data := samlutils.SSAMLIdpInitiatedLoginData{}
data.NameId = "ecsossreadonly"
@@ -41,7 +44,7 @@ func (d *SAliyunSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userI
return data, nil
}
func (d *SAliyunSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
func (d *SAliyunSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// not supported
return samlutils.SSAMLSpInitiatedLoginData{}, errors.ErrNotSupported
}
+2 -2
View File
@@ -15,7 +15,7 @@
package aliyun
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SAliyunSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SAliyunSAMLDriver{})
models.Register(&SAliyunSAMLDriver{})
}
+39 -7
View File
@@ -15,17 +15,49 @@
package aws
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SAWSSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// TODO
func (d *SAWSSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
data := samlutils.SSAMLIdpInitiatedLoginData{}
data.NameId = "ec2s3readonly"
_account, err := models.CloudaccountManager.FetchById(cloudAccountId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return data, httperrors.NewResourceNotFoundError("cloudaccount", cloudAccountId)
}
return data, httperrors.NewGeneralError(err)
}
account := _account.(*models.SCloudaccount)
if account.Provider != api.CLOUD_PROVIDER_AWS {
return data, httperrors.NewClientError("cloudaccount %s is %s not %s", account.Id, account.Provider, api.CLOUD_PROVIDER_AWS)
}
if account.SAMLAuth.IsFalse() {
return data, httperrors.NewNotSupportedError("cloudaccount %s not open saml auth", account.Id)
}
SAMLProvider, valid := account.IsSAMLProviderValid()
if !valid {
return data, httperrors.NewResourceNotReadyError("SAMLProvider for account %s not ready", account.Id)
}
role, err := account.SyncRole(userCred.GetUserId())
if err != nil {
return data, httperrors.NewGeneralError(errors.Wrapf(err, "SyncRole"))
}
data.NameId = userCred.GetUserName()
data.NameIdFormat = samlutils.NAME_ID_FORMAT_PERSISTENT
data.AudienceRestriction = "https://signin.aws.amazon.com/saml"
for _, v := range []struct {
@@ -36,17 +68,17 @@ func (d *SAWSSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId s
{
name: "https://aws.amazon.com/SAML/Attributes/Role",
friendlyName: "RoleEntitlement",
value: "arn:aws:iam::285906155448:role/ec2s3readonly,arn:aws:iam::285906155448:saml-provider/saml.yunion.cn",
value: fmt.Sprintf("%s,%s", role.ExternalId, SAMLProvider.ExternalId),
},
{
name: "https://aws.amazon.com/SAML/Attributes/RoleSessionName",
friendlyName: "RoleSessionName",
value: "ec2s3readonly",
value: userCred.GetUserId(),
},
{
name: "urn:oid:1.3.6.1.4.1.5923.1.1.1.3",
friendlyName: "eduPersonOrgDN",
value: "ec2s3readonly",
value: userCred.GetUserName(),
},
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
@@ -60,7 +92,7 @@ func (d *SAWSSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId s
return data, nil
}
func (d *SAWSSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
func (d *SAWSSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// not supported
return samlutils.SSAMLSpInitiatedLoginData{}, errors.ErrNotSupported
}
+2 -2
View File
@@ -15,7 +15,7 @@
package aws
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SAWSSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SAWSSAMLDriver{})
models.Register(&SAWSSAMLDriver{})
}
+38 -7
View File
@@ -15,17 +15,48 @@
package awscn
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SAWSCNSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// TODO
func (d *SAWSCNSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
data := samlutils.SSAMLIdpInitiatedLoginData{}
_account, err := models.CloudaccountManager.FetchById(cloudAccountId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return data, httperrors.NewResourceNotFoundError("cloudaccount", cloudAccountId)
}
return data, httperrors.NewGeneralError(err)
}
account := _account.(*models.SCloudaccount)
if account.Provider != api.CLOUD_PROVIDER_AWS {
return data, httperrors.NewClientError("cloudaccount %s is %s not %s", account.Id, account.Provider, api.CLOUD_PROVIDER_AWS)
}
if account.SAMLAuth.IsFalse() {
return data, httperrors.NewNotSupportedError("cloudaccount %s not open saml auth", account.Id)
}
data.NameId = "ec2s3readonly"
SAMLProvider, valid := account.IsSAMLProviderValid()
if !valid {
return data, httperrors.NewResourceNotReadyError("SAMLProvider for account %s not ready", account.Id)
}
role, err := account.SyncRole(userCred.GetUserId())
if err != nil {
return data, httperrors.NewGeneralError(errors.Wrapf(err, "SyncRole"))
}
data.NameId = userCred.GetUserName()
data.NameIdFormat = samlutils.NAME_ID_FORMAT_PERSISTENT
data.AudienceRestriction = "https://signin.amazonaws.cn/saml"
for _, v := range []struct {
@@ -36,17 +67,17 @@ func (d *SAWSCNSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId
{
name: "https://aws.amazon.com/SAML/Attributes/Role",
friendlyName: "RoleEntitlement",
value: "arn:aws-cn:iam::248697896586:role/ec2s3readonly,arn:aws-cn:iam::248697896586:saml-provider/saml.yunion.io",
value: fmt.Sprintf("%s,%s", role.ExternalId, SAMLProvider.ExternalId),
},
{
name: "https://aws.amazon.com/SAML/Attributes/RoleSessionName",
friendlyName: "RoleSessionName",
value: "ec2s3readonly",
value: userCred.GetUserId(),
},
{
name: "urn:oid:1.3.6.1.4.1.5923.1.1.1.3",
friendlyName: "eduPersonOrgDN",
value: "ec2s3readonly",
value: userCred.GetUserName(),
},
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
@@ -60,7 +91,7 @@ func (d *SAWSCNSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId
return data, nil
}
func (d *SAWSCNSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
func (d *SAWSCNSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// not supported
return samlutils.SSAMLSpInitiatedLoginData{}, errors.ErrNotSupported
}
+2 -2
View File
@@ -15,7 +15,7 @@
package awscn
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SAWSCNSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SAWSCNSAMLDriver{})
models.Register(&SAWSCNSAMLDriver{})
}
+5 -2
View File
@@ -15,19 +15,22 @@
package google
import (
"context"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SGoogleSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
func (d *SGoogleSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// not supported
data := samlutils.SSAMLIdpInitiatedLoginData{}
return data, httperrors.ErrNotSupported
}
func (d *SGoogleSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
func (d *SGoogleSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// TODO
data := samlutils.SSAMLSpInitiatedLoginData{}
+2 -2
View File
@@ -15,7 +15,7 @@
package google
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SGoogleSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SGoogleSAMLDriver{})
models.Register(&SGoogleSAMLDriver{})
}
+43 -8
View File
@@ -15,33 +15,68 @@
package huawei
import (
"context"
"database/sql"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SHuaweiSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
func (d *SHuaweiSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// not supported
data := samlutils.SSAMLIdpInitiatedLoginData{}
return data, httperrors.ErrNotSupported
}
func (d *SHuaweiSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// TODO
func (d *SHuaweiSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
data := samlutils.SSAMLSpInitiatedLoginData{}
data.NameId = "yunionoss"
_account, err := models.CloudaccountManager.FetchById(cloudAccountId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return data, httperrors.NewResourceNotFoundError("cloudaccount", cloudAccountId)
}
return data, httperrors.NewGeneralError(err)
}
account := _account.(*models.SCloudaccount)
if account.Provider != api.CLOUD_PROVIDER_HUAWEI {
return data, httperrors.NewClientError("cloudaccount %s is %s not %s", account.Id, account.Provider, api.CLOUD_PROVIDER_HUAWEI)
}
if account.SAMLAuth.IsFalse() {
return data, httperrors.NewNotSupportedError("cloudaccount %s not open saml auth", account.Id)
}
_, valid := account.IsSAMLProviderValid()
if !valid {
return data, httperrors.NewResourceNotReadyError("SAMLProvider for account %s not ready", account.Id)
}
groups, err := account.GetUserCloudgroups(userCred.GetUserId())
if err != nil {
return data, httperrors.NewGeneralError(errors.Wrapf(err, "GetUserCloudgroups"))
}
if len(groups) == 0 {
return data, httperrors.NewResourceNotFoundError("no available group found")
}
data.NameId = userCred.GetUserName()
data.NameIdFormat = samlutils.NAME_ID_FORMAT_TRANSIENT
data.AudienceRestriction = sp.GetEntityId()
for k, v := range map[string]string{
"User": "ec2admin",
"Group": "ec2admin",
for k, v := range map[string][]string{
"User": []string{userCred.GetUserName()},
"Groups": groups,
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
Name: k, FriendlyName: k,
NameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
Values: []string{v},
Values: v,
})
}
+2 -2
View File
@@ -15,7 +15,7 @@
package huawei
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SHuaweiSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SHuaweiSAMLDriver{})
models.Register(&SHuaweiSAMLDriver{})
}
+71 -10
View File
@@ -15,15 +15,51 @@
package qcloud
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SQcloudSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
// TODO
func (d *SQcloudSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error) {
data := samlutils.SSAMLIdpInitiatedLoginData{}
data.NameId = "cvmcosreadonly"
_account, err := models.CloudaccountManager.FetchById(cloudAccountId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return data, httperrors.NewResourceNotFoundError("cloudaccount", cloudAccountId)
}
return data, httperrors.NewGeneralError(err)
}
account := _account.(*models.SCloudaccount)
if account.Provider != api.CLOUD_PROVIDER_QCLOUD {
return data, httperrors.NewClientError("cloudaccount %s is %s not %s", account.Id, account.Provider, api.CLOUD_PROVIDER_QCLOUD)
}
if account.SAMLAuth.IsFalse() {
return data, httperrors.NewNotSupportedError("cloudaccount %s not open saml auth", account.Id)
}
SAMLProvider, valid := account.IsSAMLProviderValid()
if !valid {
return data, httperrors.NewResourceNotReadyError("SAMLProvider for account %s not ready", account.Id)
}
role, err := account.SyncRole(userCred.GetUserId())
if err != nil {
return data, httperrors.NewGeneralError(errors.Wrapf(err, "SyncRole"))
}
roleStr := fmt.Sprintf("qcs::cam::uin/%s:roleName/%s,qcs::cam::uin/%s:saml-provider/%s", account.AccountId, role.ExternalId, account.AccountId, SAMLProvider.ExternalId)
data.NameId = role.Name
data.NameIdFormat = samlutils.NAME_ID_FORMAT_TRANSIENT
data.AudienceRestriction = "https://cloud.tencent.com"
for _, v := range []struct {
@@ -34,12 +70,12 @@ func (d *SQcloudSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userI
{
name: "https://cloud.tencent.com/SAML/Attributes/Role",
friendlyName: "RoleEntitlement",
value: "qcs::cam::uin/100008182714:roleName/cvmcosreadonly,qcs::cam::uin/100008182714:saml-provider/saml.yunion.io",
value: roleStr,
},
{
name: "https://cloud.tencent.com/SAML/Attributes/RoleSessionName",
friendlyName: "RoleSessionName",
value: "cvmcosreadonly",
value: role.Name,
},
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
@@ -53,11 +89,36 @@ func (d *SQcloudSAMLDriver) GetIdpInitiatedLoginData(cloudAccoutId string, userI
return data, nil
}
func (d *SQcloudSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
// not supported
func (d *SQcloudSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, cloudAccountId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
data := samlutils.SSAMLSpInitiatedLoginData{}
_account, err := models.CloudaccountManager.FetchById(cloudAccountId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return data, httperrors.NewResourceNotFoundError("cloudaccount", cloudAccountId)
}
return data, httperrors.NewGeneralError(err)
}
account := _account.(*models.SCloudaccount)
if account.Provider != api.CLOUD_PROVIDER_QCLOUD {
return data, httperrors.NewClientError("cloudaccount %s is %s not %s", account.Id, account.Provider, api.CLOUD_PROVIDER_QCLOUD)
}
if account.SAMLAuth.IsFalse() {
return data, httperrors.NewNotSupportedError("cloudaccount %s not open saml auth", account.Id)
}
data.NameId = "cvmcosreadonly"
SAMLProvider, valid := account.IsSAMLProviderValid()
if !valid {
return data, httperrors.NewResourceNotReadyError("SAMLProvider for account %s not ready", account.Id)
}
role, err := account.SyncRole(userCred.GetUserId())
if err != nil {
return data, httperrors.NewGeneralError(errors.Wrapf(err, "SyncRole"))
}
roleStr := fmt.Sprintf("qcs::cam::uin/%s:roleName/%s,qcs::cam::uin/%s:saml-provider/%s", account.AccountId, role.ExternalId, account.AccountId, SAMLProvider.ExternalId)
data.NameId = role.Name
data.NameIdFormat = samlutils.NAME_ID_FORMAT_TRANSIENT
data.AudienceRestriction = "https://cloud.tencent.com"
for _, v := range []struct {
@@ -68,12 +129,12 @@ func (d *SQcloudSAMLDriver) GetSpInitiatedLoginData(cloudAccoutId string, userId
{
name: "https://cloud.tencent.com/SAML/Attributes/Role",
friendlyName: "RoleEntitlement",
value: "qcs::cam::uin/100008182714:roleName/cvmcosreadonly,qcs::cam::uin/100008182714:saml-provider/saml.yunion.io",
value: roleStr,
},
{
name: "https://cloud.tencent.com/SAML/Attributes/RoleSessionName",
friendlyName: "RoleSessionName",
value: "cvmcosreadonly",
value: role.Name,
},
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
+2 -2
View File
@@ -15,7 +15,7 @@
package qcloud
import (
"yunion.io/x/onecloud/pkg/cloudid/saml/providers"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -34,5 +34,5 @@ func (d *SQcloudSAMLDriver) GetMetadataUrl() string {
}
func init() {
providers.Register(&SQcloudSAMLDriver{})
models.Register(&SQcloudSAMLDriver{})
}
+3
View File
@@ -65,6 +65,9 @@ func InitHandlers(app *appsrv.Application) {
models.CloudgroupcacheManager,
models.CloudpolicyManager,
models.CloudpolicycacheManager,
models.SAMLProviderManager,
models.CloudroleManager,
models.SamluserManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
+2
View File
@@ -61,8 +61,10 @@ func StartService() {
if !opts.IsSlaveNode {
cron := cronman.InitCronJobManager(true, options.Options.CronJobWorkerCount)
cron.AddJobAtIntervalsWithStartRun("SyncCloudaccounts", time.Duration(opts.CloudaccountSyncIntervalMinutes)*time.Minute, models.CloudaccountManager.SyncCloudaccounts, true)
cron.AddJobAtIntervalsWithStartRun("SyncSAMLProviders", time.Duration(opts.SAMLProviderSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncSAMLProviders, true)
cron.AddJobAtIntervalsWithStartRun("SyncSystemCloudpolicies", time.Duration(opts.SystemPoliciesSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncCloudidSystemPolicies, true)
cron.AddJobAtIntervalsWithStartRun("SyncCloudIdResources", time.Duration(opts.CloudIdResourceSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncCloudidResources, true)
cron.AddJobAtIntervalsWithStartRun("SyncCloudroles", time.Duration(opts.CloudroleSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncCloudroles, true)
cron.Start()
defer cron.Stop()
}
@@ -0,0 +1,82 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type CloudroleDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(CloudroleDeleteTask{})
}
func (self *CloudroleDeleteTask) taskFailed(ctx context.Context, role *models.SCloudrole, err error) {
role.SetStatus(self.GetUserCred(), api.CLOUD_ROLE_STATUS_DELETE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, role, logclient.ACT_DELETE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *CloudroleDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
role := obj.(*models.SCloudrole)
isPurge := jsonutils.QueryBoolean(self.Params, "purge", false)
if len(role.ExternalId) == 0 || isPurge {
role.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
return
}
account, err := role.GetCloudaccount()
if err != nil {
self.taskFailed(ctx, role, errors.Wrapf(err, "GetCloudaccount"))
return
}
provider, err := account.GetProvider()
if err != nil {
self.taskFailed(ctx, role, errors.Wrapf(err, "GetProvider"))
return
}
iRole, err := provider.GetICloudroleById(role.ExternalId)
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
role.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
return
}
self.taskFailed(ctx, role, errors.Wrapf(err, "GetICloudroleById(%s)", role.ExternalId))
return
}
err = iRole.Delete()
if err != nil {
self.taskFailed(ctx, role, errors.Wrapf(err, "iRole.Delete"))
return
}
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,92 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type SAMLProviderCreateTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(SAMLProviderCreateTask{})
}
func (self *SAMLProviderCreateTask) taskFailed(ctx context.Context, saml *models.SSAMLProvider, err error) {
saml.SetStatus(self.GetUserCred(), api.SAML_PROVIDER_STATUS_CREATE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, saml, logclient.ACT_CREATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *SAMLProviderCreateTask) taskComplete(ctx context.Context, saml *models.SSAMLProvider) {
self.SetStageComplete(ctx, nil)
}
func (self *SAMLProviderCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
saml := obj.(*models.SSAMLProvider)
metadata, err := saml.GetMetadataDocument()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "GetMetadataDocument"))
return
}
account, err := saml.GetCloudaccount()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "GetCloudaccount"))
return
}
provider, err := account.GetProvider()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrap(err, "GetProvider"))
return
}
opts := cloudprovider.SAMLProviderCreateOptions{
Name: saml.Name,
Metadata: metadata,
}
lockman.LockRawObject(ctx, saml.CloudaccountId, "saml-provider")
defer lockman.ReleaseRawObject(ctx, saml.CloudaccountId, "saml-provider")
iSAMLProvider, err := provider.CreateICloudSAMLProvider(&opts)
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "CreateICloudSAMLProvider"))
return
}
err = saml.SyncWithCloudSAMLProvider(ctx, self.GetUserCred(), iSAMLProvider)
if err != nil {
self.taskFailed(ctx, saml, errors.Wrap(err, "SyncWithCloudSAMLProvider"))
return
}
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,85 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type SAMLProviderDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(SAMLProviderDeleteTask{})
}
func (self *SAMLProviderDeleteTask) taskFailed(ctx context.Context, saml *models.SSAMLProvider, err error) {
saml.SetStatus(self.GetUserCred(), api.SAML_PROVIDER_STATUS_DELETE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, saml, logclient.ACT_DELETE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *SAMLProviderDeleteTask) taskComplete(ctx context.Context, saml *models.SSAMLProvider) {
saml.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
func (self *SAMLProviderDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
saml := obj.(*models.SSAMLProvider)
if len(saml.ExternalId) == 0 {
self.taskComplete(ctx, saml)
return
}
account, err := saml.GetCloudaccount()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "GetCloudaccount"))
return
}
provider, err := account.GetProvider()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "GetProvider"))
return
}
samls, err := provider.GetICloudSAMLProviders()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "GetICloudSAMLProviders"))
return
}
for i := range samls {
if samls[i].GetGlobalId() == saml.ExternalId {
err = samls[i].Delete()
if err != nil {
self.taskFailed(ctx, saml, errors.Wrapf(err, "Delete"))
return
}
}
}
self.taskComplete(ctx, saml)
}
+59
View File
@@ -0,0 +1,59 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/models"
)
type SyncCloudrolesTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(SyncCloudrolesTask{})
}
func (self *SyncCloudrolesTask) taskFailed(ctx context.Context, account *models.SCloudaccount, err error) {
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *SyncCloudrolesTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
account := obj.(*models.SCloudaccount)
provider, err := account.GetProvider()
if err != nil {
self.taskFailed(ctx, account, errors.Wrapf(err, "GetProvider"))
return
}
roles, err := provider.GetICloudroles()
if err != nil {
self.taskFailed(ctx, account, errors.Wrapf(err, "GetICloudroles"))
return
}
result := account.SyncCloudroles(ctx, self.GetUserCred(), roles)
log.Infof("SyncCloudroles for account %s(%s) result: %s", account.Name, account.Provider, result.Result())
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,64 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/models"
)
type SyncSAMLProvidersTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(SyncSAMLProvidersTask{})
}
func (self *SyncSAMLProvidersTask) taskFailed(ctx context.Context, account *models.SCloudaccount, err error) {
log.Errorf("failed sync saml provider for account %s error: %v", account.Name, err)
self.SetStageFailed(ctx, nil)
}
func (self *SyncSAMLProvidersTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
account := obj.(*models.SCloudaccount)
provider, err := account.GetProvider()
if err != nil {
self.taskFailed(ctx, account, errors.Wrapf(err, "GetProvider"))
return
}
lockman.LockRawObject(ctx, account.Id, "saml-provider")
defer lockman.ReleaseRawObject(ctx, account.Id, "saml-provider")
samls, err := provider.GetICloudSAMLProviders()
if err != nil {
self.taskFailed(ctx, account, errors.Wrapf(err, "GetICloudSAMLProviders"))
return
}
result := account.SyncSAMLProviders(ctx, self.GetUserCred(), samls)
log.Infof("Sync SAMLProviders for account %s(%s) result: %s", account.Name, account.Provider, result.Result())
self.SetStageComplete(ctx, nil)
}
+38 -5
View File
@@ -153,6 +153,8 @@ type ProviderConfig struct {
Account string
Secret string
AccountId string
ProxyFunc httputils.TransportProxyFunc
}
@@ -223,6 +225,8 @@ type ICloudProviderFactory interface {
GetSupportedDnsPolicyTypes() map[TDnsZoneType][]TDnsPolicyType
GetSupportedDnsPolicyValues() map[TDnsPolicyType][]TDnsPolicyValue
GetTTLRange(zoneType TDnsZoneType, productType TDnsProductType) TTlRange
IsSupportSAMLAuth() bool
}
type ICloudProvider interface {
@@ -264,6 +268,12 @@ type ICloudProvider interface {
CreateICloudgroup(name, desc string) (ICloudgroup, error)
GetIClouduserByName(name string) (IClouduser, error)
CreateIClouduser(conf *SClouduserCreateConfig) (IClouduser, error)
CreateICloudSAMLProvider(opts *SAMLProviderCreateOptions) (ICloudSAMLProvider, error)
GetICloudSAMLProviders() ([]ICloudSAMLProvider, error)
GetICloudroles() ([]ICloudrole, error)
GetICloudroleById(id string) (ICloudrole, error)
GetICloudroleByName(name string) (ICloudrole, error)
CreateICloudrole(opts *SRoleCreateOptions) (ICloudrole, error)
CreateICloudpolicy(opts *SCloudpolicyCreateOptions) (ICloudpolicy, error)
@@ -271,7 +281,6 @@ type ICloudProvider interface {
CreateSubscription(SubscriptionCreateInput) error
GetSamlEntityId() string
GetSamlSpInitiatedLoginUrl(idpName string) string
GetICloudDnsZones() ([]ICloudDnsZone, error)
GetICloudDnsZoneById(id string) (ICloudDnsZone, error)
@@ -428,6 +437,30 @@ func (self *SBaseProvider) CreateIClouduser(conf *SClouduserCreateConfig) (IClou
return nil, ErrNotImplemented
}
func (self *SBaseProvider) GetICloudSAMLProviders() ([]ICloudSAMLProvider, error) {
return nil, errors.Wrapf(ErrNotImplemented, "GetICloudSAMLProviders")
}
func (self *SBaseProvider) GetICloudroles() ([]ICloudrole, error) {
return nil, errors.Wrapf(ErrNotImplemented, "GetICloudroles")
}
func (self *SBaseProvider) GetICloudroleById(id string) (ICloudrole, error) {
return nil, errors.Wrapf(ErrNotImplemented, "GetICloudroleById")
}
func (self *SBaseProvider) GetICloudroleByName(name string) (ICloudrole, error) {
return nil, errors.Wrapf(ErrNotImplemented, "GetICloudroleByName")
}
func (self *SBaseProvider) CreateICloudrole(opts *SRoleCreateOptions) (ICloudrole, error) {
return nil, errors.Wrapf(ErrNotImplemented, "CreateICloudrole")
}
func (self *SBaseProvider) CreateICloudSAMLProvider(opts *SAMLProviderCreateOptions) (ICloudSAMLProvider, error) {
return nil, errors.Wrapf(ErrNotImplemented, "CreateICloudSAMLProvider")
}
func (self *SBaseProvider) CreateICloudpolicy(opts *SCloudpolicyCreateOptions) (ICloudpolicy, error) {
return nil, ErrNotImplemented
}
@@ -464,10 +497,6 @@ func (self *SBaseProvider) GetSamlEntityId() string {
return ""
}
func (self *SBaseProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return ""
}
func NewBaseProvider(factory ICloudProviderFactory) SBaseProvider {
return SBaseProvider{factory: factory}
}
@@ -557,6 +586,10 @@ func (factory *baseProviderFactory) GetSupportedBrands() []string {
return []string{}
}
func (factory *baseProviderFactory) IsSupportSAMLAuth() bool {
return false
}
func (factory *baseProviderFactory) GetProvider(providerId, providerName, url, username, password string) (ICloudProvider, error) {
return nil, httperrors.NewNotImplementedError("Not Implemented GetProvider")
}
+21
View File
@@ -0,0 +1,21 @@
// 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 cloudprovider
type SRoleCreateOptions struct {
Name string
Desc string
SAMLProvider string
}
+23
View File
@@ -24,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/samlutils"
)
type ICloudResource interface {
@@ -1101,6 +1102,28 @@ type ICloudVpcPeeringConnection interface {
GetPeerVpcId() string
GetPeerAccountId() string
GetEnabled() bool
Delete() error
}
type ICloudSAMLProvider interface {
ICloudResource
GetMetadataDocument() (*samlutils.EntityDescriptor, error)
GetAuthUrl() string
Delete() error
}
type ICloudrole interface {
GetGlobalId() string
GetName() string
GetDocument() *jsonutils.JSONDict
GetSAMLProvider() string
GetICloudpolicies() ([]ICloudpolicy, error)
AttachPolicy(id string) error
DetachPolicy(id string) error
Delete() error
}
+7
View File
@@ -14,6 +14,8 @@
package cloudprovider
import "yunion.io/x/onecloud/pkg/util/samlutils"
const (
SAML_ENTITY_ID_ALIYUN_ROLE = "urn:alibaba:cloudcomputing"
SAML_ENTITY_ID_AWS_CN = "urn:amazon:webservices:cn-north-1"
@@ -22,3 +24,8 @@ const (
SAML_ENTITY_ID_HUAWEI_CLOUD = "https://auth.huaweicloud.com/"
SAML_ENTITY_ID_GOOGLE = "google.com"
)
type SAMLProviderCreateOptions struct {
Name string
Metadata samlutils.EntityDescriptor
}
+19 -14
View File
@@ -16,7 +16,6 @@ package models
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
@@ -27,8 +26,9 @@ import (
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/samlutils"
)
func (account *SCloudaccount) AllowGetDetailsSaml(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
@@ -38,6 +38,10 @@ func (account *SCloudaccount) AllowGetDetailsSaml(ctx context.Context, userCred
func (account *SCloudaccount) GetDetailsSaml(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (api.GetCloudaccountSamlOutput, error) {
output := api.GetCloudaccountSamlOutput{}
if account.SAMLAuth.IsFalse() {
return output, httperrors.NewNotSupportedError("account %s not enable saml auth", account.Name)
}
provider, err := account.GetProvider()
if err != nil {
return output, errors.Wrap(err, "GetProviderFactory")
@@ -50,18 +54,19 @@ func (account *SCloudaccount) GetDetailsSaml(ctx context.Context, userCred mccli
output.RedirectLoginUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "redirect/login", account.Id)
output.RedirectLogoutUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "redirect/logout", account.Id)
output.MetadataUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "metadata", account.Id)
// XXXXX
// TODO, find idpName for this cloudaccount
// XXXXX
idpName := "saml.yunion.io"
output.InitLoginUrl = provider.GetSamlSpInitiatedLoginUrl(idpName)
if len(output.InitLoginUrl) == 0 {
input := samlutils.SIdpInitiatedLoginInput{
EntityID: output.EntityId,
IdpId: account.Id,
}
output.InitLoginUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString()))
s := auth.GetAdminSession(ctx, options.Options.Region, "")
params := map[string]string{
"scope": "system",
"cloudaccount_id": account.Id,
"status": cloudid.SAML_PROVIDER_STATUS_AVAILABLE,
}
samlproviders, _ := modules.SAMLProviders.List(s, jsonutils.Marshal(params))
for _, sp := range samlproviders.Data {
authUrl, _ := sp.GetString("auth_url")
if len(authUrl) > 0 {
output.InitLoginUrl = authUrl
break
}
}
return output, nil
}
+5
View File
@@ -163,6 +163,8 @@ type SCloudaccount struct {
// 公有云子账号登录地址
IamLoginUrl string `width:"512" charset:"ascii" nullable:"false" list:"domain" update:"domain"`
SAMLAuth tristate.TriState `nullable:"false" get:"user" update:"domain" create:"optional" list:"user" default:"false"`
}
func (self *SCloudaccount) GetCloudproviders() []SCloudprovider {
@@ -993,6 +995,9 @@ func (manager *SCloudaccountManager) validateCreateData(
if err != nil {
return input, err
}
if input.SAMLAuth != nil && *input.SAMLAuth && !providerDriver.IsSupportSAMLAuth() {
return input, httperrors.NewNotSupportedError("%s not support saml auth", input.Provider)
}
if len(input.Brand) > 0 && input.Brand != providerDriver.GetName() {
brands := providerDriver.GetSupportedBrands()
if !utils.IsInStringArray(providerDriver.GetName(), brands) {
@@ -12,23 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package providers
package modules
var (
driverTable = make(map[string]ICloudSAMLLoginDriver)
import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
)
func Register(driver ICloudSAMLLoginDriver) {
driverTable[driver.GetEntityID()] = driver
type SCloudroleManager struct {
modulebase.ResourceManager
}
func FindDriver(entityId string) ICloudSAMLLoginDriver {
if driver, ok := driverTable[entityId]; ok {
return driver
}
return nil
}
var (
Cloudroles SCloudroleManager
)
func AllDrivers() map[string]ICloudSAMLLoginDriver {
return driverTable
func init() {
Cloudroles = SCloudroleManager{NewCloudIdManager("cloudrole", "cloudroles",
[]string{},
[]string{})}
register(&Cloudroles)
}
@@ -12,19 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package providers
package modules
import (
"yunion.io/x/onecloud/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
)
type ICloudSAMLLoginDriver interface {
GetEntityID() string
GetMetadataFilename() string
GetMetadataUrl() string
GetIdpInitiatedLoginData(idpId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error)
GetSpInitiatedLoginData(idpId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error)
type SSAMLProviderManager struct {
modulebase.ResourceManager
}
var (
SAMLProviders SSAMLProviderManager
)
func init() {
SAMLProviders = SSAMLProviderManager{NewCloudIdManager("saml_provider", "saml_providers",
[]string{},
[]string{})}
register(&SAMLProviders)
}
+35
View File
@@ -0,0 +1,35 @@
// 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 modules
import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
)
type SSamluserManager struct {
modulebase.ResourceManager
}
var (
Samlusers SClouduserManager
)
func init() {
Samlusers = SClouduserManager{NewCloudIdManager("samluser", "samlusers",
[]string{},
[]string{})}
register(&Samlusers)
}
+1
View File
@@ -464,6 +464,7 @@ type SCloudAccountUpdateBaseOptions struct {
SyncIntervalSeconds *int `help:"auto synchornize interval in seconds"`
AutoCreateProject *bool `help:"automatically create local project for new remote project"`
ProxySetting string `help:"proxy setting name or id" json:"proxy_setting"`
SamlAuth string `help:"Enable or disable saml auth" choices:"true|false"`
Desc string `help:"Description" json:"description" token:"desc"`
}
@@ -12,12 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package options
package cloudid
import "yunion.io/x/jsonutils"
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudgroupListOptions struct {
BaseListOptions
options.BaseListOptions
ClouduserId string `json:"clouduser_id"`
CloudpolicyId string `json:"cloudpolicy_id"`
@@ -25,7 +29,7 @@ type CloudgroupListOptions struct {
}
func (opts *CloudgroupListOptions) Params() (jsonutils.JSONObject, error) {
return ListStructToParams(opts)
return options.ListStructToParams(opts)
}
type CloudgroupCreateOptions struct {
@@ -0,0 +1,43 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudgroupcacheListOptions struct {
options.BaseListOptions
CloudgroupId string `json:"cloudgroup_id"`
}
func (opts *CloudgroupcacheListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type CloudgroupcacheIdOption struct {
ID string `help:"Cloudgroup cache Id"`
}
func (opts *CloudgroupcacheIdOption) GetId() string {
return opts.ID
}
func (opts *CloudgroupcacheIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -0,0 +1,35 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudgroupPolicyListOptions struct {
options.BaseListOptions
Cloudgroup string `help:"ID or Name of Cloudgroup"`
Cloudpolicy string `help:"Policy ID or name"`
}
func (opts *CloudgroupPolicyListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
func (opts *CloudgroupPolicyListOptions) GetContextId() string {
return opts.Cloudgroup
}
@@ -0,0 +1,35 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudgroupUserListOptions struct {
options.BaseListOptions
Cloudgroup string `help:"ID or Name of Cloudgroup"`
Clouduser string `help:"User ID or name"`
}
func (opts *CloudgroupUserListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
func (opts *CloudgroupUserListOptions) GetContextId() string {
return opts.Clouduser
}
@@ -12,15 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package options
package cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudpolicyListOptions struct {
BaseListOptions
options.BaseListOptions
CloudproviderId string `json:"cloudprovider_id"`
ClouduserId string `json:"clouduser_id"`
@@ -29,7 +31,7 @@ type CloudpolicyListOptions struct {
}
func (opts *CloudpolicyListOptions) Params() (jsonutils.JSONObject, error) {
return ListStructToParams(opts)
return options.ListStructToParams(opts)
}
type CloudpolicyIdOptions struct {
@@ -0,0 +1,32 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudpolicycacheListOptions struct {
options.BaseListOptions
CloudpolyId string
CloudaccountId string
}
func (opts *CloudpolicycacheListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
+41
View File
@@ -0,0 +1,41 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type CloudroleListOptions struct {
options.BaseListOptions
}
func (opts *CloudroleListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type CloudroleIdOptions struct {
ID string `help:"Cloudrole Id"`
}
func (opts *CloudroleIdOptions) GetId() string {
return opts.ID
}
func (opts *CloudroleIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -12,12 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package options
package cloudid
import "yunion.io/x/jsonutils"
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type ClouduserListOptions struct {
BaseListOptions
options.BaseListOptions
CloudaccountId string `help:"Cloudaccount Id"`
CloudproviderId string `help:"Cloudprovider Id"`
CloudpolicyId string `help:"filter cloudusers by cloudpolicy"`
@@ -25,7 +29,7 @@ type ClouduserListOptions struct {
}
func (opts *ClouduserListOptions) Params() (jsonutils.JSONObject, error) {
return ListStructToParams(opts)
return options.ListStructToParams(opts)
}
type ClouduserCreateOptions struct {
@@ -0,0 +1,35 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type ClouduserPolicyListOptions struct {
options.BaseListOptions
Clouduser string `help:"ID or Name of Clouduser"`
Cloudpolicy string `help:"Policy ID or name"`
}
func (opts *ClouduserPolicyListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
func (opts *ClouduserPolicyListOptions) GetContextId() string {
return opts.Cloudpolicy
}
+1
View File
@@ -0,0 +1 @@
package cloudid // import "yunion.io/x/onecloud/pkg/mcclient/options/cloudid"
@@ -0,0 +1,49 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type SAMLProviderListOptions struct {
options.BaseListOptions
}
func (opts *SAMLProviderListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type SAMLProviderIdOptions struct {
ID string `help:"SAML Provider Id"`
}
func (opts *SAMLProviderIdOptions) GetId() string {
return opts.ID
}
func (opts *SAMLProviderIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type SAMLProviderCreateOptions struct {
CLOUDACCOUNT_ID string
}
func (opts *SAMLProviderCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
+53
View File
@@ -0,0 +1,53 @@
// 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 cloudid
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type SamluserListOptions struct {
options.BaseListOptions
CloudgroupId string `help:"Filter by cloudgroup"`
CloudaccountId string `help:"Filter by cloudaccount"`
}
func (opts *SamluserListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type SamluserCreateOptions struct {
OwnerId string
CLOUDGROUP_ID string `help:"CloudgroupId"`
CLOUDACCOUNT_ID string `help:"CloudaccountId"`
}
func (opts *SamluserCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type SamluserIdOptions struct {
ID string `help:"SAML user Id"`
}
func (opts *SamluserIdOptions) GetId() string {
return opts.ID
}
func (opts *SamluserIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -329,10 +329,6 @@ func (self *SAliyunProvider) GetSamlEntityId() string {
return cloudprovider.SAML_ENTITY_ID_ALIYUN_ROLE
}
func (self *SAliyunProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return ""
}
func (self *SAliyunProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) {
izones := []cloudprovider.ICloudDnsZone{}
privateZone, err := self.client.GetPrivateICloudDnsZones()
+37
View File
@@ -0,0 +1,37 @@
// 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 aliyun
import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SAMLProvider struct {
multicloud.SResourceBase
client *SAliyunClient
}
func (self *SAliyunClient) ListSAMLProviders() ([]SAMLProvider, error) {
result := []SAMLProvider{}
resp, err := self.ramRequest("ListSAMLProviders", map[string]string{})
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
log.Errorf("result: %s", resp.PrettyString())
return result, nil
}
@@ -0,0 +1,36 @@
// 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 shell
import (
"yunion.io/x/onecloud/pkg/multicloud/aliyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SamlProviderListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&SamlProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *aliyun.SRegion, args *SamlProviderListOptions) error {
result, err := cli.GetClient().ListSAMLProviders()
if err != nil {
return err
}
printList(result, 0, 0, 0, []string{})
return nil
})
}
+126
View File
@@ -16,9 +16,18 @@ package aws
import (
"fmt"
"net/url"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
var (
samlRole = `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:AssumeRoleWithSAML","Principal":{"Federated":"%s"},"Condition":{"StringEquals":{"SAML:aud":["%s"]}}}]}`
)
type SRole struct {
@@ -34,6 +43,78 @@ type SRole struct {
CreateDate time.Time `xml:"CreateDate"`
}
func (self *SRole) GetGlobalId() string {
return self.Arn
}
func (self *SRole) GetName() string {
return self.RoleName
}
func (self *SRole) Delete() error {
return self.client.DeleteRole(self.RoleName)
}
func (self *SRole) GetDocument() *jsonutils.JSONDict {
data, err := url.QueryUnescape(self.AssumeRolePolicyDocument)
if err != nil {
return nil
}
document, err := jsonutils.Parse([]byte(data))
if err != nil {
return nil
}
return document.(*jsonutils.JSONDict)
}
//[{"Action":"sts:AssumeRoleWithSAML","Condition":{"StringEquals":{"SAML:aud":"https://signin.aws.amazon.com/saml"}},"Effect":"Allow","Principal":{"Federated":"arn:aws:iam::879324515906:saml-provider/quxuan"}}]
func (self *SRole) GetSAMLProvider() string {
document := self.GetDocument()
if document != nil {
statement, err := document.GetArray("Statement")
if err == nil {
for i := range statement {
if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRoleWithSAML" {
sp, _ := statement[i].GetString("Principal", "Federated")
if len(sp) > 0 {
return sp
}
}
}
}
}
return ""
}
func (self *SRole) AttachPolicy(id string) error {
return self.client.AttachRolePolicy(self.RoleName, self.client.getIamArn(id))
}
func (self *SRole) DetachPolicy(id string) error {
return self.client.DetachRolePolicy(self.RoleName, self.client.getIamArn(id))
}
func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies := []SAttachedPolicy{}
marker := ""
for {
part, err := self.client.ListAttachedRolePolicies(self.RoleName, marker, 100, "")
if err != nil {
return nil, errors.Wrapf(err, "ListAttachedRolePolicies")
}
policies = append(policies, part.AttachedPolicies...)
marker = part.Marker
if len(marker) == 0 {
break
}
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
ret = append(ret, &policies[i])
}
return ret, nil
}
type SRoles struct {
Roles []SRole `xml:"Roles>member"`
IsTruncated bool `xml:"IsTruncated"`
@@ -81,3 +162,48 @@ func (self *SAwsClient) DeleteRole(name string) error {
}
return self.iamRequest("DeleteRole", params, nil)
}
func (self *SAwsClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
roles := []SRole{}
marker := ""
for {
part, err := self.ListRoles(marker, 100, "")
if err != nil {
return nil, errors.Wrapf(err, "ListRoles")
}
roles = append(roles, part.Roles...)
marker = part.Marker
if len(marker) == 0 {
break
}
}
ret := []cloudprovider.ICloudrole{}
for i := range roles {
ret = append(ret, &roles[i])
}
return ret, nil
}
func (self *SAwsClient) CreateRole(opts *cloudprovider.SRoleCreateOptions) (*SRole, error) {
if len(opts.SAMLProvider) > 0 {
aud := "https://signin.amazonaws.cn/saml"
if self.GetAccessEnv() == api.CLOUD_ACCESS_ENV_AWS_GLOBAL {
aud = "https://signin.aws.amazon.com/saml"
}
params := map[string]string{
"RoleName": opts.Name,
"Description": opts.Desc,
"AssumeRolePolicyDocument": fmt.Sprintf(samlRole, opts.SAMLProvider, aud),
}
role := struct {
Role SRole
}{}
err := self.iamRequest("CreateRole", params, &role)
if err != nil {
return nil, errors.Wrapf(err, "CreateRole")
}
role.Role.client = self
return &role.Role, nil
}
return nil, cloudprovider.ErrNotImplemented
}
+47 -4
View File
@@ -312,16 +312,59 @@ func (self *SAwsProvider) GetSamlEntityId() string {
return self.client.GetSamlEntityId()
}
func (self *SAwsProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return ""
}
func (self *SAwsProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) {
return self.client.GetICloudDnsZones()
}
func (self *SAwsProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) {
return self.client.GetHostedZoneById(id)
}
func (self *SAwsProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) {
return self.client.CreateHostedZone(opts)
}
func (self *SAwsProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
return self.client.GetICloudSAMLProviders()
}
func (self *SAwsProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) {
sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String())
if err != nil {
return nil, errors.Wrap(err, "CreateSAMLProvider")
}
return sp, nil
}
func (self *SAwsProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
return self.client.GetICloudroles()
}
func (self *SAwsProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) {
roles, err := self.GetICloudroles()
if err != nil {
return nil, errors.Wrapf(err, "GetICloudroles")
}
for i := range roles {
if roles[i].GetGlobalId() == id {
return roles[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
}
func (self *SAwsProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) {
role, err := self.client.GetRole(name)
if err != nil {
return nil, errors.Wrapf(err, "GetRole(%s)", name)
}
return role, nil
}
func (self *SAwsProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) {
role, err := self.client.CreateRole(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateRole")
}
return role, nil
}
+173
View File
@@ -0,0 +1,173 @@
// 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 aws
import (
"fmt"
"strings"
"time"
"unicode"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/apis/cloudid"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
compute_api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/options"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/samlutils"
)
type SAMLProvider struct {
multicloud.SResourceBase
client *SAwsClient
SAMLMetadataDocument string `xml:"SAMLMetadataDocument"`
Arn string `xml:"Arn"`
ValidUntil time.Time `xml:"ValidUntil"`
CreateDate time.Time `xml:"CreateDate"`
}
func (self *SAMLProvider) GetGlobalId() string {
return self.Arn
}
func (self *SAMLProvider) GetId() string {
return self.Arn
}
func (self *SAMLProvider) GetName() string {
if info := strings.Split(self.Arn, "/"); len(info) > 0 {
return info[len(info)-1]
}
return self.Arn
}
func (self *SAMLProvider) GetStatus() string {
return api.SAML_PROVIDER_STATUS_AVAILABLE
}
func (self *SAMLProvider) Delete() error {
return self.client.DeleteSAMLProvider(self.Arn)
}
func (self *SAMLProvider) GetAuthUrl() string {
input := samlutils.SIdpInitiatedLoginInput{
EntityID: cloudprovider.SAML_ENTITY_ID_AWS_CN,
IdpId: self.client.cpcfg.AccountId,
}
if self.client.GetAccessEnv() == compute_api.CLOUD_ACCESS_ENV_AWS_GLOBAL {
input.EntityID = cloudprovider.SAML_ENTITY_ID_AWS
}
return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString()))
}
func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) {
saml, err := self.client.GetSAMLProvider(self.Arn)
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Arn)
}
metadata, err := samlutils.ParseMetadata([]byte(saml.SAMLMetadataDocument))
if err != nil {
return nil, errors.Wrapf(err, "ParseMetadata")
}
return &metadata, nil
}
type SAMLProviders struct {
SAMLProviderList []SAMLProvider `xml:"SAMLProviderList>member"`
}
func (self *SAwsClient) ListSAMLProviders() ([]SAMLProvider, error) {
result := SAMLProviders{}
err := self.iamRequest("ListSAMLProviders", nil, &result)
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
return result.SAMLProviderList, nil
}
func (self *SAwsClient) GetSAMLProvider(arn string) (*SAMLProvider, error) {
result := &SAMLProvider{client: self, Arn: arn}
params := map[string]string{"SAMLProviderArn": arn}
err := self.iamRequest("GetSAMLProvider", params, result)
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProvider")
}
return result, nil
}
func (self *SAwsClient) DeleteSAMLProvider(arn string) error {
params := map[string]string{"SAMLProviderArn": arn}
return self.iamRequest("DeleteSAMLProvider", params, nil)
}
func (self *SAwsClient) CreateSAMLProvider(name, metadata string) (*SAMLProvider, error) {
name = func() string {
ret := ""
for _, s := range name {
if unicode.IsLetter(s) || unicode.IsNumber(s) || s == '.' || s == '_' || s == '-' {
ret += string(s)
} else {
ret += "-"
}
}
if len(ret) > 128 {
ret = ret[:128]
}
return ret
}()
params := map[string]string{
"Name": name,
"SAMLMetadataDocument": metadata,
}
result := struct {
SAMLProviderArn string `xml:"SAMLProviderArn"`
}{}
err := self.iamRequest("CreateSAMLProvider", params, &result)
if err != nil {
return nil, errors.Wrapf(err, "CreateSAMLProvider")
}
return self.GetSAMLProvider(result.SAMLProviderArn)
}
func (self *SAwsClient) UpdateSAMLProvider(arn, metadata string) (*SAMLProvider, error) {
params := map[string]string{
"SAMLProviderArn": arn,
"SAMLMetadataDocument": metadata,
}
saml := &SAMLProvider{client: self}
err := self.iamRequest("UpdateSAMLProvider", params, saml)
if err != nil {
return nil, errors.Wrapf(err, "UpdateSAMLProvider")
}
return saml, nil
}
func (self *SAwsClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
providers, err := self.ListSAMLProviders()
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
ret := []cloudprovider.ICloudSAMLProvider{}
for i := range providers {
providers[i].client = self
ret = append(ret, &providers[i])
}
return ret, nil
}
+14
View File
@@ -15,6 +15,7 @@
package shell
import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
@@ -44,6 +45,10 @@ func init() {
return err
}
printObject(role)
document := role.GetDocument()
if document != nil {
printObject(document)
}
return nil
})
@@ -51,4 +56,13 @@ func init() {
return cli.GetClient().DeleteRole(args.ROLE)
})
shellutils.R(&cloudprovider.SRoleCreateOptions{}, "cloud-role-create", "Create role", func(cli *aws.SRegion, args *cloudprovider.SRoleCreateOptions) error {
role, err := cli.GetClient().CreateRole(args)
if err != nil {
return err
}
printObject(role)
return nil
})
}
+79
View File
@@ -0,0 +1,79 @@
// 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 shell
import (
"yunion.io/x/onecloud/pkg/multicloud/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SAMLProviderListOptions struct {
}
shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml providers", func(cli *aws.SRegion, args *SAMLProviderListOptions) error {
samls, err := cli.GetClient().ListSAMLProviders()
if err != nil {
return err
}
printList(samls, 0, 0, 0, []string{})
return nil
})
type SAMLProviderArnOptions struct {
ARN string
}
shellutils.R(&SAMLProviderArnOptions{}, "saml-provider-show", "Show saml provider", func(cli *aws.SRegion, args *SAMLProviderArnOptions) error {
saml, err := cli.GetClient().GetSAMLProvider(args.ARN)
if err != nil {
return err
}
printObject(saml)
return nil
})
shellutils.R(&SAMLProviderArnOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *aws.SRegion, args *SAMLProviderArnOptions) error {
return cli.GetClient().DeleteSAMLProvider(args.ARN)
})
type SAMLProviderCreateOptions struct {
NAME string
METADATA string
}
shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *aws.SRegion, args *SAMLProviderCreateOptions) error {
saml, err := cli.GetClient().CreateSAMLProvider(args.NAME, args.METADATA)
if err != nil {
return err
}
printObject(saml)
return nil
})
type SAMLProviderUpdateOptions struct {
ARN string
METADATA string
}
shellutils.R(&SAMLProviderUpdateOptions{}, "saml-provider-update", "Update saml provider", func(cli *aws.SRegion, args *SAMLProviderUpdateOptions) error {
saml, err := cli.GetClient().UpdateSAMLProvider(args.ARN, args.METADATA)
if err != nil {
return err
}
printObject(saml)
return nil
})
}
@@ -297,7 +297,3 @@ func (self *SGoogleProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicy
func (self *SGoogleProvider) GetSamlEntityId() string {
return cloudprovider.SAML_ENTITY_ID_GOOGLE
}
func (self *SGoogleProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return self.client.GetSamlSpInitiatedLoginUrl(idpName)
}
+62 -54
View File
@@ -33,60 +33,62 @@ type Client struct {
// 标记初始化状态
init bool
Balances *modules.SBalanceManager
Bandwidths *modules.SBandwidthManager
Credentials *modules.SCredentialManager
Disks *modules.SDiskManager
Domains *modules.SDomainManager
Eips *modules.SEipManager
Elasticcache *modules.SElasticcacheManager
DcsAvailableZone *modules.SDcsAvailableZoneManager
Flavors *modules.SFlavorManager
Images *modules.SImageManager
OpenStackImages *modules.SImageManager
Interface *modules.SInterfaceManager
Jobs *modules.SJobManager
Keypairs *modules.SKeypairManager
Elb *modules.SLoadbalancerManager
ElbBackend *modules.SElbBackendManager
ElbBackendGroup *modules.SElbBackendGroupManager
ElbListeners *modules.SElbListenersManager
ElbCertificates *modules.SElbCertificatesManager
ElbHealthCheck *modules.SElbHealthCheckManager
ElbL7policies *modules.SElbL7policiesManager
ElbPolicies *modules.SElbPoliciesManager
ElbWhitelist *modules.SElbWhitelistManager
Orders *modules.SOrderManager
Port *modules.SPortManager
Projects *modules.SProjectManager
Regions *modules.SRegionManager
SecurityGroupRules *modules.SSecgroupRuleManager
SecurityGroups *modules.SSecurityGroupManager
NovaSecurityGroups *modules.SSecurityGroupManager
Servers *modules.SServerManager
ServersV2 *modules.SServerManager
NovaServers *modules.SServerManager
Snapshots *modules.SSnapshotManager
OsSnapshots *modules.SSnapshotManager
Subnets *modules.SSubnetManager
Users *modules.SUserManager
Vpcs *modules.SVpcManager
Zones *modules.SZoneManager
VpcRoutes *modules.SVpcRouteManager
SNatRules *modules.SNatSRuleManager
DNatRules *modules.SNatDRuleManager
NatGateways *modules.SNatGatewayManager
VpcPeerings *modules.SVpcPeeringManager
DBInstance *modules.SDBInstanceManager
DBInstanceBackup *modules.SDBInstanceBackupManager
DBInstanceFlavor *modules.SDBInstanceFlavorManager
DBInstanceJob *modules.SDBInstanceJobManager
Traces *modules.STraceManager
CloudEye *modules.SCloudEyeManager
Quotas *modules.SQuotaManager
EnterpriseProjects *modules.SEnterpriseProjectManager
Roles *modules.SRoleManager
Groups *modules.SGroupManager
Balances *modules.SBalanceManager
Bandwidths *modules.SBandwidthManager
Credentials *modules.SCredentialManager
Disks *modules.SDiskManager
Domains *modules.SDomainManager
Eips *modules.SEipManager
Elasticcache *modules.SElasticcacheManager
DcsAvailableZone *modules.SDcsAvailableZoneManager
Flavors *modules.SFlavorManager
Images *modules.SImageManager
OpenStackImages *modules.SImageManager
Interface *modules.SInterfaceManager
Jobs *modules.SJobManager
Keypairs *modules.SKeypairManager
Elb *modules.SLoadbalancerManager
ElbBackend *modules.SElbBackendManager
ElbBackendGroup *modules.SElbBackendGroupManager
ElbListeners *modules.SElbListenersManager
ElbCertificates *modules.SElbCertificatesManager
ElbHealthCheck *modules.SElbHealthCheckManager
ElbL7policies *modules.SElbL7policiesManager
ElbPolicies *modules.SElbPoliciesManager
ElbWhitelist *modules.SElbWhitelistManager
Orders *modules.SOrderManager
Port *modules.SPortManager
Projects *modules.SProjectManager
Regions *modules.SRegionManager
SecurityGroupRules *modules.SSecgroupRuleManager
SecurityGroups *modules.SSecurityGroupManager
NovaSecurityGroups *modules.SSecurityGroupManager
Servers *modules.SServerManager
ServersV2 *modules.SServerManager
NovaServers *modules.SServerManager
Snapshots *modules.SSnapshotManager
OsSnapshots *modules.SSnapshotManager
Subnets *modules.SSubnetManager
Users *modules.SUserManager
Vpcs *modules.SVpcManager
Zones *modules.SZoneManager
VpcRoutes *modules.SVpcRouteManager
SNatRules *modules.SNatSRuleManager
DNatRules *modules.SNatDRuleManager
NatGateways *modules.SNatGatewayManager
VpcPeerings *modules.SVpcPeeringManager
DBInstance *modules.SDBInstanceManager
DBInstanceBackup *modules.SDBInstanceBackupManager
DBInstanceFlavor *modules.SDBInstanceFlavorManager
DBInstanceJob *modules.SDBInstanceJobManager
Traces *modules.STraceManager
CloudEye *modules.SCloudEyeManager
Quotas *modules.SQuotaManager
EnterpriseProjects *modules.SEnterpriseProjectManager
Roles *modules.SRoleManager
Groups *modules.SGroupManager
SAMLProviders *modules.SAMLProviderManager
SAMLProviderMappings *modules.SAMLProviderMappingManager
}
func (self *Client) SetHttpClient(httpClient *http.Client) {
@@ -142,6 +144,8 @@ func (self *Client) SetHttpClient(httpClient *http.Client) {
self.EnterpriseProjects.SetHttpClient(httpClient)
self.Roles.SetHttpClient(httpClient)
self.Groups.SetHttpClient(httpClient)
self.SAMLProviders.SetHttpClient(httpClient)
self.SAMLProviderMappings.SetHttpClient(httpClient)
}
func (self *Client) InitWithOptions(regionId, domainId, projectId string, credential auth.Credential) error {
@@ -229,6 +233,10 @@ func (self *Client) initManagers() {
self.Roles.SetDomainId(self.domainId)
self.Groups = modules.NewGroupManager(self.signer, self.debug)
self.Groups.SetDomainId(self.domainId)
self.SAMLProviders = modules.NewSAMLProviderManager(self.signer, self.debug)
self.SAMLProviders.SetDomainId(self.domainId)
self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.signer, self.debug)
self.SAMLProviderMappings.SetDomainId(self.domainId)
}
self.init = true
@@ -170,6 +170,10 @@ func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext,
request.AddQueryParam(k, v)
}
if len(self.DomainId) > 0 {
request.AddHeaderParam("X-Domain-Id", self.DomainId)
}
return self._get(request, responseKey)
}
@@ -216,6 +220,27 @@ func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContex
return self._do(request, responseKey)
}
func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return self.PatchInContext(self.ctx, id, params)
}
func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword)
}
func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
request := self.newRequest("PATCH", id, spec, ctx)
content := getContent(params)
if len(content) > 0 {
request.SetContent([]byte(content))
}
if len(self.DomainId) > 0 {
request.AddHeaderParam("X-Domain-Id", self.DomainId)
}
return self._do(request, responseKey)
}
func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return self.DeleteInContext(self.ctx, id, params)
}
@@ -248,6 +273,9 @@ func (self *SResourceManager) PerformAction(action string, id string, params jso
func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) {
request := self.newRequest("POST", id, action, nil)
request.SetContent([]byte(getContent(params)))
if len(self.DomainId) > 0 {
request.AddHeaderParam("X-Domain-Id", self.DomainId)
}
return self._do(request, responseKey)
}
@@ -0,0 +1,37 @@
// 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 modules
import (
"yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth"
)
type SAMLProviderMappingManager struct {
SResourceManager
}
func NewSAMLProviderMappingManager(signer auth.Signer, debug bool) *SAMLProviderMappingManager {
return &SAMLProviderMappingManager{SResourceManager: SResourceManager{
SBaseManager: NewBaseManager(signer, debug),
ServiceName: ServiceNameIAM,
Region: "",
ProjectId: "",
version: "v3/OS-FEDERATION",
Keyword: "mapping",
KeywordPlural: "mappings",
ResourceKeyword: "mappings",
}}
}
@@ -0,0 +1,37 @@
// 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 modules
import (
"yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth"
)
type SAMLProviderManager struct {
SResourceManager
}
func NewSAMLProviderManager(signer auth.Signer, debug bool) *SAMLProviderManager {
return &SAMLProviderManager{SResourceManager: SResourceManager{
SBaseManager: NewBaseManager(signer, debug),
ServiceName: ServiceNameIAM,
Region: "",
ProjectId: "",
version: "v3/OS-FEDERATION",
Keyword: "identity_provider",
KeywordPlural: "identity_providers",
ResourceKeyword: "identity_providers",
}}
}
-4
View File
@@ -560,7 +560,3 @@ func (self *SHuaweiClient) initOwner() error {
self.ownerId = ownerId
return nil
}
func (self *SHuaweiClient) GetSamlSpInitiatedLoginUrl(idpName string) string {
return fmt.Sprintf("https://auth.huaweicloud.com/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.ownerId, idpName)
}
+10 -2
View File
@@ -289,6 +289,14 @@ func (self *SHuaweiProvider) GetSamlEntityId() string {
return cloudprovider.SAML_ENTITY_ID_HUAWEI_CLOUD
}
func (self *SHuaweiProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return self.client.GetSamlSpInitiatedLoginUrl(idpName)
func (self *SHuaweiProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
return self.client.GetICloudSAMLProviders()
}
func (self *SHuaweiProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) {
sp, err := self.client.CreateSAMLProvider(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateSAMLProvider")
}
return sp, nil
}
+321
View File
@@ -0,0 +1,321 @@
// 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 huawei
import (
"fmt"
"time"
"unicode"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules"
"yunion.io/x/onecloud/pkg/util/samlutils"
)
type SAMLProviderLinks struct {
Self string
Protocols string
}
type SAMLProvider struct {
multicloud.SResourceBase
client *SHuaweiClient
Id string
Links SAMLProviderLinks
Description string
}
func (self *SAMLProvider) GetId() string {
return self.Id
}
func (self *SAMLProvider) GetGlobalId() string {
return self.Id
}
func (self *SAMLProvider) GetName() string {
return self.Id
}
func (self *SAMLProvider) GetStatus() string {
mappings, err := self.client.ListSAMLProviderMappings()
if err != nil {
return api.SAML_PROVIDER_STATUS_UNKNOWN
}
for i := range mappings {
if mappings[i].Id == DEFAULT_ONECLOUD_MAPPING {
return api.SAML_PROVIDER_STATUS_AVAILABLE
}
}
return api.SAML_PROVIDER_STATUS_UNVALIABLE
}
func (self *SAMLProvider) GetAuthUrl() string {
return fmt.Sprintf("https://auth.huaweicloud.com/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.client.ownerId, self.Id)
}
func (self *SAMLProvider) Delete() error {
return self.client.DeleteSAMLProvider(self.Id)
}
func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) {
info, err := self.client.GetSAMLProviderMetadata(self.Id)
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProviderMetadata(%s)", self.Id)
}
metadata, err := samlutils.ParseMetadata([]byte(info.Data))
if err != nil {
return nil, errors.Wrapf(err, "ParseMetadata")
}
return &metadata, nil
}
func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) {
client, err := self.newGeneralAPIClient()
if err != nil {
return nil, errors.Wrapf(err, "newGeneralAPIClient")
}
samls := []SAMLProvider{}
err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls)
if err != nil {
return nil, errors.Wrapf(err, "doListAll")
}
return samls, nil
}
type SAMLProviderProtocol struct {
MappingId string
Id string
}
func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) {
client, err := self.newGeneralAPIClient()
if err != nil {
return nil, errors.Wrap(err, "newGeneralAPIClient")
}
resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols")
if err != nil {
return nil, errors.Wrapf(err, "ListInContextWithSpec")
}
protocols := []SAMLProviderProtocol{}
return protocols, jsonutils.Update(&protocols, resp.Data)
}
type SAMLProviderMetadata struct {
DomainId string
UpdateTime time.Time
Data string
IdpId string
ProtocolId string
Id string
EntityId string
XaccountType string
}
func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) {
client, err := self.newGeneralAPIClient()
if err != nil {
return nil, errors.Wrap(err, "newGeneralAPIClient")
}
client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION")
resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "")
if err != nil {
return nil, err
}
metadata := &SAMLProviderMetadata{}
err = resp.Unmarshal(metadata)
if err != nil {
return nil, errors.Wrap(err, "resp.Unmarshal")
}
return metadata, nil
}
func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error {
params := map[string]string{
"domain_id": self.ownerId,
"xaccount_type": "",
"metadata": metadata,
}
client, err := self.newGeneralAPIClient()
if err != nil {
return errors.Wrap(err, "newGeneralAPIClient")
}
client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION")
_, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "")
if err != nil {
return errors.Wrapf(err, "SAMLProvider.PerformAction")
}
return nil
}
func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
samls, err := self.ListSAMLProviders()
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
ret := []cloudprovider.ICloudSAMLProvider{}
for i := range samls {
samls[i].client = self
ret = append(ret, &samls[i])
}
return ret, nil
}
func (self *SHuaweiClient) DeleteSAMLProvider(id string) error {
client, err := self.newGeneralAPIClient()
if err != nil {
return errors.Wrap(err, "newGeneralAPIClient")
}
_, err = client.SAMLProviders.Delete(id, nil)
return err
}
func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) {
client, err := self.newGeneralAPIClient()
if err != nil {
return nil, errors.Wrap(err, "newGeneralAPIClient")
}
params := jsonutils.Marshal(map[string]interface{}{
"identity_provider": map[string]interface{}{
"description": opts.Name,
"enabled": true,
},
})
name := []byte{}
for _, c := range opts.Name {
if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' {
name = append(name, byte(c))
} else {
name = append(name, '-')
}
}
opts.Name = string(name)
_, err = client.SAMLProviders.Update(opts.Name, params)
if err != nil {
if he, ok := err.(*modules.HuaweiClientError); ok && he.Code != 409 {
return nil, errors.Wrapf(err, "SAMLProviders.Update")
}
}
ret := SAMLProvider{client: self, Id: opts.Name}
err = self.UpdateSAMLProviderMetadata(opts.Name, opts.Metadata.String())
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
err = self.InitSAMLProviderMapping(opts.Name)
if err != nil {
return nil, errors.Wrapf(err, "InitSAMLProviderMapping")
}
return &ret, nil
}
type SAMLProviderMapping struct {
Id string
Rules jsonutils.JSONObject
}
const (
DEFAULT_ONECLOUD_MAPPING = "yunion-onecloud-mapping"
)
var (
onecloudMappingRules = jsonutils.Marshal(map[string]interface{}{
"rules": []map[string]interface{}{
{
"remote": []map[string]interface{}{
{
"type": "User",
},
{
"type": "Groups",
},
},
"local": []map[string]interface{}{
{
"groups": "{1}",
"user": map[string]string{"name": "{0}"},
},
},
},
},
})
)
func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) {
client, err := self.newGeneralAPIClient()
if err != nil {
return nil, errors.Wrap(err, "newGeneralAPIClient")
}
mappings := []SAMLProviderMapping{}
err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings)
if err != nil {
return nil, err
}
return mappings, nil
}
func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error {
client, err := self.newGeneralAPIClient()
if err != nil {
return errors.Wrap(err, "newGeneralAPIClient")
}
mappings, err := self.ListSAMLProviderMappings()
if err != nil {
return errors.Wrapf(err, "ListSAMLProviderMappings")
}
params := map[string]interface{}{
"mapping": onecloudMappingRules,
}
find := false
for i := range mappings {
if mappings[i].Id == DEFAULT_ONECLOUD_MAPPING {
find = true
}
}
if !find {
_, err = client.SAMLProviderMappings.Update(DEFAULT_ONECLOUD_MAPPING, jsonutils.Marshal(params))
if err != nil {
return errors.Wrapf(err, "create mapping")
}
}
protocols, err := self.GetSAMLProviderProtocols(spId)
if err != nil {
return errors.Wrapf(err, "GetSAMLProviderProtocols")
}
params = map[string]interface{}{
"protocol": map[string]string{
"mapping_id": DEFAULT_ONECLOUD_MAPPING,
},
}
for i := range protocols {
if protocols[i].Id == "saml" {
if protocols[i].MappingId == DEFAULT_ONECLOUD_MAPPING {
return nil
}
_, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "")
return err
}
}
_, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "")
return err
}
@@ -0,0 +1,89 @@
// 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 shell
import (
"yunion.io/x/onecloud/pkg/multicloud/huawei"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SAMLProviderListOptions struct {
}
shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *huawei.SRegion, args *SAMLProviderListOptions) error {
result, err := cli.GetClient().ListSAMLProviders()
if err != nil {
return err
}
printList(result, 0, 0, 0, nil)
return nil
})
type SAMLProviderIdOptions struct {
ID string
}
shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error {
return cli.GetClient().DeleteSAMLProvider(args.ID)
})
shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-protocol-list", "List saml provider protocol", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error {
result, err := cli.GetClient().GetSAMLProviderProtocols(args.ID)
if err != nil {
return err
}
printList(result, 0, 0, 0, nil)
return nil
})
shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-metadata-show", "Show saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error {
result, err := cli.GetClient().GetSAMLProviderMetadata(args.ID)
if err != nil {
return err
}
printObject(result)
return nil
})
type SAMLProviderMetadataOptions struct {
ID string
METADATA string
}
shellutils.R(&SAMLProviderMetadataOptions{}, "saml-provider-metadata-update", "Update saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderMetadataOptions) error {
return cli.GetClient().UpdateSAMLProviderMetadata(args.ID, args.METADATA)
})
type MappingListOptions struct {
}
shellutils.R(&MappingListOptions{}, "saml-provider-mapping-list", "List saml provider mapping", func(cli *huawei.SRegion, args *MappingListOptions) error {
mappings, err := cli.GetClient().ListSAMLProviderMappings()
if err != nil {
return err
}
printList(mappings, 0, 0, 0, nil)
return nil
})
type MappingInitOptions struct {
SAML_PROVIDER string
}
shellutils.R(&MappingInitOptions{}, "saml-provider-mapping-init", "Init saml provider mapping", func(cli *huawei.SRegion, args *MappingInitOptions) error {
return cli.GetClient().InitSAMLProviderMapping(args.SAML_PROVIDER)
})
}
+116 -2
View File
@@ -16,9 +16,15 @@ package qcloud
import (
"fmt"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
const (
@@ -37,7 +43,18 @@ const (
"UpdateTime": "2020-08-11 17:03:30"
*/
type SPrincipal struct {
Federated []string
}
type Statement struct {
Action string
Effect string
Principal SPrincipal
}
type SRole struct {
multicloud.SResourceBase
client *SQcloudClient
AddTime time.Time
@@ -51,6 +68,92 @@ type SRole struct {
UpdateTime time.Time
}
func (self *SRole) GetGlobalId() string {
return self.RoleName
}
func (self *SRole) GetName() string {
return self.RoleName
}
func (self *SRole) GetDocument() *jsonutils.JSONDict {
if len(self.PolicyDocument) > 0 {
document, err := jsonutils.Parse([]byte(self.PolicyDocument))
if err != nil {
return nil
}
return document.(*jsonutils.JSONDict)
}
return nil
}
func (self *SRole) GetSAMLProvider() string {
document := self.GetDocument()
if document != nil {
statements := []Statement{}
document.Unmarshal(&statements, "statement")
for i := range statements {
if statements[i].Action == "name/sts:AssumeRoleWithSAML" {
for _, federated := range statements[i].Principal.Federated {
if strings.Contains(federated, ":saml-provider/") {
info := strings.Split(federated, "/")
return info[len(info)-1]
}
}
}
}
}
return ""
}
func (self *SRole) Delete() error {
return self.client.DeleteRole(self.RoleName)
}
func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
ret := []cloudprovider.ICloudpolicy{}
for {
part, total, err := self.client.ListAttachedRolePolicies(self.RoleName, "", len(ret), 50)
if err != nil {
return nil, errors.Wrapf(err, "ListAttachedRolePolicies")
}
for i := range part {
part[i].client = self.client
ret = append(ret, &part[i])
}
if len(ret) >= total {
break
}
}
return ret, nil
}
func (self *SRole) AttachPolicy(id string) error {
return self.client.AttachRolePolicy(self.RoleName, id)
}
func (self *SRole) DetachPolicy(id string) error {
return self.client.DetachRolePolicy(self.RoleName, id)
}
func (self *SQcloudClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
ret := []cloudprovider.ICloudrole{}
for {
part, total, err := self.DescribeRoleList(len(ret), 200)
if err != nil {
return nil, errors.Wrapf(err, "DescribeRoleList")
}
for i := range part {
part[i].client = self
ret = append(ret, &part[i])
}
if len(ret) >= total {
break
}
}
return ret, nil
}
func (self *SQcloudClient) DescribeRoleList(offset int, limit int) ([]SRole, int, error) {
if limit < 1 || limit > 200 {
limit = 200
@@ -76,6 +179,9 @@ func (self *SQcloudClient) DescribeRoleList(offset int, limit int) ([]SRole, int
}
func (self *SQcloudClient) CreateRole(name, document, desc string) (*SRole, error) {
if len(document) == 0 {
document = DEFAULT_ROLE_DOCUMENT
}
params := map[string]string{
"RoleName": name,
"PolicyDocument": document,
@@ -145,7 +251,11 @@ func (self *SQcloudClient) DeleteRole(name string) error {
func (self *SQcloudClient) AttachRolePolicy(roleName string, policyId string) error {
params := map[string]string{
"AttachRoleName": roleName,
"PolicyId": policyId,
}
if _id, _ := strconv.Atoi(policyId); _id > 0 {
params["PolicyId"] = policyId
} else {
params["PolicyName"] = policyId
}
_, err := self.camRequest("AttachRolePolicy", params)
return err
@@ -154,7 +264,11 @@ func (self *SQcloudClient) AttachRolePolicy(roleName string, policyId string) er
func (self *SQcloudClient) DetachRolePolicy(roleName string, policyId string) error {
params := map[string]string{
"DetachRoleName": roleName,
"PolicyId": policyId,
}
if _id, _ := strconv.Atoi(policyId); _id > 0 {
params["PolicyId"] = policyId
} else {
params["PolicyName"] = policyId
}
_, err := self.camRequest("DetachRolePolicy", params)
return err
+2 -2
View File
@@ -55,7 +55,7 @@ func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, erro
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
if policies[i].PolicyType == "QCS" {
if policies[i].PolicyType == "QCS" || policies[i].PolicyType == "" {
policies[i].client = user.client
ret = append(ret, &policies[i])
}
@@ -79,7 +79,7 @@ func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, erro
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
if policies[i].PolicyType != "QCS" {
if policies[i].PolicyType == "User" {
policies[i].client = user.client
ret = append(ret, &policies[i])
}
+46 -4
View File
@@ -370,16 +370,58 @@ func (self *SQcloudProvider) GetSamlEntityId() string {
return cloudprovider.SAML_ENTITY_ID_QCLOUD
}
func (self *SQcloudProvider) GetSamlSpInitiatedLoginUrl(idpName string) string {
return self.client.GetSamlSpInitiatedLoginUrl(idpName)
}
func (self *SQcloudProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) {
return self.client.GetICloudDnsZones()
}
func (self *SQcloudProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) {
return self.client.GetDomainById(id)
}
func (self *SQcloudProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) {
return self.client.CreateICloudDnsZone(opts)
}
func (self *SQcloudProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) {
saml, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "")
if err != nil {
return nil, errors.Wrap(err, "CreateSAMLProvider")
}
return saml, nil
}
func (self *SQcloudProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
return self.client.GetICloudSAMLProviders()
}
func (self *SQcloudProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) {
if len(opts.SAMLProvider) > 0 {
document := fmt.Sprintf(`{"version":"2.0","statement":[{"action":"name/sts:AssumeRoleWithSAML","effect":"allow","principal":{"federated":["qcs::cam::uin/%s:saml-provider/%s"]},"condition":{}}]}`, self.client.GetAccountId(), opts.SAMLProvider)
role, err := self.client.CreateRole(opts.Name, document, opts.Desc)
if err != nil {
return nil, errors.Wrapf(err, "CreateRole")
}
return role, nil
}
role, err := self.client.CreateRole(opts.Name, "", opts.Desc)
if err != nil {
return nil, errors.Wrapf(err, "")
}
return role, nil
}
func (self *SQcloudProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
return self.client.GetICloudroles()
}
func (self *SQcloudProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) {
role, err := self.client.GetRole(name)
if err != nil {
return nil, errors.Wrapf(err, "GetRole(%s)", name)
}
return role, nil
}
func (self *SQcloudProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) {
return self.GetICloudroleByName(id)
}
-4
View File
@@ -955,7 +955,3 @@ func (self *SQcloudClient) GetCapabilities() []string {
}
return caps
}
func (self *SQcloudClient) GetSamlSpInitiatedLoginUrl(idpName string) string {
return fmt.Sprintf("https://cloud.tencent.com/login/forwardIdp/%s/%s", self.ownerName, idpName)
}
+179
View File
@@ -0,0 +1,179 @@
// 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 qcloud
import (
"encoding/base64"
"fmt"
"time"
"unicode"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/samlutils"
)
type SAMLProvider struct {
multicloud.SResourceBase
client *SQcloudClient
Name string
Description string
CreateTime time.Time
ModifyTime time.Time
SAMLMetadata string
}
func (self *SAMLProvider) GetId() string {
return self.Name
}
func (self *SAMLProvider) GetGlobalId() string {
return self.Name
}
func (self *SAMLProvider) GetName() string {
return self.Name
}
func (self *SAMLProvider) GetStatus() string {
return api.SAML_PROVIDER_STATUS_AVAILABLE
}
func (self *SAMLProvider) Delete() error {
return self.client.DeleteSAMLProvider(self.Name)
}
func (self *SAMLProvider) GetAuthUrl() string {
return fmt.Sprintf("https://cloud.tencent.com/login/forwardIdp/%s/%s", self.client.ownerName, self.Name)
}
func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) {
provider, err := self.client.GetSAMLProvider(self.Name)
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Name)
}
metadata, err := base64.StdEncoding.DecodeString(provider.SAMLMetadata)
if err != nil {
return nil, errors.Wrapf(err, "decode metadata")
}
ret, err := samlutils.ParseMetadata(metadata)
if err != nil {
return nil, errors.Wrapf(err, "ParseMetadata")
}
return &ret, nil
}
func (self *SQcloudClient) ListSAMLProviders() ([]SAMLProvider, error) {
resp, err := self.camRequest("ListSAMLProviders", nil)
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
result := []SAMLProvider{}
err = resp.Unmarshal(&result, "SAMLProviderSet")
if err != nil {
return nil, errors.Wrapf(err, "Unmarshal")
}
return result, nil
}
func (self *SQcloudClient) CreateSAMLProvider(name, metadata, desc string) (*SAMLProvider, error) {
if len(desc) == 0 {
desc = "For CloudId Service"
}
//支持3-128个数字、大小写字母、和+=,.@_-
name = func() string {
ret := ""
for _, c := range name {
if unicode.IsLetter(c) || unicode.IsNumber(c) ||
c == '+' || c == '=' || c == ',' || c == '.' || c == '@' || c == '_' || c == '-' {
ret += string(c)
} else {
ret += "-"
}
}
return ret
}()
if len(name) > 128 {
name = name[:128]
}
params := map[string]string{
"Name": name,
"Description": desc,
"SAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)),
}
_, err := self.camRequest("CreateSAMLProvider", params)
if err != nil {
return nil, errors.Wrapf(err, "CreateSAMLProvider")
}
return self.GetSAMLProvider(name)
}
func (self *SQcloudClient) GetSAMLProvider(name string) (*SAMLProvider, error) {
params := map[string]string{
"Name": name,
}
resp, err := self.camRequest("GetSAMLProvider", params)
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProvider")
}
result := &SAMLProvider{client: self}
err = resp.Unmarshal(result)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return result, nil
}
func (self *SQcloudClient) DeleteSAMLProvider(name string) error {
params := map[string]string{
"Name": name,
}
_, err := self.camRequest("DeleteSAMLProvider", params)
return err
}
func (self *SQcloudClient) UpdateSAMLProvider(name, metadata, desc string) error {
params := map[string]string{
"Name": name,
}
if len(desc) > 0 {
params["Description"] = desc
}
if len(metadata) > 0 {
params["SAMLMetadataDocument"] = base64.StdEncoding.EncodeToString([]byte(metadata))
}
_, err := self.camRequest("UpdateSAMLProvider", params)
if err != nil {
return errors.Wrap(err, "UpdateSAMLProvider")
}
return nil
}
func (self *SQcloudClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
providers, err := self.ListSAMLProviders()
if err != nil {
return nil, errors.Wrapf(err, "ListSAMLProviders")
}
ret := []cloudprovider.ICloudSAMLProvider{}
for i := range providers {
providers[i].client = self
ret = append(ret, &providers[i])
}
return ret, nil
}
@@ -0,0 +1,76 @@
// 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 shell
import (
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SAMLProviderListOptions struct {
}
shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *qcloud.SRegion, args *SAMLProviderListOptions) error {
result, err := cli.GetClient().ListSAMLProviders()
if err != nil {
return err
}
printList(result, 0, 0, 0, nil)
return nil
})
type SAMLProviderCreateOptions struct {
NAME string
Desc string
METADATA string
}
shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *qcloud.SRegion, args *SAMLProviderCreateOptions) error {
result, err := cli.GetClient().CreateSAMLProvider(args.NAME, args.METADATA, args.Desc)
if err != nil {
return err
}
printObject(result)
return nil
})
type SAMLProviderNameOptions struct {
NAME string
}
shellutils.R(&SAMLProviderNameOptions{}, "saml-provider-show", "Show saml provider", func(cli *qcloud.SRegion, args *SAMLProviderNameOptions) error {
result, err := cli.GetClient().GetSAMLProvider(args.NAME)
if err != nil {
return err
}
printObject(result)
return nil
})
shellutils.R(&SAMLProviderNameOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *qcloud.SRegion, args *SAMLProviderNameOptions) error {
return cli.GetClient().DeleteSAMLProvider(args.NAME)
})
type SAMLProviderUpdateOptions struct {
NAME string
Desc string
Metadata string
}
shellutils.R(&SAMLProviderUpdateOptions{}, "saml-provider-update", "Update saml provider", func(cli *qcloud.SRegion, args *SAMLProviderUpdateOptions) error {
return cli.GetClient().UpdateSAMLProvider(args.NAME, args.Metadata, args.Desc)
})
}
+7 -3
View File
@@ -83,7 +83,11 @@ func (idp *SSAMLIdpInstance) AddHandlers(app *appsrv.Application, prefix string,
handler = middleware(handler)
}
app.AddHandler("GET", idp.redirectLogoutPath, handler)
app.AddHandler("GET", idp.idpInitiatedSSOPath, idp.idpInitiatedSSOHandler)
handler = idp.idpInitiatedSSOHandler
if middleware != nil {
handler = middleware(handler)
}
app.AddHandler("GET", idp.idpInitiatedSSOPath, handler)
log.Infof("IDP metadata: %s", idp.getMetadataUrl(IDP_ID_KEY))
log.Infof("IDP redirect login: %s", idp.getRedirectLoginUrl(IDP_ID_KEY))
@@ -141,7 +145,7 @@ func (idp *SSAMLIdpInstance) getIdpInitiatedSSOUrl() string {
func (idp *SSAMLIdpInstance) metadataHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params := appctx.AppContextParams(ctx)
idpId := params[IDP_ID_KEY]
desc := idp.getMetadata(idpId)
desc := idp.GetMetadata(idpId)
appsrv.SendXmlWithIndent(w, nil, desc, true)
}
@@ -187,7 +191,7 @@ func (idp *SSAMLIdpInstance) idpInitiatedSSOHandler(ctx context.Context, w http.
appsrv.SendHTML(w, respHtml)
}
func (idp *SSAMLIdpInstance) getMetadata(idpId string) samlutils.EntityDescriptor {
func (idp *SSAMLIdpInstance) GetMetadata(idpId string) samlutils.EntityDescriptor {
input := samlutils.SSAMLIdpMetadataInput{
EntityId: idp.saml.GetEntityId(),
CertString: idp.saml.GetCertString(),
+1 -1
View File
@@ -37,7 +37,7 @@ func NewSAMLIdp(entityId, redirectSsoUrl string) *SSAMLIdentityProvider {
func NewSAMLIdpFromDescriptor(desc samlutils.EntityDescriptor) (*SSAMLIdentityProvider, error) {
entityId := desc.EntityId
if desc.IDPSSODescriptor != nil {
if desc.IDPSSODescriptor == nil {
return nil, errors.Wrap(httperrors.ErrInputParameter, "missing IDPSSODescriptor")
}
redirectSsoUrl := findSSOUrl(desc, samlutils.BINDING_HTTP_REDIRECT)

Some files were not shown because too many files have changed in this diff Show More