yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/ram_user.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 aliyun
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"yunion.io/x/log"
    22  	"yunion.io/x/pkg/errors"
    23  
    24  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    25  	"yunion.io/x/cloudmux/pkg/multicloud"
    26  )
    27  
    28  type sUsers struct {
    29  	User []SUser
    30  }
    31  
    32  type SUsers struct {
    33  	Users       sUsers
    34  	Marker      string
    35  	IsTruncated bool
    36  }
    37  
    38  type SUser struct {
    39  	client *SAliyunClient
    40  	multicloud.SBaseClouduser
    41  
    42  	Comments    string
    43  	CreateDate  time.Time
    44  	DisplayName string
    45  	Email       string
    46  	MobilePhone string
    47  	UserId      string
    48  	UserName    string
    49  }
    50  
    51  func (user *SUser) GetGlobalId() string {
    52  	if len(user.UserId) > 0 {
    53  		return user.UserId
    54  	}
    55  	u, err := user.client.GetUser(user.UserName)
    56  	if err != nil {
    57  		return ""
    58  	}
    59  	return u.UserId
    60  }
    61  
    62  func (user *SUser) GetName() string {
    63  	return user.UserName
    64  }
    65  
    66  func (user *SUser) GetEmailAddr() string {
    67  	return user.Email
    68  }
    69  
    70  func (user *SUser) GetInviteUrl() string {
    71  	return ""
    72  }
    73  
    74  func (user *SUser) Delete() error {
    75  	groups, err := user.client.ListGroupsForUser(user.UserName)
    76  	if err != nil {
    77  		return errors.Wrap(err, "ListGroupsForUser")
    78  	}
    79  	for i := range groups {
    80  		err = user.client.RemoveUserFromGroup(groups[i].GroupName, user.UserName)
    81  		if err != nil {
    82  			return errors.Wrapf(err, "RemoveUserFromGroup %s > %s", groups[i].GroupName, user.UserName)
    83  		}
    84  	}
    85  	policies, err := user.client.ListPoliciesForUser(user.UserName)
    86  	if err != nil {
    87  		return errors.Wrap(err, "ListPoliciesForUser")
    88  	}
    89  	for i := range policies {
    90  		err = user.client.DetachPolicyFromUser(policies[i].PolicyName, policies[i].PolicyType, user.UserName)
    91  		if err != nil {
    92  			return errors.Wrapf(err, "DetachPolicyFromUser %s %s %s", policies[i].PolicyName, policies[i].PolicyType, user.UserName)
    93  		}
    94  	}
    95  	return user.client.DeleteClouduser(user.UserName)
    96  }
    97  
    98  func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) {
    99  	groups, err := user.client.ListGroupsForUser(user.UserName)
   100  	if err != nil {
   101  		return nil, errors.Wrapf(err, "ListGroupsForUser")
   102  	}
   103  	ret := []cloudprovider.ICloudgroup{}
   104  	for i := range groups {
   105  		groups[i].client = user.client
   106  		ret = append(ret, &groups[i])
   107  	}
   108  	return ret, nil
   109  }
   110  
   111  func (user *SUser) UpdatePassword(password string) error {
   112  	return user.client.UpdateLoginProfile(user.UserName, password)
   113  }
   114  
   115  func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
   116  	policies, err := user.client.ListPoliciesForUser(user.UserName)
   117  	if err != nil {
   118  		return nil, errors.Wrap(err, "ListPoliciesForUser")
   119  	}
   120  	ret := []cloudprovider.ICloudpolicy{}
   121  	for i := range policies {
   122  		if policies[i].PolicyType == "System" {
   123  			policies[i].client = user.client
   124  			ret = append(ret, &policies[i])
   125  		}
   126  	}
   127  	return ret, nil
   128  }
   129  
   130  func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
   131  	policies, err := user.client.ListPoliciesForUser(user.UserName)
   132  	if err != nil {
   133  		return nil, errors.Wrap(err, "ListPoliciesForUser")
   134  	}
   135  	ret := []cloudprovider.ICloudpolicy{}
   136  	for i := range policies {
   137  		if policies[i].PolicyType == "Custom" {
   138  			policies[i].client = user.client
   139  			ret = append(ret, &policies[i])
   140  		}
   141  	}
   142  	return ret, nil
   143  }
   144  
   145  func (user *SUser) IsConsoleLogin() bool {
   146  	_, err := user.client.GetLoginProfile(user.UserName)
   147  	if errors.Cause(err) == cloudprovider.ErrNotFound {
   148  		return false
   149  	}
   150  	return true
   151  }
   152  
   153  func (user *SUser) ResetPassword(password string) error {
   154  	return user.client.ResetClouduserPassword(user.UserName, password)
   155  }
   156  
   157  func (user *SUser) AttachSystemPolicy(policyName string) error {
   158  	return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_SYSTEM, user.UserName)
   159  }
   160  
   161  func (user *SUser) AttachCustomPolicy(policyName string) error {
   162  	return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_CUSTOM, user.UserName)
   163  }
   164  
   165  func (user *SUser) DetachSystemPolicy(policyName string) error {
   166  	return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_SYSTEM, user.UserName)
   167  }
   168  
   169  func (user *SUser) DetachCustomPolicy(policyName string) error {
   170  	return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_CUSTOM, user.UserName)
   171  }
   172  
   173  func (self *SAliyunClient) DeleteClouduser(name string) error {
   174  	params := map[string]string{
   175  		"UserName": name,
   176  	}
   177  	_, err := self.ramRequest("DeleteUser", params)
   178  	return err
   179  }
   180  
   181  func (self *SAliyunClient) CreateUser(name, phone, email, comments string) (*SUser, error) {
   182  	params := map[string]string{
   183  		"UserName":    name,
   184  		"DisplayName": name,
   185  	}
   186  	if len(phone) > 0 {
   187  		params["MobilePhone"] = phone
   188  	}
   189  	if len(email) > 0 {
   190  		params["Email"] = email
   191  	}
   192  	if len(comments) > 0 {
   193  		params["Comments"] = comments
   194  	}
   195  	resp, err := self.ramRequest("CreateUser", params)
   196  	if err != nil {
   197  		return nil, errors.Wrap(err, "ramRequest.CreateUser")
   198  	}
   199  
   200  	user := &SUser{client: self}
   201  	err = resp.Unmarshal(user, "User")
   202  	if err != nil {
   203  		return nil, errors.Wrap(err, "resp.Unmarshal")
   204  	}
   205  	return user, nil
   206  }
   207  
   208  func (self *SAliyunClient) ListUsers(offset string, limit int) (*SUsers, error) {
   209  	params := map[string]string{}
   210  	if len(offset) > 0 {
   211  		params["Marker"] = offset
   212  	}
   213  	if limit > 0 {
   214  		params["MaxItems"] = fmt.Sprintf("%d", limit)
   215  	}
   216  	resp, err := self.ramRequest("ListUsers", params)
   217  	if err != nil {
   218  		return nil, errors.Wrap(err, "ramRequest.ListUsers")
   219  	}
   220  	users := &SUsers{}
   221  	err = resp.Unmarshal(users)
   222  	if err != nil {
   223  		return nil, errors.Wrap(err, "resp.Unmarshal")
   224  	}
   225  	return users, nil
   226  }
   227  
   228  func (self *SAliyunClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) {
   229  	user, err := self.CreateUser(conf.Name, conf.MobilePhone, conf.Email, conf.Desc)
   230  	if err != nil {
   231  		return nil, errors.Wrap(err, "CreateUser")
   232  	}
   233  	if len(conf.Password) > 0 {
   234  		_, err := self.CreateLoginProfile(conf.Name, conf.Password)
   235  		if err != nil {
   236  			return nil, errors.Wrap(err, "CreateLoginProfile")
   237  		}
   238  	}
   239  	for _, policyId := range conf.ExternalPolicyIds {
   240  		err := user.AttachSystemPolicy(policyId)
   241  		if err != nil {
   242  			log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err)
   243  		}
   244  	}
   245  	return user, nil
   246  }
   247  
   248  func (self *SAliyunClient) GetICloudusers() ([]cloudprovider.IClouduser, error) {
   249  	ret := []cloudprovider.IClouduser{}
   250  	offset := ""
   251  	for {
   252  		part, err := self.ListUsers(offset, 100)
   253  		if err != nil {
   254  			return nil, errors.Wrap(err, "GetCloudusers")
   255  		}
   256  		for i := range part.Users.User {
   257  			part.Users.User[i].client = self
   258  			ret = append(ret, &part.Users.User[i])
   259  		}
   260  		offset = part.Marker
   261  		if len(offset) == 0 || !part.IsTruncated {
   262  			break
   263  		}
   264  	}
   265  	return ret, nil
   266  }
   267  
   268  func (self *SAliyunClient) GetUser(name string) (*SUser, error) {
   269  	params := map[string]string{
   270  		"UserName": name,
   271  	}
   272  	resp, err := self.ramRequest("GetUser", params)
   273  	if err != nil {
   274  		return nil, errors.Wrap(err, "ramRequest.CreateUser")
   275  	}
   276  	user := &SUser{client: self}
   277  	err = resp.Unmarshal(user, "User")
   278  	if err != nil {
   279  		return nil, errors.Wrap(err, "resp.Unmarshal")
   280  	}
   281  	return user, nil
   282  }
   283  
   284  func (self *SAliyunClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) {
   285  	return self.GetUser(name)
   286  }
   287  
   288  type SLoginProfile struct {
   289  	CreateDate            string
   290  	MFABindRequired       bool
   291  	PasswordResetRequired bool
   292  	UserName              string
   293  }
   294  
   295  func (self *SAliyunClient) GetLoginProfile(name string) (*SLoginProfile, error) {
   296  	params := map[string]string{
   297  		"UserName": name,
   298  	}
   299  	resp, err := self.ramRequest("GetLoginProfile", params)
   300  	if err != nil {
   301  		return nil, errors.Wrap(err, "ramRequest.GetLoginProfile")
   302  	}
   303  	profile := &SLoginProfile{}
   304  	err = resp.Unmarshal(profile, "LoginProfile")
   305  	if err != nil {
   306  		return nil, errors.Wrap(err, "resp.Unmarshal")
   307  	}
   308  	return profile, nil
   309  }
   310  
   311  func (self *SAliyunClient) DeleteLoginProfile(name string) error {
   312  	params := map[string]string{
   313  		"UserName": name,
   314  	}
   315  	_, err := self.ramRequest("DeleteLoginProfile", params)
   316  	return err
   317  }
   318  
   319  func (self *SAliyunClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) {
   320  	params := map[string]string{
   321  		"UserName": name,
   322  		"Password": password,
   323  	}
   324  	resp, err := self.ramRequest("CreateLoginProfile", params)
   325  	if err != nil {
   326  		return nil, errors.Wrap(err, "ramRequest.CreateLoginProfile")
   327  	}
   328  	profile := &SLoginProfile{}
   329  	err = resp.Unmarshal(profile, "LoginProfile")
   330  	if err != nil {
   331  		return nil, errors.Wrap(err, "resp.Unmarshal")
   332  	}
   333  	return profile, nil
   334  }
   335  
   336  func (self *SAliyunClient) UpdateLoginProfile(name, password string) error {
   337  	params := map[string]string{
   338  		"UserName": name,
   339  		"Password": password,
   340  	}
   341  	_, err := self.ramRequest("UpdateLoginProfile", params)
   342  	if err != nil {
   343  		return errors.Wrap(err, "ramRequest.CreateLoginProfile")
   344  	}
   345  	return nil
   346  }
   347  
   348  func (self *SAliyunClient) ResetClouduserPassword(name, password string) error {
   349  	_, err := self.GetLoginProfile(name)
   350  	if err != nil {
   351  		if errors.Cause(err) == cloudprovider.ErrNotFound {
   352  			_, err = self.CreateLoginProfile(name, password)
   353  			return err
   354  		}
   355  		return errors.Wrap(err, "GetLoginProfile")
   356  	}
   357  	return self.UpdateLoginProfile(name, password)
   358  }
   359  
   360  func (self *SAliyunClient) GetIamLoginUrl() string {
   361  	params := map[string]string{}
   362  	resp, err := self.ramRequest("GetAccountAlias", params)
   363  	if err != nil {
   364  		log.Errorf("GetAccountAlias error: %v", err)
   365  		return ""
   366  	}
   367  	alias, _ := resp.GetString("AccountAlias")
   368  	if len(alias) > 0 {
   369  		return fmt.Sprintf("https://signin.aliyun.com/%s.onaliyun.com/login.htm", alias)
   370  	}
   371  	return ""
   372  }
   373  
   374  // https://help.aliyun.com/document_detail/28707.html?spm=a2c4g.11186623.6.752.f4466bbfVy5j0s
   375  func (self *SAliyunClient) ListGroupsForUser(user string) ([]SGroup, error) {
   376  	params := map[string]string{
   377  		"UserName": user,
   378  	}
   379  	resp, err := self.ramRequest("ListGroupsForUser", params)
   380  	if err != nil {
   381  		return nil, errors.Wrap(err, "ListGroupsForUser")
   382  	}
   383  	groups := []SGroup{}
   384  	err = resp.Unmarshal(&groups, "Groups", "Group")
   385  	if err != nil {
   386  		return nil, errors.Wrap(err, "resp.Unmarshal")
   387  	}
   388  	return groups, nil
   389  }
   390  
   391  // https://help.aliyun.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8
   392  func (self *SAliyunClient) ListPoliciesForUser(user string) ([]SPolicy, error) {
   393  	params := map[string]string{
   394  		"UserName": user,
   395  	}
   396  	resp, err := self.ramRequest("ListPoliciesForUser", params)
   397  	if err != nil {
   398  		return nil, errors.Wrap(err, "ListPoliciesForUser")
   399  	}
   400  	policies := []SPolicy{}
   401  	err = resp.Unmarshal(&policies, "Policies", "Policy")
   402  	if err != nil {
   403  		return nil, errors.Wrap(err, "resp.Unmarshal")
   404  	}
   405  	return policies, nil
   406  }