yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/azure/saml_provider.go (about) 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 15 package azure 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/pkg/errors" 24 25 "yunion.io/x/cloudmux/pkg/apis/cloudid" 26 api "yunion.io/x/cloudmux/pkg/apis/cloudid" 27 compute_api "yunion.io/x/cloudmux/pkg/apis/compute" 28 "yunion.io/x/onecloud/pkg/cloudid/options" 29 "yunion.io/x/cloudmux/pkg/cloudprovider" 30 "yunion.io/x/cloudmux/pkg/multicloud" 31 "yunion.io/x/onecloud/pkg/util/httputils" 32 "yunion.io/x/onecloud/pkg/util/samlutils" 33 ) 34 35 type SAMLProvider struct { 36 multicloud.SResourceBase 37 AzureTags 38 client *SAzureClient 39 40 Name string 41 Metadata samlutils.EntityDescriptor 42 } 43 44 func (self *SAMLProvider) Delete() error { 45 return nil 46 } 47 48 func (self *SAMLProvider) GetGlobalId() string { 49 return strings.TrimPrefix(options.Options.ApiServer, "https://") 50 } 51 52 func (self *SAMLProvider) GetId() string { 53 return options.Options.ApiServer 54 } 55 56 func (self *SAMLProvider) GetName() string { 57 return self.Name 58 } 59 60 func (self *SAMLProvider) GetStatus() string { 61 return api.SAML_PROVIDER_STATUS_AVAILABLE 62 } 63 64 func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { 65 return nil 66 } 67 68 func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { 69 return &self.Metadata, nil 70 } 71 72 func (self *SAMLProvider) GetAuthUrl() string { 73 input := samlutils.SIdpInitiatedLoginInput{ 74 EntityID: cloudprovider.SAML_ENTITY_ID_AZURE, 75 IdpId: self.client.cpcfg.AccountId, 76 } 77 if self.client.GetAccessEnv() != compute_api.CLOUD_ACCESS_ENV_AZURE_GLOBAL { 78 return "" 79 } 80 return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) 81 } 82 83 func (self *SAzureClient) ListSAMLProviders() ([]SAMLProvider, error) { 84 _, err := self.msGraphRequest("GET", "identityProviders", nil) 85 if err != nil { 86 return nil, err 87 } 88 return []SAMLProvider{}, nil 89 } 90 91 func (self *SAzureClient) InviteUser(email string) (*SClouduser, error) { 92 body := jsonutils.Marshal(map[string]string{ 93 "invitedUserEmailAddress": email, 94 "inviteRedirectUrl": fmt.Sprintf("https://portal.azure.com/%s?login_hint=%s", self.tenantId, email), 95 }) 96 resp, err := self.msGraphRequest("POST", "invitations", body) 97 if err != nil { 98 return nil, errors.Wrapf(err, "msGraphRequest.invitations") 99 } 100 inviteUrl, _ := resp.GetString("inviteRedeemUrl") 101 err = cloudprovider.Wait(time.Second*2, time.Minute, func() (bool, error) { 102 users, err := self.ListGraphUsers() 103 if err != nil { 104 return false, errors.Wrapf(err, "GetCloudusers") 105 } 106 for i := range users { 107 users[i].inviteRedeemUrl = inviteUrl 108 if users[i].GetEmailAddr() == email { 109 return true, nil 110 } 111 } 112 return false, nil 113 }) 114 if err != nil { 115 return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) 116 } 117 users, err := self.ListGraphUsers() 118 if err != nil { 119 return nil, errors.Wrapf(err, "GetCloudusers") 120 } 121 for i := range users { 122 users[i].inviteRedeemUrl = inviteUrl 123 if users[i].GetEmailAddr() == email { 124 return &users[i], nil 125 } 126 } 127 128 return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) 129 } 130 131 func (self *SAzureClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { 132 return &SAMLProvider{ 133 client: self, 134 Name: opts.Name, 135 Metadata: opts.Metadata, 136 }, nil 137 }