Files
cloudpods/pkg/cloudid/models/saml_provider.go
T

305 lines
9.8 KiB
Go

// 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/cloudmux/pkg/cloudprovider"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/samlutils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
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/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SSAMLProviderManager struct {
db.SStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudaccountResourceBaseManager
SCloudproviderResourceBaseManager
}
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
SCloudproviderResourceBase
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 (self *SSAMLProvider) GetCloudprovider() (*SCloudprovider, error) {
provider, err := CloudproviderManager.FetchById(self.ManagerId)
if err != nil {
return nil, errors.Wrapf(err, "CloudproviderManager.FetchById(%s)", self.ManagerId)
}
return provider.(*SCloudprovider), nil
}
func (self *SSAMLProvider) GetProvider() (cloudprovider.ICloudProvider, error) {
if len(self.ManagerId) > 0 {
provider, err := self.GetCloudprovider()
if err != nil {
return nil, errors.Wrap(err, "GetCloudprovider")
}
return provider.GetProvider()
}
account, err := self.GetCloudaccount()
if err != nil {
return nil, errors.Wrap(err, "GetCloudaccount")
}
return account.GetProvider()
}
// 公有云身份提供商列表
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
}
q, err = manager.SCloudproviderResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudproviderResourceListInput)
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) 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(ctx, userCred, apis.STATUS_DELETING, "")
return task.ScheduleRun(nil)
}
func (self *SSAMLProvider) GetISAMLProvider() (cloudprovider.ICloudSAMLProvider, error) {
if len(self.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
}
provider, err := self.GetProvider()
if err != nil {
return nil, err
}
samlProviders, err := provider.GetICloudSAMLProviders()
if err != nil {
return nil, err
}
for i := range samlProviders {
if samlProviders[i].GetGlobalId() == self.ExternalId {
return samlProviders[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, self.ExternalId)
}
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) 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, managerId string) error {
_, err := db.Update(self, func() error {
self.ExternalId = ext.GetGlobalId()
self.AuthUrl = ext.GetAuthUrl(options.Options.ApiServer)
metadata, _ := ext.GetMetadataDocument()
if metadata != nil {
self.EntityId = metadata.EntityId
self.MetadataDocument = metadata.String()
}
self.Status = apis.STATUS_UNKNOWN
if self.EntityId == options.Options.ApiServer && strings.Contains(self.MetadataDocument, "login/"+self.ManagerId) {
self.Status = apis.STATUS_AVAILABLE
}
if len(managerId) > 0 {
self.ManagerId = managerId
}
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
}
func (self *SCloudaccount) SyncSAMLProviders(ctx context.Context, userCred mcclient.TokenCredential, samls []cloudprovider.ICloudSAMLProvider, managerId string) compare.SyncResult {
result := compare.SyncResult{}
dbSamls, err := self.GetSAMLProviders(managerId)
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], managerId)
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i++ {
err = self.newFromCloudSAMLProvider(ctx, userCred, added[i], managerId)
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SCloudaccount) newFromCloudSAMLProvider(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSAMLProvider, managerId string) error {
saml := &SSAMLProvider{}
saml.SetModelManager(SAMLProviderManager, saml)
saml.Name = ext.GetName()
saml.ExternalId = ext.GetGlobalId()
saml.DomainId = self.DomainId
saml.CloudaccountId = self.Id
saml.ManagerId = managerId
saml.AuthUrl = ext.GetAuthUrl(options.Options.ApiServer)
metadata, _ := ext.GetMetadataDocument()
if metadata != nil {
saml.EntityId = metadata.EntityId
saml.MetadataDocument = metadata.String()
}
saml.Status = ext.GetStatus()
saml.Status = apis.STATUS_UNKNOWN
if saml.EntityId == options.Options.ApiServer && strings.Contains(saml.MetadataDocument, "login/"+saml.ManagerId) {
saml.Status = apis.STATUS_AVAILABLE
}
return SAMLProviderManager.TableSpec().Insert(ctx, saml)
}
func (self *SCloudprovider) GetSamlProviders() ([]SSAMLProvider, error) {
q := SAMLProviderManager.Query().Equals("manager_id", self.Id)
ret := []SSAMLProvider{}
err := db.FetchModelObjects(SAMLProviderManager, q, &ret)
if err != nil {
return nil, err
}
return ret, nil
}