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  }