github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/iam/user.go (about)

     1  package iam
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"path"
    10  	"strconv"
    11  
    12  	validation "github.com/go-ozzo/ozzo-validation/v4"
    13  	"github.com/go-ozzo/ozzo-validation/v4/is"
    14  )
    15  
    16  type (
    17  	// Users is the IAM user identity API interface
    18  	Users interface {
    19  		// CreateUser creates a user in the account specified in your own API client credentials or clone an existing user's role assignments
    20  		//
    21  		// See: https://techdocs.akamai.com/iam-user-admin/reference/post-ui-identity
    22  		CreateUser(context.Context, CreateUserRequest) (*User, error)
    23  
    24  		// GetUser gets  a specific user's profile
    25  		//
    26  		// See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identity
    27  		GetUser(context.Context, GetUserRequest) (*User, error)
    28  
    29  		// ListUsers returns a list of users who have access on this account
    30  		//
    31  		// See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identities
    32  		ListUsers(context.Context, ListUsersRequest) ([]UserListItem, error)
    33  
    34  		// RemoveUser removes a user identity
    35  		//
    36  		// See: https://techdocs.akamai.com/iam-user-admin/reference/delete-ui-identity
    37  		RemoveUser(context.Context, RemoveUserRequest) error
    38  
    39  		// UpdateUserAuthGrants edits what groups a user has access to, and how the user can interact with the objects in those groups
    40  		//
    41  		// See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-uiidentity-auth-grants
    42  		UpdateUserAuthGrants(context.Context, UpdateUserAuthGrantsRequest) ([]AuthGrant, error)
    43  
    44  		// UpdateUserInfo updates a user's information
    45  		//
    46  		// See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-basic-info
    47  		UpdateUserInfo(context.Context, UpdateUserInfoRequest) (*UserBasicInfo, error)
    48  
    49  		// UpdateUserNotifications subscribes or un-subscribe user to product notification emails
    50  		//
    51  		// See: https://techdocs.akamai.com/iam-user-admin/reference/put-notifications
    52  		UpdateUserNotifications(context.Context, UpdateUserNotificationsRequest) (*UserNotifications, error)
    53  
    54  		// UpdateTFA updates a user's two-factor authentication setting and can reset tfa
    55  		//
    56  		// See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-tfa
    57  		UpdateTFA(context.Context, UpdateTFARequest) error
    58  	}
    59  
    60  	// CreateUserRequest contains the request parameters for the create user endpoint
    61  	CreateUserRequest struct {
    62  		UserBasicInfo
    63  		AuthGrants    []AuthGrantRequest `json:"authGrants,omitempty"`
    64  		Notifications UserNotifications  `json:"notifications,omitempty"`
    65  		SendEmail     bool               `json:"-"`
    66  	}
    67  
    68  	// ListUsersRequest contains the request parameters for the list users endpoint
    69  	ListUsersRequest struct {
    70  		GroupID    *int64
    71  		AuthGrants bool
    72  		Actions    bool
    73  	}
    74  
    75  	// GetUserRequest contains the request parameters of the get user endpoint
    76  	GetUserRequest struct {
    77  		IdentityID    string
    78  		Actions       bool
    79  		AuthGrants    bool
    80  		Notifications bool
    81  	}
    82  
    83  	// UpdateUserInfoRequest contains the request parameters of the update user endpoint
    84  	UpdateUserInfoRequest struct {
    85  		IdentityID string
    86  		User       UserBasicInfo
    87  	}
    88  
    89  	// UpdateUserNotificationsRequest contains the request parameters of the update user notifications endpoint
    90  	UpdateUserNotificationsRequest struct {
    91  		IdentityID    string
    92  		Notifications UserNotifications
    93  	}
    94  
    95  	// UpdateUserAuthGrantsRequest contains the request parameters of the update user auth grants endpoint
    96  	UpdateUserAuthGrantsRequest struct {
    97  		IdentityID string
    98  		AuthGrants []AuthGrantRequest
    99  	}
   100  
   101  	// RemoveUserRequest contains the request parameters of the remove user endpoint
   102  	RemoveUserRequest struct {
   103  		IdentityID string
   104  	}
   105  
   106  	// User describes the response of the get and create user endpoints
   107  	User struct {
   108  		UserBasicInfo
   109  		IdentityID         string            `json:"uiIdentityId"`
   110  		IsLocked           bool              `json:"isLocked"`
   111  		LastLoginDate      string            `json:"lastLoginDate,omitempty"`
   112  		PasswordExpiryDate string            `json:"passwordExpiryDate,omitempty"`
   113  		TFAConfigured      bool              `json:"tfaConfigured"`
   114  		EmailUpdatePending bool              `json:"emailUpdatePending"`
   115  		AuthGrants         []AuthGrant       `json:"authGrants,omitempty"`
   116  		Notifications      UserNotifications `json:"notifications,omitempty"`
   117  	}
   118  
   119  	// UserListItem describes the response of the list endpoint
   120  	UserListItem struct {
   121  		FirstName     string       `json:"firstName"`
   122  		LastName      string       `json:"lastName"`
   123  		UserName      string       `json:"uiUserName,omitempty"`
   124  		Email         string       `json:"email"`
   125  		TFAEnabled    bool         `json:"tfaEnabled"`
   126  		IdentityID    string       `json:"uiIdentityId"`
   127  		IsLocked      bool         `json:"isLocked"`
   128  		LastLoginDate string       `json:"lastLoginDate,omitempty"`
   129  		TFAConfigured bool         `json:"tfaConfigured"`
   130  		AccountID     string       `json:"accountId"`
   131  		Actions       *UserActions `json:"actions,omitempty"`
   132  		AuthGrants    []AuthGrant  `json:"authGrants,omitempty"`
   133  	}
   134  
   135  	// UserBasicInfo is the user basic info structure
   136  	UserBasicInfo struct {
   137  		FirstName         string `json:"firstName"`
   138  		LastName          string `json:"lastName"`
   139  		UserName          string `json:"uiUserName,omitempty"`
   140  		Email             string `json:"email"`
   141  		Phone             string `json:"phone,omitempty"`
   142  		TimeZone          string `json:"timeZone,omitempty"`
   143  		JobTitle          string `json:"jobTitle"`
   144  		TFAEnabled        bool   `json:"tfaEnabled"`
   145  		SecondaryEmail    string `json:"secondaryEmail,omitempty"`
   146  		MobilePhone       string `json:"mobilePhone,omitempty"`
   147  		Address           string `json:"address,omitempty"`
   148  		City              string `json:"city,omitempty"`
   149  		State             string `json:"state,omitempty"`
   150  		ZipCode           string `json:"zipCode,omitempty"`
   151  		Country           string `json:"country"`
   152  		ContactType       string `json:"contactType,omitempty"`
   153  		PreferredLanguage string `json:"preferredLanguage,omitempty"`
   154  		SessionTimeOut    *int   `json:"sessionTimeOut,omitempty"`
   155  	}
   156  
   157  	// UserActions encapsulates permissions available to the user for this group
   158  	UserActions struct {
   159  		APIClient        bool `json:"apiClient"`
   160  		Delete           bool `json:"delete"`
   161  		Edit             bool `json:"edit"`
   162  		IsCloneable      bool `json:"isCloneable"`
   163  		ResetPassword    bool `json:"resetPassword"`
   164  		ThirdPartyAccess bool `json:"thirdPartyAccess"`
   165  		CanEditTFA       bool `json:"canEditTFA"`
   166  		EditProfile      bool `json:"editProfile"`
   167  	}
   168  
   169  	// AuthGrant is user’s role assignments, per group
   170  	AuthGrant struct {
   171  		GroupID         int64       `json:"groupId"`
   172  		GroupName       string      `json:"groupName"`
   173  		IsBlocked       bool        `json:"isBlocked"`
   174  		RoleDescription string      `json:"roleDescription"`
   175  		RoleID          *int        `json:"roleId,omitempty"`
   176  		RoleName        string      `json:"roleName"`
   177  		Subgroups       []AuthGrant `json:"subGroups,omitempty"`
   178  	}
   179  
   180  	// AuthGrantRequest is user’s role assignments, per group for the create/update operation
   181  	AuthGrantRequest struct {
   182  		GroupID   int64              `json:"groupId"`
   183  		IsBlocked bool               `json:"isBlocked"`
   184  		RoleID    *int               `json:"roleId,omitempty"`
   185  		Subgroups []AuthGrantRequest `json:"subGroups,omitempty"`
   186  	}
   187  
   188  	// UserNotifications types of notification emails the user receives
   189  	UserNotifications struct {
   190  		EnableEmail bool                    `json:"enableEmailNotifications"`
   191  		Options     UserNotificationOptions `json:"options"`
   192  	}
   193  
   194  	// UserNotificationOptions types of notification emails the user receives
   195  	UserNotificationOptions struct {
   196  		NewUser        bool     `json:"newUserNotification"`
   197  		PasswordExpiry bool     `json:"passwordExpiry"`
   198  		Proactive      []string `json:"proactive"`
   199  		Upgrade        []string `json:"upgrade"`
   200  	}
   201  
   202  	// TFAActionType is a type for tfa action constants
   203  	TFAActionType string
   204  
   205  	// UpdateTFARequest contains the request parameters of the tfa user endpoint
   206  	UpdateTFARequest struct {
   207  		IdentityID string
   208  		Action     TFAActionType
   209  	}
   210  )
   211  
   212  const (
   213  	// TFAActionEnable ia an action value to use to enable tfa
   214  	TFAActionEnable TFAActionType = "enable"
   215  	// TFAActionDisable ia an action value to use to disable tfa
   216  	TFAActionDisable TFAActionType = "disable"
   217  	// TFAActionReset ia an action value to use to reset tfa
   218  	TFAActionReset TFAActionType = "reset"
   219  )
   220  
   221  var (
   222  	// ErrCreateUser is returned when CreateUser fails
   223  	ErrCreateUser = errors.New("create user")
   224  
   225  	// ErrGetUser is returned when GetUser fails
   226  	ErrGetUser = errors.New("get user")
   227  
   228  	// ErrListUsers is returned when GetUser fails
   229  	ErrListUsers = errors.New("list users")
   230  
   231  	// ErrRemoveUser is returned when RemoveUser fails
   232  	ErrRemoveUser = errors.New("remove user")
   233  
   234  	// ErrUpdateUserAuthGrants is returned when UpdateUserAuthGrants fails
   235  	ErrUpdateUserAuthGrants = errors.New("update user auth grants")
   236  
   237  	// ErrUpdateUserInfo is returned when UpdateUserInfo fails
   238  	ErrUpdateUserInfo = errors.New("update user info")
   239  
   240  	// ErrUpdateUserNotifications is returned when UpdateUserNotifications fails
   241  	ErrUpdateUserNotifications = errors.New("update user notifications")
   242  
   243  	// ErrUpdateTFA is returned when UpdateTFA fails
   244  	ErrUpdateTFA = errors.New("update user's two-factor authentication")
   245  )
   246  
   247  // Validate performs validation on AuthGrant
   248  func (r AuthGrant) Validate() error {
   249  	return validation.Errors{
   250  		"group_id": validation.Validate(r.GroupID, validation.Required),
   251  		"role_id":  validation.Validate(r.RoleID, validation.Required),
   252  	}.Filter()
   253  }
   254  
   255  // Validate validates CreateUserRequest
   256  func (r CreateUserRequest) Validate() error {
   257  	return validation.Errors{
   258  		"country":       validation.Validate(r.Country, validation.Required),
   259  		"email":         validation.Validate(r.Email, validation.Required, is.EmailFormat),
   260  		"firstName":     validation.Validate(r.FirstName, validation.Required),
   261  		"lastName":      validation.Validate(r.LastName, validation.Required),
   262  		"authGrants":    validation.Validate(r.AuthGrants, validation.Required),
   263  		"notifications": validation.Validate(r.Notifications, validation.Required),
   264  	}.Filter()
   265  }
   266  
   267  // Validate validates GetUserRequest
   268  func (r GetUserRequest) Validate() error {
   269  	return validation.Errors{
   270  		"uiIdentity": validation.Validate(r.IdentityID, validation.Required),
   271  	}.Filter()
   272  }
   273  
   274  // Validate validates UpdateUserInfoRequest
   275  func (r UpdateUserInfoRequest) Validate() error {
   276  	return validation.Errors{
   277  		"uiIdentity":        validation.Validate(r.IdentityID, validation.Required),
   278  		"firstName":         validation.Validate(r.User.FirstName, validation.Required),
   279  		"lastName":          validation.Validate(r.User.LastName, validation.Required),
   280  		"country":           validation.Validate(r.User.Country, validation.Required),
   281  		"timeZone":          validation.Validate(r.User.TimeZone, validation.Required),
   282  		"preferredLanguage": validation.Validate(r.User.PreferredLanguage, validation.Required),
   283  		"sessionTimeOut":    validation.Validate(r.User.SessionTimeOut, validation.Required),
   284  	}.Filter()
   285  }
   286  
   287  // Validate validates UpdateUserNotificationsRequest
   288  func (r UpdateUserNotificationsRequest) Validate() error {
   289  	return validation.Errors{
   290  		"uiIdentity": validation.Validate(r.IdentityID, validation.Required),
   291  	}.Filter()
   292  }
   293  
   294  // Validate validates UpdateUserAuthGrantsRequest
   295  func (r UpdateUserAuthGrantsRequest) Validate() error {
   296  	return validation.Errors{
   297  		"uiIdentity": validation.Validate(r.IdentityID, validation.Required),
   298  		"authGrants": validation.Validate(r.AuthGrants, validation.Required),
   299  	}.Filter()
   300  }
   301  
   302  // Validate validates RemoveUserRequest
   303  func (r RemoveUserRequest) Validate() error {
   304  	return validation.Errors{
   305  		"uiIdentity": validation.Validate(r.IdentityID, validation.Required),
   306  	}.Filter()
   307  }
   308  
   309  // Validate validates UpdateTFARequest
   310  func (r UpdateTFARequest) Validate() error {
   311  	return validation.Errors{
   312  		"IdentityID": validation.Validate(r.IdentityID, validation.Required),
   313  		"Action": validation.Validate(r.Action, validation.Required, validation.In(TFAActionEnable, TFAActionDisable, TFAActionReset).
   314  			Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'enable', 'disable' or 'reset'", r.Action))),
   315  	}.Filter()
   316  }
   317  
   318  func (i *iam) CreateUser(ctx context.Context, params CreateUserRequest) (*User, error) {
   319  	if err := params.Validate(); err != nil {
   320  		return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateUser, ErrStructValidation, err)
   321  	}
   322  
   323  	u, err := url.Parse(path.Join("/identity-management/v2/user-admin", "ui-identities"))
   324  	if err != nil {
   325  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateUser, err)
   326  	}
   327  
   328  	q := u.Query()
   329  	q.Add("sendEmail", strconv.FormatBool(params.SendEmail))
   330  
   331  	u.RawQuery = q.Encode()
   332  
   333  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil)
   334  	if err != nil {
   335  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateUser, err)
   336  	}
   337  
   338  	var result User
   339  	resp, err := i.Exec(req, &result, params)
   340  	if err != nil {
   341  		return nil, fmt.Errorf("%w: request failed: %s", ErrCreateUser, err)
   342  	}
   343  
   344  	if resp.StatusCode != http.StatusCreated {
   345  		return nil, fmt.Errorf("%s: %w", ErrCreateUser, i.Error(resp))
   346  	}
   347  
   348  	return &result, nil
   349  }
   350  
   351  func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) {
   352  	if err := params.Validate(); err != nil {
   353  		return nil, fmt.Errorf("%s: %w:\n%s", ErrGetUser, ErrStructValidation, err)
   354  	}
   355  
   356  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID))
   357  	if err != nil {
   358  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err)
   359  	}
   360  
   361  	q := u.Query()
   362  	q.Add("actions", strconv.FormatBool(params.Actions))
   363  	q.Add("authGrants", strconv.FormatBool(params.AuthGrants))
   364  	q.Add("notifications", strconv.FormatBool(params.Notifications))
   365  
   366  	u.RawQuery = q.Encode()
   367  
   368  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
   369  	if err != nil {
   370  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err)
   371  	}
   372  
   373  	var rval User
   374  	resp, err := i.Exec(req, &rval)
   375  	if err != nil {
   376  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetUser, err)
   377  	}
   378  
   379  	if resp.StatusCode != http.StatusOK {
   380  		return nil, fmt.Errorf("%s: %w", ErrGetUser, i.Error(resp))
   381  	}
   382  
   383  	return &rval, nil
   384  }
   385  
   386  func (i *iam) ListUsers(ctx context.Context, params ListUsersRequest) ([]UserListItem, error) {
   387  	u, err := url.Parse("/identity-management/v2/user-admin/ui-identities")
   388  	if err != nil {
   389  		return nil, fmt.Errorf("%w: failed to parse the URL:\n%s", ErrListUsers, err)
   390  	}
   391  
   392  	q := u.Query()
   393  	q.Add("actions", strconv.FormatBool(params.Actions))
   394  	q.Add("authGrants", strconv.FormatBool(params.AuthGrants))
   395  	if params.GroupID != nil {
   396  		q.Add("groupId", strconv.FormatInt(int64(*params.GroupID), 10))
   397  	}
   398  	u.RawQuery = q.Encode()
   399  
   400  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
   401  	if err != nil {
   402  		return nil, fmt.Errorf("%w: failed to create request:\n%s", ErrListUsers, err)
   403  	}
   404  
   405  	var users []UserListItem
   406  	resp, err := i.Exec(req, &users)
   407  	if err != nil {
   408  		return nil, fmt.Errorf("%w: request failed:\n%s", ErrListUsers, err)
   409  	}
   410  
   411  	if resp.StatusCode != http.StatusOK {
   412  		return nil, fmt.Errorf("%s: %w", ErrListUsers, i.Error(resp))
   413  	}
   414  
   415  	return users, nil
   416  }
   417  
   418  func (i *iam) RemoveUser(ctx context.Context, params RemoveUserRequest) error {
   419  	if err := params.Validate(); err != nil {
   420  		return fmt.Errorf("%s: %w:\n%s", ErrRemoveUser, ErrStructValidation, err)
   421  	}
   422  
   423  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID))
   424  	if err != nil {
   425  		return fmt.Errorf("%w: failed to create request: %s", ErrRemoveUser, err)
   426  	}
   427  
   428  	req, err := http.NewRequestWithContext(ctx, http.MethodDelete, u.String(), nil)
   429  	if err != nil {
   430  		return fmt.Errorf("%w: failed to create request: %s", ErrRemoveUser, err)
   431  	}
   432  
   433  	resp, err := i.Exec(req, nil)
   434  	if err != nil {
   435  		return fmt.Errorf("%w: request failed: %s", ErrRemoveUser, err)
   436  	}
   437  
   438  	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
   439  		return fmt.Errorf("%s: %w", ErrRemoveUser, i.Error(resp))
   440  	}
   441  
   442  	return nil
   443  }
   444  
   445  func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGrantsRequest) ([]AuthGrant, error) {
   446  	if err := params.Validate(); err != nil {
   447  		return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserAuthGrants, ErrStructValidation, err)
   448  	}
   449  
   450  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/auth-grants", params.IdentityID))
   451  	if err != nil {
   452  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err)
   453  	}
   454  
   455  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil)
   456  	if err != nil {
   457  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err)
   458  	}
   459  
   460  	rval := make([]AuthGrant, 0)
   461  
   462  	resp, err := i.Exec(req, &rval, params.AuthGrants)
   463  	if err != nil {
   464  		return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserAuthGrants, err)
   465  	}
   466  
   467  	if resp.StatusCode != http.StatusOK {
   468  		return nil, fmt.Errorf("%s: %w", ErrUpdateUserAuthGrants, i.Error(resp))
   469  	}
   470  
   471  	return rval, nil
   472  }
   473  
   474  func (i *iam) UpdateUserInfo(ctx context.Context, params UpdateUserInfoRequest) (*UserBasicInfo, error) {
   475  	if err := params.Validate(); err != nil {
   476  		return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserInfo, ErrStructValidation, err)
   477  	}
   478  
   479  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/basic-info", params.IdentityID))
   480  	if err != nil {
   481  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserInfo, err)
   482  	}
   483  
   484  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil)
   485  	if err != nil {
   486  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserInfo, err)
   487  	}
   488  
   489  	var rval UserBasicInfo
   490  	resp, err := i.Exec(req, &rval, params.User)
   491  	if err != nil {
   492  		return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserInfo, err)
   493  	}
   494  
   495  	if resp.StatusCode != http.StatusOK {
   496  		return nil, fmt.Errorf("%s: %w", ErrUpdateUserInfo, i.Error(resp))
   497  	}
   498  
   499  	return &rval, nil
   500  }
   501  
   502  func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNotificationsRequest) (*UserNotifications, error) {
   503  	if err := params.Validate(); err != nil {
   504  		return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserNotifications, ErrStructValidation, err)
   505  	}
   506  
   507  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/notifications", params.IdentityID))
   508  	if err != nil {
   509  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err)
   510  	}
   511  
   512  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil)
   513  	if err != nil {
   514  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err)
   515  	}
   516  
   517  	var rval UserNotifications
   518  	resp, err := i.Exec(req, &rval, params.Notifications)
   519  	if err != nil {
   520  		return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserNotifications, err)
   521  	}
   522  
   523  	if resp.StatusCode != http.StatusOK {
   524  		return nil, fmt.Errorf("%s: %w", ErrUpdateUserNotifications, i.Error(resp))
   525  	}
   526  
   527  	return &rval, nil
   528  }
   529  
   530  func (i *iam) UpdateTFA(ctx context.Context, params UpdateTFARequest) error {
   531  	if err := params.Validate(); err != nil {
   532  		return fmt.Errorf("%s: %w:\n%s", ErrUpdateTFA, ErrStructValidation, err)
   533  	}
   534  
   535  	u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/tfa", params.IdentityID))
   536  	if err != nil {
   537  		return fmt.Errorf("%w: failed to create request: %s", ErrUpdateTFA, err)
   538  	}
   539  
   540  	q := u.Query()
   541  	q.Add("action", string(params.Action))
   542  	u.RawQuery = q.Encode()
   543  
   544  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil)
   545  	if err != nil {
   546  		return fmt.Errorf("%w: failed to create request: %s", ErrUpdateTFA, err)
   547  	}
   548  
   549  	resp, err := i.Exec(req, nil, nil)
   550  	if err != nil {
   551  		return fmt.Errorf("%w: request failed: %s", ErrUpdateTFA, err)
   552  	}
   553  
   554  	if resp.StatusCode != http.StatusNoContent {
   555  		return fmt.Errorf("%s: %w", ErrUpdateTFA, i.Error(resp))
   556  	}
   557  
   558  	return nil
   559  }