github.com/minio/console@v1.4.1/api/admin_users.go (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2021 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "context" 21 "fmt" 22 "sort" 23 "strings" 24 25 "github.com/minio/console/pkg/utils" 26 27 "github.com/go-openapi/errors" 28 "github.com/go-openapi/runtime/middleware" 29 "github.com/minio/console/api/operations" 30 accountApi "github.com/minio/console/api/operations/account" 31 bucketApi "github.com/minio/console/api/operations/bucket" 32 userApi "github.com/minio/console/api/operations/user" 33 "github.com/minio/console/models" 34 "github.com/minio/madmin-go/v3" 35 iampolicy "github.com/minio/pkg/v3/policy" 36 ) 37 38 // Policy evaluated constants 39 const ( 40 Unknown = 0 41 Allow = 1 42 Deny = -1 43 ) 44 45 func registerUsersHandlers(api *operations.ConsoleAPI) { 46 // List Users 47 api.UserListUsersHandler = userApi.ListUsersHandlerFunc(func(params userApi.ListUsersParams, session *models.Principal) middleware.Responder { 48 listUsersResponse, err := getListUsersResponse(session, params) 49 if err != nil { 50 return userApi.NewListUsersDefault(err.Code).WithPayload(err.APIError) 51 } 52 return userApi.NewListUsersOK().WithPayload(listUsersResponse) 53 }) 54 // Add User 55 api.UserAddUserHandler = userApi.AddUserHandlerFunc(func(params userApi.AddUserParams, session *models.Principal) middleware.Responder { 56 userResponse, err := getUserAddResponse(session, params) 57 if err != nil { 58 return userApi.NewAddUserDefault(err.Code).WithPayload(err.APIError) 59 } 60 return userApi.NewAddUserCreated().WithPayload(userResponse) 61 }) 62 // Remove User 63 api.UserRemoveUserHandler = userApi.RemoveUserHandlerFunc(func(params userApi.RemoveUserParams, session *models.Principal) middleware.Responder { 64 err := getRemoveUserResponse(session, params) 65 if err != nil { 66 return userApi.NewRemoveUserDefault(err.Code).WithPayload(err.APIError) 67 } 68 return userApi.NewRemoveUserNoContent() 69 }) 70 // Update User-Groups 71 api.UserUpdateUserGroupsHandler = userApi.UpdateUserGroupsHandlerFunc(func(params userApi.UpdateUserGroupsParams, session *models.Principal) middleware.Responder { 72 userUpdateResponse, err := getUpdateUserGroupsResponse(session, params) 73 if err != nil { 74 return userApi.NewUpdateUserGroupsDefault(err.Code).WithPayload(err.APIError) 75 } 76 77 return userApi.NewUpdateUserGroupsOK().WithPayload(userUpdateResponse) 78 }) 79 // Get User 80 api.UserGetUserInfoHandler = userApi.GetUserInfoHandlerFunc(func(params userApi.GetUserInfoParams, session *models.Principal) middleware.Responder { 81 userInfoResponse, err := getUserInfoResponse(session, params) 82 if err != nil { 83 return userApi.NewGetUserInfoDefault(err.Code).WithPayload(err.APIError) 84 } 85 86 return userApi.NewGetUserInfoOK().WithPayload(userInfoResponse) 87 }) 88 // Update User 89 api.UserUpdateUserInfoHandler = userApi.UpdateUserInfoHandlerFunc(func(params userApi.UpdateUserInfoParams, session *models.Principal) middleware.Responder { 90 userUpdateResponse, err := getUpdateUserResponse(session, params) 91 if err != nil { 92 return userApi.NewUpdateUserInfoDefault(err.Code).WithPayload(err.APIError) 93 } 94 95 return userApi.NewUpdateUserInfoOK().WithPayload(userUpdateResponse) 96 }) 97 // Update User-Groups Bulk 98 api.UserBulkUpdateUsersGroupsHandler = userApi.BulkUpdateUsersGroupsHandlerFunc(func(params userApi.BulkUpdateUsersGroupsParams, session *models.Principal) middleware.Responder { 99 err := getAddUsersListToGroupsResponse(session, params) 100 if err != nil { 101 return userApi.NewBulkUpdateUsersGroupsDefault(err.Code).WithPayload(err.APIError) 102 } 103 104 return userApi.NewBulkUpdateUsersGroupsOK() 105 }) 106 api.BucketListUsersWithAccessToBucketHandler = bucketApi.ListUsersWithAccessToBucketHandlerFunc(func(params bucketApi.ListUsersWithAccessToBucketParams, session *models.Principal) middleware.Responder { 107 response, err := getListUsersWithAccessToBucketResponse(session, params) 108 if err != nil { 109 return bucketApi.NewListUsersWithAccessToBucketDefault(err.Code).WithPayload(err.APIError) 110 } 111 return bucketApi.NewListUsersWithAccessToBucketOK().WithPayload(response) 112 }) 113 // Change User Password 114 api.AccountChangeUserPasswordHandler = accountApi.ChangeUserPasswordHandlerFunc(func(params accountApi.ChangeUserPasswordParams, session *models.Principal) middleware.Responder { 115 err := getChangeUserPasswordResponse(session, params) 116 if err != nil { 117 return accountApi.NewChangeUserPasswordDefault(err.Code).WithPayload(err.APIError) 118 } 119 return accountApi.NewChangeUserPasswordCreated() 120 }) 121 // Check number of Service Accounts for listed users 122 api.UserCheckUserServiceAccountsHandler = userApi.CheckUserServiceAccountsHandlerFunc(func(params userApi.CheckUserServiceAccountsParams, session *models.Principal) middleware.Responder { 123 userSAList, err := getCheckUserSAResponse(session, params) 124 if err != nil { 125 return userApi.NewCheckUserServiceAccountsDefault(err.Code).WithPayload(err.APIError) 126 } 127 return userApi.NewCheckUserServiceAccountsOK().WithPayload(userSAList) 128 }) 129 } 130 131 func listUsers(ctx context.Context, client MinioAdmin) ([]*models.User, error) { 132 // Get list of all users in the MinIO 133 // This call requires explicit authentication, no anonymous requests are 134 // allowed for listing users. 135 userMap, err := client.listUsers(ctx) 136 if err != nil { 137 return []*models.User{}, err 138 } 139 140 var users []*models.User 141 for accessKey, user := range userMap { 142 userElem := &models.User{ 143 AccessKey: accessKey, 144 Status: string(user.Status), 145 Policy: strings.Split(user.PolicyName, ","), 146 MemberOf: user.MemberOf, 147 } 148 users = append(users, userElem) 149 } 150 151 return users, nil 152 } 153 154 // getListUsersResponse performs listUsers() and serializes it to the handler's output 155 func getListUsersResponse(session *models.Principal, params userApi.ListUsersParams) (*models.ListUsersResponse, *CodedAPIError) { 156 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 157 defer cancel() 158 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 159 if err != nil { 160 return nil, ErrorWithContext(ctx, err) 161 } 162 // create a minioClient interface implementation 163 // defining the client to be used 164 adminClient := AdminClient{Client: mAdmin} 165 users, err := listUsers(ctx, adminClient) 166 if err != nil { 167 return nil, ErrorWithContext(ctx, err) 168 } 169 // serialize output 170 listUsersResponse := &models.ListUsersResponse{ 171 Users: users, 172 } 173 return listUsersResponse, nil 174 } 175 176 // addUser invokes adding a users on `MinioAdmin` and builds the response `models.User` 177 func addUser(ctx context.Context, client MinioAdmin, accessKey, secretKey *string, groups []string, policies []string) (*models.User, error) { 178 // Calls into MinIO to add a new user if there's an errors return it 179 if err := client.addUser(ctx, *accessKey, *secretKey); err != nil { 180 return nil, err 181 } 182 // set groups for the newly created user 183 var userWithGroups *models.User 184 if len(groups) > 0 { 185 var errUG error 186 userWithGroups, errUG = updateUserGroups(ctx, client, *accessKey, groups) 187 188 if errUG != nil { 189 return nil, errUG 190 } 191 } 192 // set policies for the newly created user 193 if len(policies) > 0 { 194 policyString := strings.Join(policies, ",") 195 if err := SetPolicy(ctx, client, policyString, *accessKey, "user"); err != nil { 196 return nil, err 197 } 198 } 199 200 memberOf := []string{} 201 status := "enabled" 202 if userWithGroups != nil { 203 memberOf = userWithGroups.MemberOf 204 status = userWithGroups.Status 205 } 206 207 userRet := &models.User{ 208 AccessKey: *accessKey, 209 MemberOf: memberOf, 210 Policy: policies, 211 Status: status, 212 } 213 return userRet, nil 214 } 215 216 func getUserAddResponse(session *models.Principal, params userApi.AddUserParams) (*models.User, *CodedAPIError) { 217 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 218 defer cancel() 219 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 220 if err != nil { 221 return nil, ErrorWithContext(ctx, err) 222 } 223 // create a minioClient interface implementation 224 // defining the client to be used 225 adminClient := AdminClient{Client: mAdmin} 226 var userExists bool 227 228 _, err = adminClient.getUserInfo(ctx, *params.Body.AccessKey) 229 userExists = err == nil 230 231 if userExists { 232 return nil, ErrorWithContext(ctx, ErrNonUniqueAccessKey) 233 } 234 user, err := addUser( 235 ctx, 236 adminClient, 237 params.Body.AccessKey, 238 params.Body.SecretKey, 239 params.Body.Groups, 240 params.Body.Policies, 241 ) 242 if err != nil { 243 return nil, ErrorWithContext(ctx, err) 244 } 245 return user, nil 246 } 247 248 // removeUser invokes removing an user on `MinioAdmin`, then we return the response from API 249 func removeUser(ctx context.Context, client MinioAdmin, accessKey string) error { 250 return client.removeUser(ctx, accessKey) 251 } 252 253 func getRemoveUserResponse(session *models.Principal, params userApi.RemoveUserParams) *CodedAPIError { 254 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 255 defer cancel() 256 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 257 if err != nil { 258 return ErrorWithContext(ctx, err) 259 } 260 userName, err := utils.DecodeBase64(params.Name) 261 if err != nil { 262 return ErrorWithContext(ctx, err) 263 } 264 if session.AccountAccessKey == userName { 265 return ErrorWithContext(ctx, ErrAvoidSelfAccountDelete) 266 } 267 // create a minioClient interface implementation 268 // defining the client to be used 269 adminClient := AdminClient{Client: mAdmin} 270 if err := removeUser(ctx, adminClient, userName); err != nil { 271 return ErrorWithContext(ctx, err) 272 } 273 return nil 274 } 275 276 // getUserInfo calls MinIO server get the User Information 277 func getUserInfo(ctx context.Context, client MinioAdmin, accessKey string) (*madmin.UserInfo, error) { 278 userInfo, err := client.getUserInfo(ctx, accessKey) 279 if err != nil { 280 return nil, err 281 } 282 return &userInfo, nil 283 } 284 285 func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoParams) (*models.User, *CodedAPIError) { 286 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 287 defer cancel() 288 289 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 290 if err != nil { 291 return nil, ErrorWithContext(ctx, err) 292 } 293 294 // create a minioClient interface implementation 295 // defining the client to be used 296 adminClient := AdminClient{Client: mAdmin} 297 298 userName, err := utils.DecodeBase64(params.Name) 299 if err != nil { 300 return nil, ErrorWithContext(ctx, err) 301 } 302 303 user, err := getUserInfo(ctx, adminClient, userName) 304 if err != nil { 305 // User doesn't exist, return 404 306 if madmin.ToErrorResponse(err).Code == "XMinioAdminNoSuchUser" { 307 errorCode := 404 308 errorMessage := "User doesn't exist" 309 return nil, &CodedAPIError{Code: errorCode, APIError: &models.APIError{Message: errorMessage, DetailedMessage: err.Error()}} 310 } 311 return nil, ErrorWithContext(ctx, err) 312 } 313 314 var policies []string 315 if user.PolicyName == "" { 316 policies = []string{} 317 } else { 318 policies = strings.Split(user.PolicyName, ",") 319 } 320 321 hasPolicy := true 322 323 if len(policies) == 0 { 324 hasPolicy = false 325 for i := 0; i < len(user.MemberOf); i++ { 326 group, err := adminClient.getGroupDescription(ctx, user.MemberOf[i]) 327 if err != nil { 328 continue 329 } 330 if group.Policy != "" { 331 hasPolicy = true 332 break 333 } 334 } 335 } 336 337 userInformation := &models.User{ 338 AccessKey: userName, 339 MemberOf: user.MemberOf, 340 Policy: policies, 341 Status: string(user.Status), 342 HasPolicy: hasPolicy, 343 } 344 345 return userInformation, nil 346 } 347 348 // updateUserGroups invokes getUserInfo() to get the old groups from the user, 349 // then we merge the list with the new groups list to have a shorter iteration between groups and we do a comparison between the current and old groups. 350 // We delete or update the groups according the location in each list and send the user with the new groups from `MinioAdmin` to the client 351 func updateUserGroups(ctx context.Context, client MinioAdmin, user string, groupsToAssign []string) (*models.User, error) { 352 parallelUserUpdate := func(groupName string, originGroups []string) chan error { 353 chProcess := make(chan error) 354 355 go func() error { 356 defer close(chProcess) 357 358 // Compare if groupName is in the arrays 359 isGroupPersistent := IsElementInArray(groupsToAssign, groupName) 360 isInOriginGroups := IsElementInArray(originGroups, groupName) 361 362 if isGroupPersistent && isInOriginGroups { // Group is already assigned and doesn't need to be updated 363 chProcess <- nil 364 365 return nil 366 } 367 368 isRemove := false // User is added by default 369 370 // User is deleted from the group 371 if !isGroupPersistent { 372 isRemove = true 373 } 374 375 userToAddRemove := []string{user} 376 377 updateReturn := updateGroupMembers(ctx, client, groupName, userToAddRemove, isRemove) 378 379 chProcess <- updateReturn 380 381 return updateReturn 382 }() 383 384 return chProcess 385 } 386 387 userInfoOr, err := getUserInfo(ctx, client, user) 388 if err != nil { 389 return nil, err 390 } 391 392 memberOf := userInfoOr.MemberOf 393 mergedGroupArray := UniqueKeys(append(memberOf, groupsToAssign...)) 394 395 var listOfUpdates []chan error 396 397 // Each group must be updated individually because there is no way to update all the groups at once for a user, 398 // we are using the same logic as 'mc admin group add' command 399 for _, groupN := range mergedGroupArray { 400 proc := parallelUserUpdate(groupN, memberOf) 401 listOfUpdates = append(listOfUpdates, proc) 402 } 403 404 channelHasError := false 405 406 for _, chanRet := range listOfUpdates { 407 locError := <-chanRet 408 409 if locError != nil { 410 channelHasError = true 411 } 412 } 413 414 if channelHasError { 415 errRt := errors.New(500, "there was an error updating the groups") 416 return nil, errRt 417 } 418 419 userInfo, err := getUserInfo(ctx, client, user) 420 if err != nil { 421 return nil, err 422 } 423 424 policies := strings.Split(userInfo.PolicyName, ",") 425 426 userReturn := &models.User{ 427 AccessKey: user, 428 MemberOf: userInfo.MemberOf, 429 Policy: policies, 430 Status: string(userInfo.Status), 431 } 432 433 return userReturn, nil 434 } 435 436 func getUpdateUserGroupsResponse(session *models.Principal, params userApi.UpdateUserGroupsParams) (*models.User, *CodedAPIError) { 437 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 438 defer cancel() 439 440 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 441 if err != nil { 442 return nil, ErrorWithContext(ctx, err) 443 } 444 445 // create a minioClient interface implementation 446 // defining the client to be used 447 adminClient := AdminClient{Client: mAdmin} 448 449 userName, err := utils.DecodeBase64(params.Name) 450 if err != nil { 451 return nil, ErrorWithContext(ctx, err) 452 } 453 454 user, err := updateUserGroups(ctx, adminClient, userName, params.Body.Groups) 455 if err != nil { 456 return nil, ErrorWithContext(ctx, err) 457 } 458 459 return user, nil 460 } 461 462 // setUserStatus invokes setUserStatus from madmin to update user status 463 func setUserStatus(ctx context.Context, client MinioAdmin, user string, status string) error { 464 var setStatus madmin.AccountStatus 465 switch status { 466 case "enabled": 467 setStatus = madmin.AccountEnabled 468 case "disabled": 469 setStatus = madmin.AccountDisabled 470 default: 471 return errors.New(500, "status not valid") 472 } 473 474 return client.setUserStatus(ctx, user, setStatus) 475 } 476 477 func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserInfoParams) (*models.User, *CodedAPIError) { 478 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 479 defer cancel() 480 481 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 482 if err != nil { 483 return nil, ErrorWithContext(ctx, err) 484 } 485 486 // create a minioClient interface implementation 487 // defining the client to be used 488 adminClient := AdminClient{Client: mAdmin} 489 userName, err := utils.DecodeBase64(params.Name) 490 if err != nil { 491 return nil, ErrorWithContext(ctx, err) 492 } 493 status := *params.Body.Status 494 groups := params.Body.Groups 495 496 if err := setUserStatus(ctx, adminClient, userName, status); err != nil { 497 return nil, ErrorWithContext(ctx, err) 498 } 499 500 userElem, errUG := updateUserGroups(ctx, adminClient, userName, groups) 501 502 if errUG != nil { 503 return nil, ErrorWithContext(ctx, errUG) 504 } 505 return userElem, nil 506 } 507 508 // addUsersListToGroups iterates over the user list & assigns the requested groups to each user. 509 func addUsersListToGroups(ctx context.Context, client MinioAdmin, usersToUpdate []string, groupsToAssign []string) error { 510 // We update each group with the complete usersList 511 parallelGroupsUpdate := func(groupToAssign string) chan error { 512 groupProcess := make(chan error) 513 514 go func() { 515 defer close(groupProcess) 516 // We add the users array to the group. 517 err := updateGroupMembers(ctx, client, groupToAssign, usersToUpdate, false) 518 519 groupProcess <- err 520 }() 521 return groupProcess 522 } 523 524 var groupsUpdateList []chan error 525 526 // We get each group name & add users accordingly 527 for _, groupName := range groupsToAssign { 528 // We update the group 529 proc := parallelGroupsUpdate(groupName) 530 groupsUpdateList = append(groupsUpdateList, proc) 531 } 532 533 errorsList := []string{} // We get the errors list because we want to have all errors at once. 534 for _, err := range groupsUpdateList { 535 errorFromUpdate := <-err // We store the errors to avoid Data Race 536 if errorFromUpdate != nil { 537 // If there is an errors, we store the errors strings so we can join them after we receive all errors 538 errorsList = append(errorsList, errorFromUpdate.Error()) // We wait until all the channels have been closed. 539 } 540 } 541 542 // If there are errors, we throw the final errors with the errors inside 543 if len(errorsList) > 0 { 544 errGen := fmt.Errorf("error in users-groups assignation: %q", strings.Join(errorsList, ",")) 545 return errGen 546 } 547 548 return nil 549 } 550 551 func getAddUsersListToGroupsResponse(session *models.Principal, params userApi.BulkUpdateUsersGroupsParams) *CodedAPIError { 552 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 553 defer cancel() 554 555 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 556 if err != nil { 557 return ErrorWithContext(ctx, err) 558 } 559 560 // create a minioClient interface implementation 561 // defining the client to be used 562 adminClient := AdminClient{Client: mAdmin} 563 564 usersList := params.Body.Users 565 groupsList := params.Body.Groups 566 567 if err := addUsersListToGroups(ctx, adminClient, usersList, groupsList); err != nil { 568 return ErrorWithContext(ctx, err) 569 } 570 571 return nil 572 } 573 574 func getListUsersWithAccessToBucketResponse(session *models.Principal, params bucketApi.ListUsersWithAccessToBucketParams) ([]string, *CodedAPIError) { 575 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 576 defer cancel() 577 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 578 if err != nil { 579 return nil, ErrorWithContext(ctx, err) 580 } 581 // create a minioClient interface implementation 582 // defining the client to be used 583 adminClient := AdminClient{Client: mAdmin} 584 list, err := listUsersWithAccessToBucket(ctx, adminClient, params.Bucket) 585 if err != nil { 586 return nil, ErrorWithContext(ctx, err) 587 } 588 return list, nil 589 } 590 591 func policyAllowsAndMatchesBucket(policy *iampolicy.Policy, bucket string) int { 592 policyStatements := policy.Statements 593 for i := 0; i < len(policyStatements); i++ { 594 resources := policyStatements[i].Resources 595 effect := policyStatements[i].Effect 596 if resources.Match(bucket, map[string][]string{}) { 597 if effect.IsValid() { 598 if effect.IsAllowed(true) { 599 return Allow 600 } 601 return Deny 602 } 603 } 604 } 605 return Unknown 606 } 607 608 func listUsersWithAccessToBucket(ctx context.Context, adminClient MinioAdmin, bucket string) ([]string, error) { 609 users, err := adminClient.listUsers(ctx) 610 if err != nil { 611 return nil, err 612 } 613 var retval []string 614 akHasAccess := make(map[string]struct{}) 615 akIsDenied := make(map[string]struct{}) 616 for k, v := range users { 617 for _, policyName := range strings.Split(v.PolicyName, ",") { 618 policyName = strings.TrimSpace(policyName) 619 if policyName == "" { 620 continue 621 } 622 policy, err := adminClient.getPolicy(ctx, policyName) 623 if err != nil { 624 ErrorWithContext(ctx, fmt.Errorf("unable to fetch policy %s: %v", policyName, err)) 625 continue 626 } 627 if _, ok := akIsDenied[k]; !ok { 628 switch policyAllowsAndMatchesBucket(policy, bucket) { 629 case Allow: 630 if _, ok := akHasAccess[k]; !ok { 631 akHasAccess[k] = struct{}{} 632 } 633 case Deny: 634 akIsDenied[k] = struct{}{} 635 delete(akHasAccess, k) 636 } 637 } 638 } 639 } 640 641 groups, err := adminClient.listGroups(ctx) 642 if err != nil { 643 ErrorWithContext(ctx, fmt.Errorf("unable to list groups: %v", err)) 644 return retval, nil 645 } 646 647 for _, groupName := range groups { 648 info, err := groupInfo(ctx, adminClient, groupName) 649 if err != nil { 650 ErrorWithContext(ctx, fmt.Errorf("unable to fetch group info %s: %v", groupName, err)) 651 continue 652 } 653 policy, err := adminClient.getPolicy(ctx, info.Policy) 654 if err != nil { 655 ErrorWithContext(ctx, fmt.Errorf("unable to fetch group policy %s: %v", info.Policy, err)) 656 continue 657 } 658 for _, member := range info.Members { 659 if _, ok := akIsDenied[member]; !ok { 660 switch policyAllowsAndMatchesBucket(policy, bucket) { 661 case Allow: 662 if _, ok := akHasAccess[member]; !ok { 663 akHasAccess[member] = struct{}{} 664 } 665 case Deny: 666 akIsDenied[member] = struct{}{} 667 delete(akHasAccess, member) 668 } 669 } 670 } 671 } 672 for k := range akHasAccess { 673 retval = append(retval, k) 674 } 675 sort.Strings(retval) 676 return retval, nil 677 } 678 679 // changeUserPassword changes password of selectedUser to newSecretKey 680 func changeUserPassword(ctx context.Context, client MinioAdmin, selectedUser string, newSecretKey string) error { 681 return client.changePassword(ctx, selectedUser, newSecretKey) 682 } 683 684 // getChangeUserPasswordResponse will change the password of selctedUser to newSecretKey 685 func getChangeUserPasswordResponse(session *models.Principal, params accountApi.ChangeUserPasswordParams) *CodedAPIError { 686 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 687 defer cancel() 688 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 689 if err != nil { 690 return ErrorWithContext(ctx, err) 691 } 692 // create a minioClient interface implementation 693 // defining the client to be used 694 adminClient := AdminClient{Client: mAdmin} 695 696 // params will contain selectedUser and newSecretKey credentials for the user 697 user := *params.Body.SelectedUser 698 newSecretKey := *params.Body.NewSecretKey 699 700 // changes password of user to newSecretKey 701 if err := changeUserPassword(ctx, adminClient, user, newSecretKey); err != nil { 702 return ErrorWithContext(ctx, err) 703 } 704 return nil 705 } 706 707 func getCheckUserSAResponse(session *models.Principal, params userApi.CheckUserServiceAccountsParams) (*models.UserServiceAccountSummary, *CodedAPIError) { 708 ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) 709 defer cancel() 710 mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) 711 if err != nil { 712 return nil, ErrorWithContext(ctx, err) 713 } 714 // create a minioClient interface implementation 715 // defining the client to be used 716 adminClient := AdminClient{Client: mAdmin} 717 718 var userServiceAccountList []*models.UserServiceAccountItem 719 hasSA := false 720 for _, user := range params.SelectedUsers { 721 listServAccs, err := adminClient.listServiceAccounts(ctx, user) 722 if err != nil { 723 return nil, ErrorWithContext(ctx, err) 724 } 725 numSAs := int64(len(listServAccs.Accounts)) 726 if numSAs > 0 { 727 hasSA = true 728 } 729 userAccountItem := &models.UserServiceAccountItem{ 730 UserName: user, 731 NumSAs: numSAs, 732 } 733 userServiceAccountList = append(userServiceAccountList, userAccountItem) 734 } 735 736 userAccountList := &models.UserServiceAccountSummary{ 737 UserServiceAccountList: userServiceAccountList, 738 HasSA: hasSA, 739 } 740 741 return userAccountList, nil 742 }