saml_provider.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "strings"
  18. "yunion.io/x/cloudmux/pkg/cloudprovider"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/compare"
  22. "yunion.io/x/pkg/util/samlutils"
  23. "yunion.io/x/sqlchemy"
  24. "yunion.io/x/onecloud/pkg/apis"
  25. api "yunion.io/x/onecloud/pkg/apis/cloudid"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  28. "yunion.io/x/onecloud/pkg/cloudid/options"
  29. "yunion.io/x/onecloud/pkg/mcclient"
  30. "yunion.io/x/onecloud/pkg/util/stringutils2"
  31. )
  32. type SSAMLProviderManager struct {
  33. db.SStatusInfrasResourceBaseManager
  34. db.SExternalizedResourceBaseManager
  35. SCloudaccountResourceBaseManager
  36. SCloudproviderResourceBaseManager
  37. }
  38. var SAMLProviderManager *SSAMLProviderManager
  39. func init() {
  40. SAMLProviderManager = &SSAMLProviderManager{
  41. SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
  42. SSAMLProvider{},
  43. "saml_provider_tbl",
  44. "saml_provider",
  45. "saml_providers",
  46. ),
  47. }
  48. SAMLProviderManager.SetVirtualObject(SAMLProviderManager)
  49. }
  50. type SSAMLProvider struct {
  51. db.SStatusInfrasResourceBase
  52. db.SExternalizedResourceBase
  53. SCloudaccountResourceBase
  54. SCloudproviderResourceBase
  55. EntityId string `get:"domain" create:"domain_optional" list:"domain"`
  56. MetadataDocument string `get:"domain" create:"domain_optional"`
  57. AuthUrl string `width:"512" charset:"ascii" get:"domain" list:"domain"`
  58. }
  59. func (manager *SSAMLProviderManager) GetIVirtualModelManager() db.IVirtualModelManager {
  60. return manager.GetVirtualObject().(db.IVirtualModelManager)
  61. }
  62. func (manager *SSAMLProviderManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
  63. return nil, nil
  64. }
  65. func (manager *SSAMLProviderManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
  66. accountId, _ := data.GetString("cloudaccount_id")
  67. return jsonutils.Marshal(map[string]string{"cloudaccount_id": accountId})
  68. }
  69. func (manager *SSAMLProviderManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
  70. accountId, _ := values.GetString("cloudaccount_id")
  71. if len(accountId) > 0 {
  72. q = q.Equals("cloudaccount_id", accountId)
  73. }
  74. return q
  75. }
  76. func (self *SSAMLProvider) GetCloudprovider() (*SCloudprovider, error) {
  77. provider, err := CloudproviderManager.FetchById(self.ManagerId)
  78. if err != nil {
  79. return nil, errors.Wrapf(err, "CloudproviderManager.FetchById(%s)", self.ManagerId)
  80. }
  81. return provider.(*SCloudprovider), nil
  82. }
  83. func (self *SSAMLProvider) GetProvider() (cloudprovider.ICloudProvider, error) {
  84. if len(self.ManagerId) > 0 {
  85. provider, err := self.GetCloudprovider()
  86. if err != nil {
  87. return nil, errors.Wrap(err, "GetCloudprovider")
  88. }
  89. return provider.GetProvider()
  90. }
  91. account, err := self.GetCloudaccount()
  92. if err != nil {
  93. return nil, errors.Wrap(err, "GetCloudaccount")
  94. }
  95. return account.GetProvider()
  96. }
  97. // 公有云身份提供商列表
  98. func (manager *SSAMLProviderManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SAMLProviderListInput) (*sqlchemy.SQuery, error) {
  99. var err error
  100. q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
  101. if err != nil {
  102. return nil, err
  103. }
  104. q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
  105. if err != nil {
  106. return nil, err
  107. }
  108. q, err = manager.SCloudproviderResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudproviderResourceListInput)
  109. if err != nil {
  110. return nil, err
  111. }
  112. return q, nil
  113. }
  114. // 删除
  115. func (self *SSAMLProvider) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  116. params := jsonutils.NewDict()
  117. return self.StartSAMLProviderDeleteTask(ctx, userCred, params, "")
  118. }
  119. func (self *SSAMLProvider) StartSAMLProviderDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
  120. task, err := taskman.TaskManager.NewTask(ctx, "SAMLProviderDeleteTask", self, userCred, data, parentTaskId, "", nil)
  121. if err != nil {
  122. return errors.Wrap(err, "NewTask")
  123. }
  124. self.SetStatus(ctx, userCred, apis.STATUS_DELETING, "")
  125. return task.ScheduleRun(nil)
  126. }
  127. func (self *SSAMLProvider) GetISAMLProvider() (cloudprovider.ICloudSAMLProvider, error) {
  128. if len(self.ExternalId) == 0 {
  129. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  130. }
  131. provider, err := self.GetProvider()
  132. if err != nil {
  133. return nil, err
  134. }
  135. samlProviders, err := provider.GetICloudSAMLProviders()
  136. if err != nil {
  137. return nil, err
  138. }
  139. for i := range samlProviders {
  140. if samlProviders[i].GetGlobalId() == self.ExternalId {
  141. return samlProviders[i], nil
  142. }
  143. }
  144. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%v", self.ExternalId)
  145. }
  146. func (self *SSAMLProvider) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  147. return nil
  148. }
  149. func (self *SSAMLProvider) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  150. return self.SStatusInfrasResourceBase.Delete(ctx, userCred)
  151. }
  152. func (self *SSAMLProvider) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
  153. return self.RealDelete(ctx, userCred)
  154. }
  155. func (self *SSAMLProvider) SyncWithCloudSAMLProvider(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSAMLProvider, managerId string) error {
  156. _, err := db.Update(self, func() error {
  157. self.ExternalId = ext.GetGlobalId()
  158. self.AuthUrl = ext.GetAuthUrl(options.Options.ApiServer)
  159. metadata, _ := ext.GetMetadataDocument()
  160. if metadata != nil {
  161. self.EntityId = metadata.EntityId
  162. self.MetadataDocument = metadata.String()
  163. }
  164. self.Status = apis.STATUS_UNKNOWN
  165. if self.EntityId == options.Options.ApiServer && strings.Contains(self.MetadataDocument, "login/"+self.ManagerId) {
  166. self.Status = apis.STATUS_AVAILABLE
  167. }
  168. if len(managerId) > 0 {
  169. self.ManagerId = managerId
  170. }
  171. return nil
  172. })
  173. return err
  174. }
  175. func (self *SSAMLProvider) GetMetadataDocument() (samlutils.EntityDescriptor, error) {
  176. return samlutils.ParseMetadata([]byte(self.MetadataDocument))
  177. }
  178. func (manager *SSAMLProviderManager) FetchCustomizeColumns(
  179. ctx context.Context,
  180. userCred mcclient.TokenCredential,
  181. query jsonutils.JSONObject,
  182. objs []interface{},
  183. fields stringutils2.SSortedStrings,
  184. isList bool,
  185. ) []api.SAMLProviderDetails {
  186. rows := make([]api.SAMLProviderDetails, len(objs))
  187. infRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  188. acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  189. for i := range rows {
  190. rows[i] = api.SAMLProviderDetails{
  191. StatusInfrasResourceBaseDetails: infRows[i],
  192. CloudaccountResourceDetails: acRows[i],
  193. }
  194. }
  195. return rows
  196. }
  197. func (self *SCloudaccount) SyncSAMLProviders(ctx context.Context, userCred mcclient.TokenCredential, samls []cloudprovider.ICloudSAMLProvider, managerId string) compare.SyncResult {
  198. result := compare.SyncResult{}
  199. dbSamls, err := self.GetSAMLProviders(managerId)
  200. if err != nil {
  201. result.Error(errors.Wrap(err, "GetSAMLProviders"))
  202. return result
  203. }
  204. removed := make([]SSAMLProvider, 0)
  205. commondb := make([]SSAMLProvider, 0)
  206. commonext := make([]cloudprovider.ICloudSAMLProvider, 0)
  207. added := make([]cloudprovider.ICloudSAMLProvider, 0)
  208. err = compare.CompareSets(dbSamls, samls, &removed, &commondb, &commonext, &added)
  209. if err != nil {
  210. result.Error(errors.Wrap(err, "compare.CompareSets"))
  211. return result
  212. }
  213. for i := 0; i < len(removed); i++ {
  214. err = removed[i].RealDelete(ctx, userCred)
  215. if err != nil {
  216. result.DeleteError(err)
  217. continue
  218. }
  219. result.Delete()
  220. }
  221. for i := 0; i < len(commondb); i++ {
  222. err = commondb[i].SyncWithCloudSAMLProvider(ctx, userCred, commonext[i], managerId)
  223. if err != nil {
  224. result.UpdateError(err)
  225. continue
  226. }
  227. result.Update()
  228. }
  229. for i := 0; i < len(added); i++ {
  230. err = self.newFromCloudSAMLProvider(ctx, userCred, added[i], managerId)
  231. if err != nil {
  232. result.AddError(err)
  233. continue
  234. }
  235. result.Add()
  236. }
  237. return result
  238. }
  239. func (self *SCloudaccount) newFromCloudSAMLProvider(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSAMLProvider, managerId string) error {
  240. saml := &SSAMLProvider{}
  241. saml.SetModelManager(SAMLProviderManager, saml)
  242. saml.Name = ext.GetName()
  243. saml.ExternalId = ext.GetGlobalId()
  244. saml.DomainId = self.DomainId
  245. saml.CloudaccountId = self.Id
  246. saml.ManagerId = managerId
  247. saml.AuthUrl = ext.GetAuthUrl(options.Options.ApiServer)
  248. metadata, _ := ext.GetMetadataDocument()
  249. if metadata != nil {
  250. saml.EntityId = metadata.EntityId
  251. saml.MetadataDocument = metadata.String()
  252. }
  253. saml.Status = ext.GetStatus()
  254. saml.Status = apis.STATUS_UNKNOWN
  255. if saml.EntityId == options.Options.ApiServer && strings.Contains(saml.MetadataDocument, "login/"+saml.ManagerId) {
  256. saml.Status = apis.STATUS_AVAILABLE
  257. }
  258. return SAMLProviderManager.TableSpec().Insert(ctx, saml)
  259. }
  260. func (self *SCloudprovider) GetSamlProviders() ([]SSAMLProvider, error) {
  261. q := SAMLProviderManager.Query().Equals("manager_id", self.Id)
  262. ret := []SSAMLProvider{}
  263. err := db.FetchModelObjects(SAMLProviderManager, q, &ret)
  264. if err != nil {
  265. return nil, err
  266. }
  267. return ret, nil
  268. }