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