mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
feature: saml for cloudid
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -12,7 +12,31 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package providers
|
||||
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)
|
||||
@@ -12,19 +12,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package providers
|
||||
package models
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/util/samlutils"
|
||||
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
|
||||
)
|
||||
import "yunion.io/x/pkg/errors"
|
||||
|
||||
type ICloudSAMLLoginDriver interface {
|
||||
GetEntityID() string
|
||||
type SAMLProviderResourceBaseManager struct {
|
||||
}
|
||||
|
||||
GetMetadataFilename() string
|
||||
GetMetadataUrl() string
|
||||
type SAMLProviderResourceBase struct {
|
||||
SAMLProviderId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" json:"saml_provider_id"`
|
||||
}
|
||||
|
||||
GetIdpInitiatedLoginData(idpId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLIdpInitiatedLoginData, error)
|
||||
GetSpInitiatedLoginData(idpId string, userId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error)
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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 |<----------------------------------------------
|
||||
+------+
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user