storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/admin-handlers-users.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2019-2020 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"io"
    24  	"io/ioutil"
    25  	"net/http"
    26  
    27  	"github.com/gorilla/mux"
    28  
    29  	"storj.io/minio/cmd/logger"
    30  	"storj.io/minio/pkg/auth"
    31  	iampolicy "storj.io/minio/pkg/iam/policy"
    32  	"storj.io/minio/pkg/madmin"
    33  )
    34  
    35  func validateAdminUsersReq(ctx context.Context, w http.ResponseWriter, r *http.Request, action iampolicy.AdminAction) (ObjectLayer, auth.Credentials) {
    36  	var cred auth.Credentials
    37  	var adminAPIErr APIErrorCode
    38  
    39  	// Get current object layer instance.
    40  	objectAPI := newObjectLayerFn()
    41  	if objectAPI == nil || GlobalNotificationSys == nil {
    42  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
    43  		return nil, cred
    44  	}
    45  
    46  	// Validate request signature.
    47  	cred, adminAPIErr = checkAdminRequestAuth(ctx, r, action, "")
    48  	if adminAPIErr != ErrNone {
    49  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(adminAPIErr), r.URL)
    50  		return nil, cred
    51  	}
    52  
    53  	return objectAPI, cred
    54  }
    55  
    56  // RemoveUser - DELETE /minio/admin/v3/remove-user?accessKey=<access_key>
    57  func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) {
    58  	ctx := NewContext(r, w, "RemoveUser")
    59  
    60  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
    61  
    62  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.DeleteUserAdminAction)
    63  	if objectAPI == nil {
    64  		return
    65  	}
    66  
    67  	vars := mux.Vars(r)
    68  	accessKey := vars["accessKey"]
    69  
    70  	ok, _, err := GlobalIAMSys.IsTempUser(accessKey)
    71  	if err != nil {
    72  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
    73  		return
    74  	}
    75  	if ok {
    76  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL)
    77  		return
    78  	}
    79  
    80  	if err := GlobalIAMSys.DeleteUser(accessKey); err != nil {
    81  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
    82  		return
    83  	}
    84  
    85  	// Notify all other MinIO peers to delete user.
    86  	for _, nerr := range GlobalNotificationSys.DeleteUser(accessKey) {
    87  		if nerr.Err != nil {
    88  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
    89  			logger.LogIf(ctx, nerr.Err)
    90  		}
    91  	}
    92  }
    93  
    94  // ListUsers - GET /minio/admin/v3/list-users
    95  func (a adminAPIHandlers) ListUsers(w http.ResponseWriter, r *http.Request) {
    96  	ctx := NewContext(r, w, "ListUsers")
    97  
    98  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
    99  
   100  	objectAPI, cred := validateAdminUsersReq(ctx, w, r, iampolicy.ListUsersAdminAction)
   101  	if objectAPI == nil {
   102  		return
   103  	}
   104  
   105  	password := cred.SecretKey
   106  
   107  	allCredentials, err := GlobalIAMSys.ListUsers()
   108  	if err != nil {
   109  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   110  		return
   111  	}
   112  
   113  	data, err := json.Marshal(allCredentials)
   114  	if err != nil {
   115  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   116  		return
   117  	}
   118  
   119  	econfigData, err := madmin.EncryptData(password, data)
   120  	if err != nil {
   121  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   122  		return
   123  	}
   124  
   125  	writeSuccessResponseJSON(w, econfigData)
   126  }
   127  
   128  // GetUserInfo - GET /minio/admin/v3/user-info
   129  func (a adminAPIHandlers) GetUserInfo(w http.ResponseWriter, r *http.Request) {
   130  	ctx := NewContext(r, w, "GetUserInfo")
   131  
   132  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   133  
   134  	vars := mux.Vars(r)
   135  	name := vars["accessKey"]
   136  
   137  	// Get current object layer instance.
   138  	objectAPI := newObjectLayerFn()
   139  	if objectAPI == nil || GlobalNotificationSys == nil {
   140  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   141  		return
   142  	}
   143  
   144  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   145  	if s3Err != ErrNone {
   146  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   147  		return
   148  	}
   149  
   150  	accessKey := cred.AccessKey
   151  	if cred.ParentUser != "" {
   152  		accessKey = cred.ParentUser
   153  	}
   154  
   155  	implicitPerm := name == accessKey
   156  	if !implicitPerm {
   157  		if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   158  			AccountName:     accessKey,
   159  			Groups:          cred.Groups,
   160  			Action:          iampolicy.GetUserAdminAction,
   161  			ConditionValues: getConditionValues(r, "", accessKey, claims),
   162  			IsOwner:         owner,
   163  			Claims:          claims,
   164  		}) {
   165  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   166  			return
   167  		}
   168  	}
   169  
   170  	userInfo, err := GlobalIAMSys.GetUserInfo(ctx, name)
   171  	if err != nil {
   172  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   173  		return
   174  	}
   175  
   176  	data, err := json.Marshal(userInfo)
   177  	if err != nil {
   178  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   179  		return
   180  	}
   181  
   182  	writeSuccessResponseJSON(w, data)
   183  }
   184  
   185  // UpdateGroupMembers - PUT /minio/admin/v3/update-group-members
   186  func (a adminAPIHandlers) UpdateGroupMembers(w http.ResponseWriter, r *http.Request) {
   187  	ctx := NewContext(r, w, "UpdateGroupMembers")
   188  
   189  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   190  
   191  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.AddUserToGroupAdminAction)
   192  	if objectAPI == nil {
   193  		return
   194  	}
   195  
   196  	defer r.Body.Close()
   197  	data, err := ioutil.ReadAll(r.Body)
   198  	if err != nil {
   199  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
   200  		return
   201  	}
   202  
   203  	var updReq madmin.GroupAddRemove
   204  	err = json.Unmarshal(data, &updReq)
   205  	if err != nil {
   206  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
   207  		return
   208  	}
   209  
   210  	if updReq.IsRemove {
   211  		err = GlobalIAMSys.RemoveUsersFromGroup(updReq.Group, updReq.Members)
   212  	} else {
   213  		err = GlobalIAMSys.AddUsersToGroup(updReq.Group, updReq.Members)
   214  	}
   215  
   216  	if err != nil {
   217  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   218  		return
   219  	}
   220  
   221  	// Notify all other MinIO peers to load group.
   222  	for _, nerr := range GlobalNotificationSys.LoadGroup(updReq.Group) {
   223  		if nerr.Err != nil {
   224  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   225  			logger.LogIf(ctx, nerr.Err)
   226  		}
   227  	}
   228  }
   229  
   230  // GetGroup - /minio/admin/v3/group?group=mygroup1
   231  func (a adminAPIHandlers) GetGroup(w http.ResponseWriter, r *http.Request) {
   232  	ctx := NewContext(r, w, "GetGroup")
   233  
   234  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   235  
   236  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.GetGroupAdminAction)
   237  	if objectAPI == nil {
   238  		return
   239  	}
   240  
   241  	vars := mux.Vars(r)
   242  	group := vars["group"]
   243  
   244  	gdesc, err := GlobalIAMSys.GetGroupDescription(group)
   245  	if err != nil {
   246  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   247  		return
   248  	}
   249  
   250  	body, err := json.Marshal(gdesc)
   251  	if err != nil {
   252  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   253  		return
   254  	}
   255  
   256  	writeSuccessResponseJSON(w, body)
   257  }
   258  
   259  // ListGroups - GET /minio/admin/v3/groups
   260  func (a adminAPIHandlers) ListGroups(w http.ResponseWriter, r *http.Request) {
   261  	ctx := NewContext(r, w, "ListGroups")
   262  
   263  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   264  
   265  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.ListGroupsAdminAction)
   266  	if objectAPI == nil {
   267  		return
   268  	}
   269  
   270  	groups, err := GlobalIAMSys.ListGroups()
   271  	if err != nil {
   272  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   273  		return
   274  	}
   275  
   276  	body, err := json.Marshal(groups)
   277  	if err != nil {
   278  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   279  		return
   280  	}
   281  
   282  	writeSuccessResponseJSON(w, body)
   283  }
   284  
   285  // SetGroupStatus - PUT /minio/admin/v3/set-group-status?group=mygroup1&status=enabled
   286  func (a adminAPIHandlers) SetGroupStatus(w http.ResponseWriter, r *http.Request) {
   287  	ctx := NewContext(r, w, "SetGroupStatus")
   288  
   289  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   290  
   291  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.EnableGroupAdminAction)
   292  	if objectAPI == nil {
   293  		return
   294  	}
   295  
   296  	vars := mux.Vars(r)
   297  	group := vars["group"]
   298  	status := vars["status"]
   299  
   300  	var err error
   301  	if status == statusEnabled {
   302  		err = GlobalIAMSys.SetGroupStatus(group, true)
   303  	} else if status == statusDisabled {
   304  		err = GlobalIAMSys.SetGroupStatus(group, false)
   305  	} else {
   306  		err = errInvalidArgument
   307  	}
   308  	if err != nil {
   309  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   310  		return
   311  	}
   312  
   313  	// Notify all other MinIO peers to reload user.
   314  	for _, nerr := range GlobalNotificationSys.LoadGroup(group) {
   315  		if nerr.Err != nil {
   316  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   317  			logger.LogIf(ctx, nerr.Err)
   318  		}
   319  	}
   320  }
   321  
   322  // SetUserStatus - PUT /minio/admin/v3/set-user-status?accessKey=<access_key>&status=[enabled|disabled]
   323  func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) {
   324  	ctx := NewContext(r, w, "SetUserStatus")
   325  
   326  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   327  
   328  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.EnableUserAdminAction)
   329  	if objectAPI == nil {
   330  		return
   331  	}
   332  
   333  	vars := mux.Vars(r)
   334  	accessKey := vars["accessKey"]
   335  	status := vars["status"]
   336  
   337  	// This API is not allowed to lookup accessKey user status
   338  	if accessKey == globalActiveCred.AccessKey {
   339  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
   340  		return
   341  	}
   342  
   343  	if err := GlobalIAMSys.SetUserStatus(accessKey, madmin.AccountStatus(status)); err != nil {
   344  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   345  		return
   346  	}
   347  
   348  	// Notify all other MinIO peers to reload user.
   349  	for _, nerr := range GlobalNotificationSys.LoadUser(accessKey, false) {
   350  		if nerr.Err != nil {
   351  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   352  			logger.LogIf(ctx, nerr.Err)
   353  		}
   354  	}
   355  }
   356  
   357  // AddUser - PUT /minio/admin/v3/add-user?accessKey=<access_key>
   358  func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) {
   359  	ctx := NewContext(r, w, "AddUser")
   360  
   361  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   362  
   363  	vars := mux.Vars(r)
   364  	accessKey := vars["accessKey"]
   365  
   366  	// Get current object layer instance.
   367  	objectAPI := newObjectLayerFn()
   368  	if objectAPI == nil || GlobalNotificationSys == nil {
   369  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   370  		return
   371  	}
   372  
   373  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   374  	if s3Err != ErrNone {
   375  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   376  		return
   377  	}
   378  
   379  	// Not allowed to add a user with same access key as root credential
   380  	if owner && accessKey == cred.AccessKey {
   381  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL)
   382  		return
   383  	}
   384  
   385  	if (cred.IsTemp() || cred.IsServiceAccount()) && cred.ParentUser == accessKey {
   386  		// Incoming access key matches parent user then we should
   387  		// reject password change requests.
   388  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL)
   389  		return
   390  	}
   391  
   392  	implicitPerm := accessKey == cred.AccessKey
   393  	if !implicitPerm {
   394  		parentUser := cred.ParentUser
   395  		if parentUser == "" {
   396  			parentUser = cred.AccessKey
   397  		}
   398  		if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   399  			AccountName:     parentUser,
   400  			Groups:          cred.Groups,
   401  			Action:          iampolicy.CreateUserAdminAction,
   402  			ConditionValues: getConditionValues(r, "", parentUser, claims),
   403  			IsOwner:         owner,
   404  			Claims:          claims,
   405  		}) {
   406  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   407  			return
   408  		}
   409  	}
   410  
   411  	if implicitPerm && !GlobalIAMSys.IsAllowed(iampolicy.Args{
   412  		AccountName:     accessKey,
   413  		Groups:          cred.Groups,
   414  		Action:          iampolicy.CreateUserAdminAction,
   415  		ConditionValues: getConditionValues(r, "", accessKey, claims),
   416  		IsOwner:         owner,
   417  		Claims:          claims,
   418  		DenyOnly:        true, // check if changing password is explicitly denied.
   419  	}) {
   420  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   421  		return
   422  	}
   423  
   424  	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 {
   425  		// More than maxConfigSize bytes were available
   426  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL)
   427  		return
   428  	}
   429  
   430  	password := cred.SecretKey
   431  	configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength))
   432  	if err != nil {
   433  		logger.LogIf(ctx, err)
   434  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL)
   435  		return
   436  	}
   437  
   438  	var uinfo madmin.UserInfo
   439  	if err = json.Unmarshal(configBytes, &uinfo); err != nil {
   440  		logger.LogIf(ctx, err)
   441  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL)
   442  		return
   443  	}
   444  
   445  	if err = GlobalIAMSys.CreateUser(accessKey, uinfo); err != nil {
   446  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   447  		return
   448  	}
   449  
   450  	// Notify all other Minio peers to reload user
   451  	for _, nerr := range GlobalNotificationSys.LoadUser(accessKey, false) {
   452  		if nerr.Err != nil {
   453  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   454  			logger.LogIf(ctx, nerr.Err)
   455  		}
   456  	}
   457  }
   458  
   459  // AddServiceAccount - PUT /minio/admin/v3/add-service-account
   460  func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Request) {
   461  	ctx := NewContext(r, w, "AddServiceAccount")
   462  
   463  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   464  
   465  	// Get current object layer instance.
   466  	objectAPI := newObjectLayerFn()
   467  	if objectAPI == nil || GlobalNotificationSys == nil {
   468  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   469  		return
   470  	}
   471  
   472  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   473  	if s3Err != ErrNone {
   474  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   475  		return
   476  	}
   477  
   478  	password := cred.SecretKey
   479  	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength))
   480  	if err != nil {
   481  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   482  		return
   483  	}
   484  
   485  	var createReq madmin.AddServiceAccountReq
   486  	if err = json.Unmarshal(reqBytes, &createReq); err != nil {
   487  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   488  		return
   489  	}
   490  
   491  	// Disallow creating service accounts by root user.
   492  	if createReq.TargetUser == globalActiveCred.AccessKey {
   493  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminAccountNotEligible), r.URL)
   494  		return
   495  	}
   496  
   497  	var (
   498  		targetUser   string
   499  		targetGroups []string
   500  	)
   501  
   502  	targetUser = createReq.TargetUser
   503  
   504  	// Need permission if we are creating a service acccount
   505  	// for a user <> to the request sender
   506  	if targetUser != "" && targetUser != cred.AccessKey {
   507  		if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   508  			AccountName:     cred.AccessKey,
   509  			Action:          iampolicy.CreateServiceAccountAdminAction,
   510  			ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   511  			IsOwner:         owner,
   512  			Claims:          claims,
   513  		}) {
   514  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   515  			return
   516  		}
   517  	}
   518  
   519  	if globalLDAPConfig.Enabled && targetUser != "" {
   520  		// If LDAP enabled, service accounts need
   521  		// to be created only for LDAP users.
   522  		var err error
   523  		_, targetGroups, err = globalLDAPConfig.LookupUserDN(targetUser)
   524  		if err != nil {
   525  			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   526  			return
   527  		}
   528  	} else {
   529  		if targetUser == "" {
   530  			targetUser = cred.AccessKey
   531  		}
   532  		if cred.ParentUser != "" {
   533  			targetUser = cred.ParentUser
   534  		}
   535  		targetGroups = cred.Groups
   536  	}
   537  
   538  	opts := newServiceAccountOpts{sessionPolicy: createReq.Policy, accessKey: createReq.AccessKey, secretKey: createReq.SecretKey}
   539  	newCred, err := GlobalIAMSys.NewServiceAccount(ctx, targetUser, targetGroups, opts)
   540  	if err != nil {
   541  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   542  		return
   543  	}
   544  
   545  	// Notify all other Minio peers to reload user the service account
   546  	for _, nerr := range GlobalNotificationSys.LoadServiceAccount(newCred.AccessKey) {
   547  		if nerr.Err != nil {
   548  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   549  			logger.LogIf(ctx, nerr.Err)
   550  		}
   551  	}
   552  
   553  	var createResp = madmin.AddServiceAccountResp{
   554  		Credentials: auth.Credentials{
   555  			AccessKey: newCred.AccessKey,
   556  			SecretKey: newCred.SecretKey,
   557  		},
   558  	}
   559  
   560  	data, err := json.Marshal(createResp)
   561  	if err != nil {
   562  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   563  		return
   564  	}
   565  
   566  	encryptedData, err := madmin.EncryptData(password, data)
   567  	if err != nil {
   568  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   569  		return
   570  	}
   571  
   572  	writeSuccessResponseJSON(w, encryptedData)
   573  }
   574  
   575  // UpdateServiceAccount - POST /minio/admin/v3/update-service-account
   576  func (a adminAPIHandlers) UpdateServiceAccount(w http.ResponseWriter, r *http.Request) {
   577  	ctx := NewContext(r, w, "UpdateServiceAccount")
   578  
   579  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   580  
   581  	// Get current object layer instance.
   582  	objectAPI := newObjectLayerFn()
   583  	if objectAPI == nil || GlobalNotificationSys == nil {
   584  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   585  		return
   586  	}
   587  
   588  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   589  	if s3Err != ErrNone {
   590  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   591  		return
   592  	}
   593  
   594  	accessKey := mux.Vars(r)["accessKey"]
   595  	if accessKey == "" {
   596  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
   597  		return
   598  	}
   599  
   600  	// Disallow editing service accounts by root user.
   601  	if owner {
   602  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminAccountNotEligible), r.URL)
   603  		return
   604  	}
   605  
   606  	svcAccount, _, err := GlobalIAMSys.GetServiceAccount(ctx, accessKey)
   607  	if err != nil {
   608  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   609  		return
   610  	}
   611  
   612  	if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   613  		AccountName:     cred.AccessKey,
   614  		Action:          iampolicy.UpdateServiceAccountAdminAction,
   615  		ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   616  		IsOwner:         owner,
   617  		Claims:          claims,
   618  	}) {
   619  		requestUser := cred.AccessKey
   620  		if cred.ParentUser != "" {
   621  			requestUser = cred.ParentUser
   622  		}
   623  
   624  		if requestUser != svcAccount.ParentUser {
   625  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   626  			return
   627  		}
   628  	}
   629  
   630  	password := cred.SecretKey
   631  	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength))
   632  	if err != nil {
   633  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   634  		return
   635  	}
   636  
   637  	var updateReq madmin.UpdateServiceAccountReq
   638  	if err = json.Unmarshal(reqBytes, &updateReq); err != nil {
   639  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   640  		return
   641  	}
   642  
   643  	opts := updateServiceAccountOpts{sessionPolicy: updateReq.NewPolicy, secretKey: updateReq.NewSecretKey, status: updateReq.NewStatus}
   644  	err = GlobalIAMSys.UpdateServiceAccount(ctx, accessKey, opts)
   645  	if err != nil {
   646  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   647  		return
   648  	}
   649  
   650  	// Notify all other Minio peers to reload user the service account
   651  	for _, nerr := range GlobalNotificationSys.LoadServiceAccount(accessKey) {
   652  		if nerr.Err != nil {
   653  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   654  			logger.LogIf(ctx, nerr.Err)
   655  		}
   656  	}
   657  
   658  	writeSuccessNoContent(w)
   659  }
   660  
   661  // InfoServiceAccount - GET /minio/admin/v3/info-service-account
   662  func (a adminAPIHandlers) InfoServiceAccount(w http.ResponseWriter, r *http.Request) {
   663  	ctx := NewContext(r, w, "InfoServiceAccount")
   664  
   665  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   666  
   667  	// Get current object layer instance.
   668  	objectAPI := newObjectLayerFn()
   669  	if objectAPI == nil || GlobalNotificationSys == nil {
   670  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   671  		return
   672  	}
   673  
   674  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   675  	if s3Err != ErrNone {
   676  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   677  		return
   678  	}
   679  
   680  	// Disallow creating service accounts by root user.
   681  	if owner {
   682  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminAccountNotEligible), r.URL)
   683  		return
   684  	}
   685  
   686  	accessKey := mux.Vars(r)["accessKey"]
   687  	if accessKey == "" {
   688  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
   689  		return
   690  	}
   691  
   692  	svcAccount, policy, err := GlobalIAMSys.GetServiceAccount(ctx, accessKey)
   693  	if err != nil {
   694  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   695  		return
   696  	}
   697  
   698  	if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   699  		AccountName:     cred.AccessKey,
   700  		Action:          iampolicy.ListServiceAccountsAdminAction,
   701  		ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   702  		IsOwner:         owner,
   703  		Claims:          claims,
   704  	}) {
   705  		requestUser := cred.AccessKey
   706  		if cred.ParentUser != "" {
   707  			requestUser = cred.ParentUser
   708  		}
   709  
   710  		if requestUser != svcAccount.ParentUser {
   711  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   712  			return
   713  		}
   714  	}
   715  
   716  	var svcAccountPolicy iampolicy.Policy
   717  
   718  	impliedPolicy := policy == nil
   719  
   720  	// If policy is empty, check for policy of the parent user
   721  	if !impliedPolicy {
   722  		svcAccountPolicy = svcAccountPolicy.Merge(*policy)
   723  	} else {
   724  		policiesNames, err := GlobalIAMSys.PolicyDBGet(svcAccount.ParentUser, false)
   725  		if err != nil {
   726  			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   727  			return
   728  		}
   729  		svcAccountPolicy = svcAccountPolicy.Merge(GlobalIAMSys.GetCombinedPolicy(policiesNames...))
   730  	}
   731  
   732  	policyJSON, err := json.Marshal(svcAccountPolicy)
   733  	if err != nil {
   734  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   735  		return
   736  	}
   737  
   738  	var infoResp = madmin.InfoServiceAccountResp{
   739  		ParentUser:    svcAccount.ParentUser,
   740  		AccountStatus: svcAccount.Status,
   741  		ImpliedPolicy: impliedPolicy,
   742  		Policy:        string(policyJSON),
   743  	}
   744  
   745  	data, err := json.Marshal(infoResp)
   746  	if err != nil {
   747  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   748  		return
   749  	}
   750  
   751  	encryptedData, err := madmin.EncryptData(cred.SecretKey, data)
   752  	if err != nil {
   753  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   754  		return
   755  	}
   756  
   757  	writeSuccessResponseJSON(w, encryptedData)
   758  }
   759  
   760  // ListServiceAccounts - GET /minio/admin/v3/list-service-accounts
   761  func (a adminAPIHandlers) ListServiceAccounts(w http.ResponseWriter, r *http.Request) {
   762  	ctx := NewContext(r, w, "ListServiceAccounts")
   763  
   764  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   765  
   766  	// Get current object layer instance.
   767  	objectAPI := newObjectLayerFn()
   768  	if objectAPI == nil || GlobalNotificationSys == nil {
   769  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   770  		return
   771  	}
   772  
   773  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   774  	if s3Err != ErrNone {
   775  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   776  		return
   777  	}
   778  
   779  	// Disallow creating service accounts by root user.
   780  	if owner {
   781  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminAccountNotEligible), r.URL)
   782  		return
   783  	}
   784  
   785  	var targetAccount string
   786  
   787  	user := r.URL.Query().Get("user")
   788  	if user != "" {
   789  		if !GlobalIAMSys.IsAllowed(iampolicy.Args{
   790  			AccountName:     cred.AccessKey,
   791  			Action:          iampolicy.ListServiceAccountsAdminAction,
   792  			ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   793  			IsOwner:         owner,
   794  			Claims:          claims,
   795  		}) {
   796  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
   797  			return
   798  		}
   799  		targetAccount = user
   800  	} else {
   801  		targetAccount = cred.AccessKey
   802  		if cred.ParentUser != "" {
   803  			targetAccount = cred.ParentUser
   804  		}
   805  	}
   806  
   807  	serviceAccounts, err := GlobalIAMSys.ListServiceAccounts(ctx, targetAccount)
   808  	if err != nil {
   809  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   810  		return
   811  	}
   812  
   813  	var serviceAccountsNames []string
   814  
   815  	for _, svc := range serviceAccounts {
   816  		serviceAccountsNames = append(serviceAccountsNames, svc.AccessKey)
   817  	}
   818  
   819  	var listResp = madmin.ListServiceAccountsResp{
   820  		Accounts: serviceAccountsNames,
   821  	}
   822  
   823  	data, err := json.Marshal(listResp)
   824  	if err != nil {
   825  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   826  		return
   827  	}
   828  
   829  	encryptedData, err := madmin.EncryptData(cred.SecretKey, data)
   830  	if err != nil {
   831  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   832  		return
   833  	}
   834  
   835  	writeSuccessResponseJSON(w, encryptedData)
   836  }
   837  
   838  // DeleteServiceAccount - DELETE /minio/admin/v3/delete-service-account
   839  func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Request) {
   840  	ctx := NewContext(r, w, "DeleteServiceAccount")
   841  
   842  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   843  
   844  	// Get current object layer instance.
   845  	objectAPI := newObjectLayerFn()
   846  	if objectAPI == nil || GlobalNotificationSys == nil {
   847  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   848  		return
   849  	}
   850  
   851  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   852  	if s3Err != ErrNone {
   853  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   854  		return
   855  	}
   856  
   857  	// Disallow creating service accounts by root user.
   858  	if owner {
   859  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminAccountNotEligible), r.URL)
   860  		return
   861  	}
   862  
   863  	serviceAccount := mux.Vars(r)["accessKey"]
   864  	if serviceAccount == "" {
   865  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminInvalidArgument), r.URL)
   866  		return
   867  	}
   868  
   869  	svcAccount, _, err := GlobalIAMSys.GetServiceAccount(ctx, serviceAccount)
   870  	if err != nil {
   871  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   872  		return
   873  	}
   874  
   875  	adminPrivilege := GlobalIAMSys.IsAllowed(iampolicy.Args{
   876  		AccountName:     cred.AccessKey,
   877  		Action:          iampolicy.RemoveServiceAccountAdminAction,
   878  		ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   879  		IsOwner:         owner,
   880  		Claims:          claims,
   881  	})
   882  
   883  	if !adminPrivilege {
   884  		parentUser := cred.AccessKey
   885  		if cred.ParentUser != "" {
   886  			parentUser = cred.ParentUser
   887  		}
   888  		if parentUser != svcAccount.ParentUser {
   889  			// The service account belongs to another user but return not
   890  			// found error to mitigate brute force attacks. or the
   891  			// serviceAccount doesn't exist.
   892  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminServiceAccountNotFound), r.URL)
   893  			return
   894  		}
   895  	}
   896  
   897  	err = GlobalIAMSys.DeleteServiceAccount(ctx, serviceAccount)
   898  	if err != nil {
   899  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   900  		return
   901  	}
   902  
   903  	writeSuccessNoContent(w)
   904  }
   905  
   906  // AccountInfoHandler returns usage
   907  func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Request) {
   908  	ctx := NewContext(r, w, "AccountInfo")
   909  
   910  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   911  
   912  	// Get current object layer instance.
   913  	objectAPI := newObjectLayerFn()
   914  	if objectAPI == nil || GlobalNotificationSys == nil {
   915  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   916  		return
   917  	}
   918  
   919  	cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
   920  	if s3Err != ErrNone {
   921  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   922  		return
   923  	}
   924  
   925  	// Set prefix value for "s3:prefix" policy conditionals.
   926  	r.Header.Set("prefix", "")
   927  
   928  	// Set delimiter value for "s3:delimiter" policy conditionals.
   929  	r.Header.Set("delimiter", SlashSeparator)
   930  
   931  	isAllowedAccess := func(bucketName string) (rd, wr bool) {
   932  		// Use the following trick to filter in place
   933  		// https://github.com/golang/go/wiki/SliceTricks#filter-in-place
   934  		if GlobalIAMSys.IsAllowed(iampolicy.Args{
   935  			AccountName:     cred.AccessKey,
   936  			Groups:          cred.Groups,
   937  			Action:          iampolicy.ListBucketAction,
   938  			BucketName:      bucketName,
   939  			ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   940  			IsOwner:         owner,
   941  			ObjectName:      "",
   942  			Claims:          claims,
   943  		}) {
   944  			rd = true
   945  		}
   946  
   947  		if GlobalIAMSys.IsAllowed(iampolicy.Args{
   948  			AccountName:     cred.AccessKey,
   949  			Groups:          cred.Groups,
   950  			Action:          iampolicy.PutObjectAction,
   951  			BucketName:      bucketName,
   952  			ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
   953  			IsOwner:         owner,
   954  			ObjectName:      "",
   955  			Claims:          claims,
   956  		}) {
   957  			wr = true
   958  		}
   959  
   960  		return rd, wr
   961  	}
   962  
   963  	// Load the latest calculated data usage
   964  	dataUsageInfo, err := loadDataUsageFromBackend(ctx, objectAPI)
   965  	if err != nil {
   966  		// log the error, continue with the accounting response
   967  		logger.LogIf(ctx, err)
   968  	}
   969  
   970  	buckets, err := objectAPI.ListBuckets(ctx)
   971  	if err != nil {
   972  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   973  		return
   974  	}
   975  
   976  	accountName := cred.AccessKey
   977  	var policies []string
   978  	switch GlobalIAMSys.usersSysType {
   979  	case MinIOUsersSysType:
   980  		policies, err = GlobalIAMSys.PolicyDBGet(accountName, false)
   981  	case LDAPUsersSysType:
   982  		parentUser := accountName
   983  		if cred.ParentUser != "" {
   984  			parentUser = cred.ParentUser
   985  		}
   986  		policies, err = GlobalIAMSys.PolicyDBGet(parentUser, false, cred.Groups...)
   987  	default:
   988  		err = errors.New("should not happen!")
   989  	}
   990  	if err != nil {
   991  		logger.LogIf(ctx, err)
   992  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   993  		return
   994  	}
   995  
   996  	acctInfo := madmin.AccountInfo{
   997  		AccountName: accountName,
   998  		Policy:      GlobalIAMSys.GetCombinedPolicy(policies...),
   999  	}
  1000  
  1001  	for _, bucket := range buckets {
  1002  		rd, wr := isAllowedAccess(bucket.Name)
  1003  		if rd || wr {
  1004  			var size uint64
  1005  			// Fetch the data usage of the current bucket
  1006  			if !dataUsageInfo.LastUpdate.IsZero() {
  1007  				size = dataUsageInfo.BucketsUsage[bucket.Name].Size
  1008  			}
  1009  			acctInfo.Buckets = append(acctInfo.Buckets, madmin.BucketAccessInfo{
  1010  				Name:    bucket.Name,
  1011  				Created: bucket.Created,
  1012  				Size:    size,
  1013  				Access: madmin.AccountAccess{
  1014  					Read:  rd,
  1015  					Write: wr,
  1016  				},
  1017  			})
  1018  		}
  1019  	}
  1020  
  1021  	usageInfoJSON, err := json.Marshal(acctInfo)
  1022  	if err != nil {
  1023  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1024  		return
  1025  	}
  1026  
  1027  	writeSuccessResponseJSON(w, usageInfoJSON)
  1028  }
  1029  
  1030  // InfoCannedPolicyV2 - GET /minio/admin/v2/info-canned-policy?name={policyName}
  1031  func (a adminAPIHandlers) InfoCannedPolicyV2(w http.ResponseWriter, r *http.Request) {
  1032  	ctx := NewContext(r, w, "InfoCannedPolicyV2")
  1033  
  1034  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1035  
  1036  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.GetPolicyAdminAction)
  1037  	if objectAPI == nil {
  1038  		return
  1039  	}
  1040  
  1041  	policy, err := GlobalIAMSys.InfoPolicy(mux.Vars(r)["name"])
  1042  	if err != nil {
  1043  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1044  		return
  1045  	}
  1046  
  1047  	data, err := json.Marshal(policy)
  1048  	if err != nil {
  1049  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1050  		return
  1051  	}
  1052  
  1053  	w.Write(data)
  1054  	w.(http.Flusher).Flush()
  1055  }
  1056  
  1057  // InfoCannedPolicy - GET /minio/admin/v3/info-canned-policy?name={policyName}
  1058  func (a adminAPIHandlers) InfoCannedPolicy(w http.ResponseWriter, r *http.Request) {
  1059  	ctx := NewContext(r, w, "InfoCannedPolicy")
  1060  
  1061  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1062  
  1063  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.GetPolicyAdminAction)
  1064  	if objectAPI == nil {
  1065  		return
  1066  	}
  1067  
  1068  	policy, err := GlobalIAMSys.InfoPolicy(mux.Vars(r)["name"])
  1069  	if err != nil {
  1070  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1071  		return
  1072  	}
  1073  
  1074  	if err = json.NewEncoder(w).Encode(policy); err != nil {
  1075  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1076  		return
  1077  	}
  1078  	w.(http.Flusher).Flush()
  1079  }
  1080  
  1081  // ListCannedPoliciesV2 - GET /minio/admin/v2/list-canned-policies
  1082  func (a adminAPIHandlers) ListCannedPoliciesV2(w http.ResponseWriter, r *http.Request) {
  1083  	ctx := NewContext(r, w, "ListCannedPoliciesV2")
  1084  
  1085  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1086  
  1087  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.ListUserPoliciesAdminAction)
  1088  	if objectAPI == nil {
  1089  		return
  1090  	}
  1091  
  1092  	policies, err := GlobalIAMSys.ListPolicies()
  1093  	if err != nil {
  1094  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1095  		return
  1096  	}
  1097  
  1098  	policyMap := make(map[string][]byte, len(policies))
  1099  	for k, p := range policies {
  1100  		var err error
  1101  		policyMap[k], err = json.Marshal(p)
  1102  		if err != nil {
  1103  			logger.LogIf(ctx, err)
  1104  			continue
  1105  		}
  1106  	}
  1107  	if err = json.NewEncoder(w).Encode(policyMap); err != nil {
  1108  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1109  		return
  1110  	}
  1111  
  1112  	w.(http.Flusher).Flush()
  1113  }
  1114  
  1115  // ListCannedPolicies - GET /minio/admin/v3/list-canned-policies
  1116  func (a adminAPIHandlers) ListCannedPolicies(w http.ResponseWriter, r *http.Request) {
  1117  	ctx := NewContext(r, w, "ListCannedPolicies")
  1118  
  1119  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1120  
  1121  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.ListUserPoliciesAdminAction)
  1122  	if objectAPI == nil {
  1123  		return
  1124  	}
  1125  
  1126  	policies, err := GlobalIAMSys.ListPolicies()
  1127  	if err != nil {
  1128  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1129  		return
  1130  	}
  1131  
  1132  	var newPolicies = make(map[string]iampolicy.Policy)
  1133  	for name, p := range policies {
  1134  		_, err = json.Marshal(p)
  1135  		if err != nil {
  1136  			logger.LogIf(ctx, err)
  1137  			continue
  1138  		}
  1139  		newPolicies[name] = p
  1140  	}
  1141  	if err = json.NewEncoder(w).Encode(newPolicies); err != nil {
  1142  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1143  		return
  1144  	}
  1145  
  1146  	w.(http.Flusher).Flush()
  1147  }
  1148  
  1149  // RemoveCannedPolicy - DELETE /minio/admin/v3/remove-canned-policy?name=<policy_name>
  1150  func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Request) {
  1151  	ctx := NewContext(r, w, "RemoveCannedPolicy")
  1152  
  1153  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1154  
  1155  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.DeletePolicyAdminAction)
  1156  	if objectAPI == nil {
  1157  		return
  1158  	}
  1159  
  1160  	vars := mux.Vars(r)
  1161  	policyName := vars["name"]
  1162  
  1163  	if err := GlobalIAMSys.DeletePolicy(policyName); err != nil {
  1164  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1165  		return
  1166  	}
  1167  
  1168  	// Notify all other MinIO peers to delete policy
  1169  	for _, nerr := range GlobalNotificationSys.DeletePolicy(policyName) {
  1170  		if nerr.Err != nil {
  1171  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
  1172  			logger.LogIf(ctx, nerr.Err)
  1173  		}
  1174  	}
  1175  }
  1176  
  1177  // AddCannedPolicy - PUT /minio/admin/v3/add-canned-policy?name=<policy_name>
  1178  func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request) {
  1179  	ctx := NewContext(r, w, "AddCannedPolicy")
  1180  
  1181  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1182  
  1183  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.CreatePolicyAdminAction)
  1184  	if objectAPI == nil {
  1185  		return
  1186  	}
  1187  
  1188  	vars := mux.Vars(r)
  1189  	policyName := vars["name"]
  1190  
  1191  	// Error out if Content-Length is missing.
  1192  	if r.ContentLength <= 0 {
  1193  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL)
  1194  		return
  1195  	}
  1196  
  1197  	// Error out if Content-Length is beyond allowed size.
  1198  	if r.ContentLength > maxBucketPolicySize {
  1199  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL)
  1200  		return
  1201  	}
  1202  
  1203  	iamPolicy, err := iampolicy.ParseConfig(io.LimitReader(r.Body, r.ContentLength))
  1204  	if err != nil {
  1205  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1206  		return
  1207  	}
  1208  
  1209  	// Version in policy must not be empty
  1210  	if iamPolicy.Version == "" {
  1211  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMalformedPolicy), r.URL)
  1212  		return
  1213  	}
  1214  
  1215  	if err = GlobalIAMSys.SetPolicy(policyName, *iamPolicy); err != nil {
  1216  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1217  		return
  1218  	}
  1219  
  1220  	// Notify all other MinIO peers to reload policy
  1221  	for _, nerr := range GlobalNotificationSys.LoadPolicy(policyName) {
  1222  		if nerr.Err != nil {
  1223  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
  1224  			logger.LogIf(ctx, nerr.Err)
  1225  		}
  1226  	}
  1227  }
  1228  
  1229  // SetPolicyForUserOrGroup - PUT /minio/admin/v3/set-policy?policy=xxx&user-or-group=?[&is-group]
  1230  func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http.Request) {
  1231  	ctx := NewContext(r, w, "SetPolicyForUserOrGroup")
  1232  
  1233  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
  1234  
  1235  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.AttachPolicyAdminAction)
  1236  	if objectAPI == nil {
  1237  		return
  1238  	}
  1239  
  1240  	vars := mux.Vars(r)
  1241  	policyName := vars["policyName"]
  1242  	entityName := vars["userOrGroup"]
  1243  	isGroup := vars["isGroup"] == "true"
  1244  
  1245  	if !isGroup {
  1246  		ok, _, err := GlobalIAMSys.IsTempUser(entityName)
  1247  		if err != nil && err != errNoSuchUser {
  1248  			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1249  			return
  1250  		}
  1251  		if ok {
  1252  			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL)
  1253  			return
  1254  		}
  1255  	}
  1256  
  1257  	if err := GlobalIAMSys.PolicyDBSet(entityName, policyName, isGroup); err != nil {
  1258  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
  1259  		return
  1260  	}
  1261  
  1262  	// Notify all other MinIO peers to reload policy
  1263  	for _, nerr := range GlobalNotificationSys.LoadPolicyMapping(entityName, isGroup) {
  1264  		if nerr.Err != nil {
  1265  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
  1266  			logger.LogIf(ctx, nerr.Err)
  1267  		}
  1268  	}
  1269  }