| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | // Copyright (c) 2015-2023 MinIO, Inc.
 | 
					
						
							| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2021-03-24 08:39:20 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2023-01-24 10:47:18 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2025-08-29 10:39:48 +08:00
										 |  |  | 	"maps" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2021-02-10 01:53:07 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2024-05-29 01:14:16 +08:00
										 |  |  | 	"unicode/utf8" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	"github.com/klauspost/compress/zip" | 
					
						
							| 
									
										
										
										
											2023-06-20 08:53:08 +08:00
										 |  |  | 	"github.com/minio/madmin-go/v3" | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/config/dns" | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2023-01-23 19:12:47 +08:00
										 |  |  | 	"github.com/minio/mux" | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 	xldap "github.com/minio/pkg/v3/ldap" | 
					
						
							|  |  |  | 	"github.com/minio/pkg/v3/policy" | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 	"github.com/puzpuzpuz/xsync/v3" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // RemoveUser - DELETE /minio/admin/v3/remove-user?accessKey=<access_key>
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, policy.DeleteUserAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	accessKey := vars["accessKey"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 05:49:59 +08:00
										 |  |  | 	ok, _, err := globalIAMSys.IsTempUser(accessKey) | 
					
						
							| 
									
										
										
										
											2019-12-20 06:21:21 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-22 10:24:04 +08:00
										 |  |  | 	// This API only supports removal of internal users not service accounts.
 | 
					
						
							|  |  |  | 	ok, _, err = globalIAMSys.IsServiceAccount(accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 	// When the user is root credential you are not allowed to
 | 
					
						
							|  |  |  | 	// remove the root user. Also you cannot delete yourself.
 | 
					
						
							|  |  |  | 	if accessKey == globalActiveCred.AccessKey || accessKey == cred.AccessKey { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:16:50 +08:00
										 |  |  | 	if err := globalIAMSys.DeleteUser(ctx, accessKey, true); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 		Type: madmin.SRIAMItemIAMUser, | 
					
						
							|  |  |  | 		IAMUser: &madmin.SRIAMUser{ | 
					
						
							|  |  |  | 			AccessKey:   accessKey, | 
					
						
							|  |  |  | 			IsDeleteReq: true, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: UTCNow(), | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 02:45:13 +08:00
										 |  |  | // ListBucketUsers - GET /minio/admin/v3/list-users?bucket={bucket}
 | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | func (a adminAPIHandlers) ListBucketUsers(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, policy.ListUsersAdminAction) | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := mux.Vars(r)["bucket"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 00:00:19 +08:00
										 |  |  | 	allCredentials, err := globalIAMSys.ListBucketUsers(ctx, bucket) | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(allCredentials) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	econfigData, err := madmin.EncryptData(password, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // ListUsers - GET /minio/admin/v3/list-users
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) ListUsers(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, policy.ListUsersAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 05:06:00 +08:00
										 |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 00:00:19 +08:00
										 |  |  | 	allCredentials, err := globalIAMSys.ListUsers(ctx) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-16 12:26:02 +08:00
										 |  |  | 	// Add ldap users which have mapped policies if in LDAP mode
 | 
					
						
							|  |  |  | 	// FIXME(vadmeste): move this to policy info in the future
 | 
					
						
							| 
									
										
										
										
											2022-10-05 01:41:47 +08:00
										 |  |  | 	ldapUsers, err := globalIAMSys.ListLDAPUsers(ctx) | 
					
						
							| 
									
										
										
										
											2022-04-16 12:26:02 +08:00
										 |  |  | 	if err != nil && err != errIAMActionNotAllowed { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-08-29 10:39:48 +08:00
										 |  |  | 	maps.Copy(allCredentials, ldapUsers) | 
					
						
							| 
									
										
										
										
											2022-04-16 12:26:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Marshal the response
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	data, err := json.Marshal(allCredentials) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	econfigData, err := madmin.EncryptData(password, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // GetUserInfo - GET /minio/admin/v3/user-info
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) GetUserInfo(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	name := vars["accessKey"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-30 08:56:02 +08:00
										 |  |  | 	checkDenyOnly := name == cred.AccessKey | 
					
						
							| 
									
										
										
										
											2021-12-11 07:03:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-12-11 07:03:39 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.GetUserAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2021-12-11 07:03:39 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-12-11 07:03:39 +08:00
										 |  |  | 		DenyOnly:        checkDenyOnly, | 
					
						
							|  |  |  | 	}) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-16 06:14:22 +08:00
										 |  |  | 	userInfo, err := globalIAMSys.GetUserInfo(ctx, name) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(userInfo) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, data) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // UpdateGroupMembers - PUT /minio/admin/v3/update-group-members
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) UpdateGroupMembers(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.AddUserToGroupAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	data, err := io.ReadAll(r.Body) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var updReq madmin.GroupAddRemove | 
					
						
							|  |  |  | 	err = json.Unmarshal(data, &updReq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Reject if the group add and remove are temporary credentials, or root credential.
 | 
					
						
							|  |  |  | 	for _, member := range updReq.Members { | 
					
						
							|  |  |  | 		ok, _, err := globalIAMSys.IsTempUser(member) | 
					
						
							|  |  |  | 		if err != nil && err != errNoSuchUser { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if ok { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// When the user is root credential you are not allowed to
 | 
					
						
							|  |  |  | 		// add policies for root user.
 | 
					
						
							|  |  |  | 		if member == globalActiveCred.AccessKey { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	var updatedAt time.Time | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if updReq.IsRemove { | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		updatedAt, err = globalIAMSys.RemoveUsersFromGroup(ctx, updReq.Group, updReq.Members) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-05-03 00:27:35 +08:00
										 |  |  | 		// Check if group already exists
 | 
					
						
							|  |  |  | 		if _, gerr := globalIAMSys.GetGroupDescription(updReq.Group); gerr != nil { | 
					
						
							|  |  |  | 			// If group does not exist, then check if the group has beginning and end space characters
 | 
					
						
							|  |  |  | 			// we will reject such group names.
 | 
					
						
							|  |  |  | 			if errors.Is(gerr, errNoSuchGroup) && hasSpaceBE(updReq.Group) { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 			// We don't allow internal group manipulation in this API when LDAP
 | 
					
						
							|  |  |  | 			// is enabled for now.
 | 
					
						
							|  |  |  | 			err = errIAMActionNotAllowed | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			updatedAt, err = globalIAMSys.AddUsersToGroup(ctx, updReq.Group, updReq.Members) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 		Type: madmin.SRIAMItemGroupInfo, | 
					
						
							|  |  |  | 		GroupInfo: &madmin.SRGroupInfo{ | 
					
						
							|  |  |  | 			UpdateReq: updReq, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // GetGroup - /minio/admin/v3/group?group=mygroup1
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) GetGroup(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.GetGroupAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	group := vars["group"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdesc, err := globalIAMSys.GetGroupDescription(group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	body, err := json.Marshal(gdesc) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, body) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // ListGroups - GET /minio/admin/v3/groups
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) ListGroups(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.ListGroupsAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-16 06:14:22 +08:00
										 |  |  | 	groups, err := globalIAMSys.ListGroups(ctx) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	body, err := json.Marshal(groups) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, body) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // SetGroupStatus - PUT /minio/admin/v3/set-group-status?group=mygroup1&status=enabled
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) SetGroupStatus(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.EnableGroupAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	group := vars["group"] | 
					
						
							|  |  |  | 	status := vars["status"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		err       error | 
					
						
							|  |  |  | 		updatedAt time.Time | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-11-17 01:28:29 +08:00
										 |  |  | 	switch status { | 
					
						
							|  |  |  | 	case statusEnabled: | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		updatedAt, err = globalIAMSys.SetGroupStatus(ctx, group, true) | 
					
						
							| 
									
										
										
										
											2021-11-17 01:28:29 +08:00
										 |  |  | 	case statusDisabled: | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		updatedAt, err = globalIAMSys.SetGroupStatus(ctx, group, false) | 
					
						
							| 
									
										
										
										
											2021-11-17 01:28:29 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		err = errInvalidArgument | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-20 12:02:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-01-20 12:02:24 +08:00
										 |  |  | 		Type: madmin.SRIAMItemGroupInfo, | 
					
						
							|  |  |  | 		GroupInfo: &madmin.SRGroupInfo{ | 
					
						
							|  |  |  | 			UpdateReq: madmin.GroupAddRemove{ | 
					
						
							|  |  |  | 				Group:    group, | 
					
						
							|  |  |  | 				Status:   madmin.GroupStatus(status), | 
					
						
							|  |  |  | 				IsRemove: false, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // SetUserStatus - PUT /minio/admin/v3/set-user-status?accessKey=<access_key>&status=[enabled|disabled]
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, creds := validateAdminReq(ctx, w, r, policy.EnableUserAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	accessKey := vars["accessKey"] | 
					
						
							|  |  |  | 	status := vars["status"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 	// you cannot enable or disable yourself.
 | 
					
						
							|  |  |  | 	if accessKey == creds.AccessKey { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errInvalidArgument), r.URL) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	updatedAt, err := globalIAMSys.SetUserStatus(ctx, accessKey, madmin.AccountStatus(status)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-20 12:02:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-01-20 12:02:24 +08:00
										 |  |  | 		Type: madmin.SRIAMItemIAMUser, | 
					
						
							|  |  |  | 		IAMUser: &madmin.SRIAMUser{ | 
					
						
							|  |  |  | 			AccessKey:   accessKey, | 
					
						
							|  |  |  | 			IsDeleteReq: false, | 
					
						
							|  |  |  | 			UserReq: &madmin.AddOrUpdateUserReq{ | 
					
						
							|  |  |  | 				Status: madmin.AccountStatus(status), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // AddUser - PUT /minio/admin/v3/add-user?accessKey=<access_key>
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	vars := mux.Vars(r) | 
					
						
							| 
									
										
										
										
											2021-04-16 07:32:13 +08:00
										 |  |  | 	accessKey := vars["accessKey"] | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-20 05:24:21 +08:00
										 |  |  | 	// Not allowed to add a user with same access key as root credential
 | 
					
						
							| 
									
										
										
										
											2023-03-14 03:46:17 +08:00
										 |  |  | 	if accessKey == globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2020-12-20 05:24:21 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL) | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	user, exists := globalIAMSys.GetUser(ctx, accessKey) | 
					
						
							|  |  |  | 	if exists && (user.Credentials.IsTemp() || user.Credentials.IsServiceAccount()) { | 
					
						
							| 
									
										
										
										
											2021-12-10 09:48:51 +08:00
										 |  |  | 		// Updating STS credential is not allowed, and this API does not
 | 
					
						
							|  |  |  | 		// support updating service accounts.
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-20 05:24:21 +08:00
										 |  |  | 	if (cred.IsTemp() || cred.IsServiceAccount()) && cred.ParentUser == accessKey { | 
					
						
							|  |  |  | 		// Incoming access key matches parent user then we should
 | 
					
						
							|  |  |  | 		// reject password change requests.
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-03 00:27:35 +08:00
										 |  |  | 	// Check if accessKey has beginning and end space characters, this only applies to new users.
 | 
					
						
							|  |  |  | 	if !exists && hasSpaceBE(accessKey) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-29 01:14:16 +08:00
										 |  |  | 	if !utf8.ValidString(accessKey) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserValidUTF), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-30 08:56:02 +08:00
										 |  |  | 	checkDenyOnly := accessKey == cred.AccessKey | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-12-10 09:48:51 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2021-03-24 06:15:51 +08:00
										 |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.CreateUserAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2021-03-03 09:02:29 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-12-10 09:48:51 +08:00
										 |  |  | 		DenyOnly:        checkDenyOnly, | 
					
						
							| 
									
										
										
										
											2021-03-03 07:35:50 +08:00
										 |  |  | 	}) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-19 18:03:18 +08:00
										 |  |  | 	password := cred.SecretKey | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	var ureq madmin.AddOrUpdateUserReq | 
					
						
							|  |  |  | 	if err = json.Unmarshal(configBytes, &ureq); err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 	// We don't allow internal user creation with LDAP enabled for now.
 | 
					
						
							|  |  |  | 	if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	updatedAt, err := globalIAMSys.CreateUser(ctx, accessKey, ureq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 		Type: madmin.SRIAMItemIAMUser, | 
					
						
							|  |  |  | 		IAMUser: &madmin.SRIAMUser{ | 
					
						
							|  |  |  | 			AccessKey:   accessKey, | 
					
						
							|  |  |  | 			IsDeleteReq: false, | 
					
						
							|  |  |  | 			UserReq:     &ureq, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | // TemporaryAccountInfo - GET /minio/admin/v3/temporary-account-info
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) TemporaryAccountInfo(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey := mux.Vars(r)["accessKey"] | 
					
						
							|  |  |  | 	if accessKey == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 	args := policy.Args{ | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.ListTemporaryAccountsAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !globalIAMSys.IsAllowed(args) { | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	stsAccount, sessionPolicy, err := globalIAMSys.GetTemporaryAccount(ctx, accessKey) | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	var stsAccountPolicy policy.Policy | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	if sessionPolicy != nil { | 
					
						
							|  |  |  | 		stsAccountPolicy = *sessionPolicy | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 		policiesNames, err := globalIAMSys.PolicyDBGet(stsAccount.ParentUser, stsAccount.Groups...) | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 		if len(policiesNames) == 0 { | 
					
						
							|  |  |  | 			policySet, _ := args.GetPolicies(iamPolicyClaimNameOpenID()) | 
					
						
							|  |  |  | 			policiesNames = policySet.ToSlice() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		stsAccountPolicy = globalIAMSys.GetCombinedPolicy(policiesNames...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policyJSON, err := json.MarshalIndent(stsAccountPolicy, "", " ") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	infoResp := madmin.TemporaryAccountInfoResp{ | 
					
						
							|  |  |  | 		ParentUser:    stsAccount.ParentUser, | 
					
						
							|  |  |  | 		AccountStatus: stsAccount.Status, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		ImpliedPolicy: sessionPolicy == nil, | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 		Policy:        string(policyJSON), | 
					
						
							| 
									
										
										
										
											2023-03-23 07:47:02 +08:00
										 |  |  | 		Expiration:    &stsAccount.Expiration, | 
					
						
							| 
									
										
										
										
											2022-12-14 00:38:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(infoResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 02:28:56 +08:00
										 |  |  | // AddServiceAccount - PUT /minio/admin/v3/add-service-account
 | 
					
						
							| 
									
										
										
										
											2020-03-18 01:36:13 +08:00
										 |  |  | func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | 	ctx, cred, opts, createReq, targetUser, APIError := commonAddServiceAccount(r, false) | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	if APIError.Code != "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, APIError, r.URL) | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-15 02:37:12 +08:00
										 |  |  | 	if createReq.AccessKey == globalActiveCred.AccessKey { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		targetGroups []string | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		err          error | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 	// Find the user for the request sender (as it may be sent via a service
 | 
					
						
							|  |  |  | 	// account or STS account):
 | 
					
						
							|  |  |  | 	requestorUser := cred.AccessKey | 
					
						
							|  |  |  | 	requestorParentUser := cred.AccessKey | 
					
						
							|  |  |  | 	requestorGroups := cred.Groups | 
					
						
							|  |  |  | 	requestorIsDerivedCredential := false | 
					
						
							|  |  |  | 	if cred.IsServiceAccount() || cred.IsTemp() { | 
					
						
							|  |  |  | 		requestorParentUser = cred.ParentUser | 
					
						
							|  |  |  | 		requestorIsDerivedCredential = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-24 10:47:18 +08:00
										 |  |  | 	if globalIAMSys.GetUsersSysType() == MinIOUsersSysType && targetUser != cred.AccessKey { | 
					
						
							|  |  |  | 		// For internal IDP, ensure that the targetUser's parent account exists.
 | 
					
						
							|  |  |  | 		// It could be a regular user account or the root account.
 | 
					
						
							|  |  |  | 		_, isRegularUser := globalIAMSys.GetUser(ctx, targetUser) | 
					
						
							|  |  |  | 		if !isRegularUser && targetUser != globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2023-02-20 18:11:47 +08:00
										 |  |  | 			apiErr := toAdminAPIErr(ctx, errNoSuchUser) | 
					
						
							|  |  |  | 			apiErr.Description = fmt.Sprintf("Specified target user %s does not exist", targetUser) | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, apiErr, r.URL) | 
					
						
							| 
									
										
										
										
											2023-01-24 10:47:18 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 	// Check if we are creating svc account for request sender.
 | 
					
						
							| 
									
										
										
										
											2025-03-30 08:56:02 +08:00
										 |  |  | 	isSvcAccForRequestor := targetUser == requestorUser || targetUser == requestorParentUser | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 	// If we are creating svc account for request sender, ensure
 | 
					
						
							|  |  |  | 	// that targetUser is a real user (i.e. not derived
 | 
					
						
							|  |  |  | 	// credentials).
 | 
					
						
							|  |  |  | 	if isSvcAccForRequestor { | 
					
						
							|  |  |  | 		if requestorIsDerivedCredential { | 
					
						
							|  |  |  | 			if requestorParentUser == "" { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, | 
					
						
							|  |  |  | 					errors.New("service accounts cannot be generated for temporary credentials without parent")), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			targetUser = requestorParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		targetGroups = requestorGroups | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-06 02:49:33 +08:00
										 |  |  | 		// In case of LDAP/OIDC we need to set `opts.claims` to ensure
 | 
					
						
							|  |  |  | 		// it is associated with the LDAP/OIDC user properly.
 | 
					
						
							|  |  |  | 		for k, v := range cred.Claims { | 
					
						
							|  |  |  | 			if k == expClaim { | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-10-06 02:49:33 +08:00
										 |  |  | 			opts.claims[k] = v | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	} else if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 		// In case of LDAP we need to resolve the targetUser to a DN and
 | 
					
						
							|  |  |  | 		// query their groups:
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		opts.claims[ldapUserN] = targetUser // simple username
 | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		var lookupResult *xldap.DNSearchResult | 
					
						
							|  |  |  | 		lookupResult, targetGroups, err = globalIAMSys.LDAPConfig.LookupUserDN(targetUser) | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2021-05-13 12:25:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		targetUser = lookupResult.NormDN | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		opts.claims[ldapUser] = targetUser // username DN
 | 
					
						
							| 
									
										
										
										
											2024-05-25 21:43:06 +08:00
										 |  |  | 		opts.claims[ldapActualUser] = lookupResult.ActualDN | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		// Add LDAP attributes that were looked up into the claims.
 | 
					
						
							|  |  |  | 		for attribKey, attribValue := range lookupResult.Attributes { | 
					
						
							|  |  |  | 			opts.claims[ldapAttribPrefix+attribKey] = attribValue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 05:28:19 +08:00
										 |  |  | 		// NOTE: if not using LDAP, then internal IDP or open ID is
 | 
					
						
							|  |  |  | 		// being used - in the former, group info is enforced when
 | 
					
						
							|  |  |  | 		// generated credentials are used to make requests, and in the
 | 
					
						
							|  |  |  | 		// latter, a group notion is not supported.
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	newCred, updatedAt, err := globalIAMSys.NewServiceAccount(ctx, targetUser, targetGroups, opts) | 
					
						
							| 
									
										
										
										
											2020-03-18 01:36:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-21 10:09:11 +08:00
										 |  |  | 	createResp := madmin.AddServiceAccountResp{ | 
					
						
							|  |  |  | 		Credentials: madmin.Credentials{ | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 			AccessKey:  newCred.AccessKey, | 
					
						
							|  |  |  | 			SecretKey:  newCred.SecretKey, | 
					
						
							|  |  |  | 			Expiration: newCred.Expiration, | 
					
						
							| 
									
										
										
										
											2022-05-21 10:09:11 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(createResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							| 
									
										
										
										
											2022-05-21 10:09:11 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-07 07:52:43 +08:00
										 |  |  | 	// Call hook for cluster-replication if the service account is not for a
 | 
					
						
							|  |  |  | 	// root user.
 | 
					
						
							|  |  |  | 	if newCred.ParentUser != globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 			Type: madmin.SRIAMItemSvcAcc, | 
					
						
							|  |  |  | 			SvcAccChange: &madmin.SRSvcAccChange{ | 
					
						
							|  |  |  | 				Create: &madmin.SRSvcAccCreate{ | 
					
						
							|  |  |  | 					Parent:        newCred.ParentUser, | 
					
						
							|  |  |  | 					AccessKey:     newCred.AccessKey, | 
					
						
							|  |  |  | 					SecretKey:     newCred.SecretKey, | 
					
						
							|  |  |  | 					Groups:        newCred.Groups, | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 					Name:          newCred.Name, | 
					
						
							|  |  |  | 					Description:   newCred.Description, | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 					Claims:        opts.claims, | 
					
						
							| 
									
										
										
										
											2025-02-25 09:43:59 +08:00
										 |  |  | 					SessionPolicy: madmin.SRSessionPolicy(createReq.Policy), | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 					Status:        auth.AccountOn, | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 					Expiration:    createReq.Expiration, | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | // UpdateServiceAccount - POST /minio/admin/v3/update-service-account
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) UpdateServiceAccount(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey := mux.Vars(r)["accessKey"] | 
					
						
							|  |  |  | 	if accessKey == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	svcAccount, _, err := globalIAMSys.GetServiceAccount(ctx, accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var updateReq madmin.UpdateServiceAccountReq | 
					
						
							|  |  |  | 	if err = json.Unmarshal(reqBytes, &updateReq); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := updateReq.Validate(); err != nil { | 
					
						
							|  |  |  | 		// Since this validation would happen client side as well, we only send
 | 
					
						
							|  |  |  | 		// a generic error message here.
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	condValues := getConditionValues(r, "", cred) | 
					
						
							| 
									
										
										
										
											2024-05-29 01:19:04 +08:00
										 |  |  | 	err = addExpirationToCondValues(updateReq.NewExpiration, condValues) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-01 02:56:45 +08:00
										 |  |  | 	// Permission checks:
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 1. Any type of account (i.e. access keys (previously/still called service
 | 
					
						
							|  |  |  | 	// accounts), STS accounts, internal IDP accounts, etc) with the
 | 
					
						
							|  |  |  | 	// policy.UpdateServiceAccountAdminAction permission can update any service
 | 
					
						
							|  |  |  | 	// account.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 2. We would like to let a user update their own access keys, however it
 | 
					
						
							|  |  |  | 	// is currently blocked pending a re-design. Users are still able to delete
 | 
					
						
							|  |  |  | 	// and re-create them.
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.UpdateServiceAccountAdminAction, | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 		ConditionValues: condValues, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	}) { | 
					
						
							| 
									
										
										
										
											2024-02-01 02:56:45 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	var sp *policy.Policy | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	if len(updateReq.NewPolicy) > 0 { | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		sp, err = policy.ParseConfig(bytes.NewReader(updateReq.NewPolicy)) | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-11-01 03:30:36 +08:00
										 |  |  | 		if sp.Version == "" && len(sp.Statements) == 0 { | 
					
						
							|  |  |  | 			sp = nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	opts := updateServiceAccountOpts{ | 
					
						
							|  |  |  | 		secretKey:     updateReq.NewSecretKey, | 
					
						
							|  |  |  | 		status:        updateReq.NewStatus, | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 		name:          updateReq.NewName, | 
					
						
							|  |  |  | 		description:   updateReq.NewDescription, | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 		expiration:    updateReq.NewExpiration, | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 		sessionPolicy: sp, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	updatedAt, err := globalIAMSys.UpdateServiceAccount(ctx, accessKey, opts) | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 09:41:43 +08:00
										 |  |  | 	// Call site replication hook - non-root user accounts are replicated.
 | 
					
						
							|  |  |  | 	if svcAccount.ParentUser != globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 			Type: madmin.SRIAMItemSvcAcc, | 
					
						
							|  |  |  | 			SvcAccChange: &madmin.SRSvcAccChange{ | 
					
						
							|  |  |  | 				Update: &madmin.SRSvcAccUpdate{ | 
					
						
							|  |  |  | 					AccessKey:     accessKey, | 
					
						
							|  |  |  | 					SecretKey:     opts.secretKey, | 
					
						
							|  |  |  | 					Status:        opts.status, | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 					Name:          opts.name, | 
					
						
							|  |  |  | 					Description:   opts.description, | 
					
						
							| 
									
										
										
										
											2025-02-25 09:43:59 +08:00
										 |  |  | 					SessionPolicy: madmin.SRSessionPolicy(updateReq.NewPolicy), | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 					Expiration:    updateReq.NewExpiration, | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-08 09:41:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	writeSuccessNoContent(w) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // InfoServiceAccount - GET /minio/admin/v3/info-service-account
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) InfoServiceAccount(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey := mux.Vars(r)["accessKey"] | 
					
						
							|  |  |  | 	if accessKey == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	svcAccount, sessionPolicy, err := globalIAMSys.GetServiceAccount(ctx, accessKey) | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	}) { | 
					
						
							|  |  |  | 		requestUser := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			requestUser = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if requestUser != svcAccount.ParentUser { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 03:30:36 +08:00
										 |  |  | 	// if session policy is nil or empty, then it is implied policy
 | 
					
						
							|  |  |  | 	impliedPolicy := sessionPolicy == nil || (sessionPolicy.Version == "" && len(sessionPolicy.Statements) == 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	var svcAccountPolicy policy.Policy | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 03:30:36 +08:00
										 |  |  | 	if !impliedPolicy { | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		svcAccountPolicy = *sessionPolicy | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 		policiesNames, err := globalIAMSys.PolicyDBGet(svcAccount.ParentUser, svcAccount.Groups...) | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-11 06:26:26 +08:00
										 |  |  | 		svcAccountPolicy = globalIAMSys.GetCombinedPolicy(policiesNames...) | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-30 00:22:22 +08:00
										 |  |  | 	policyJSON, err := json.MarshalIndent(svcAccountPolicy, "", " ") | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 	var expiration *time.Time | 
					
						
							|  |  |  | 	if !svcAccount.Expiration.IsZero() && !svcAccount.Expiration.Equal(timeSentinel) { | 
					
						
							|  |  |  | 		expiration = &svcAccount.Expiration | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	infoResp := madmin.InfoServiceAccountResp{ | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		ParentUser:    svcAccount.ParentUser, | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 		Name:          svcAccount.Name, | 
					
						
							|  |  |  | 		Description:   svcAccount.Description, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		AccountStatus: svcAccount.Status, | 
					
						
							| 
									
										
										
										
											2023-11-01 03:30:36 +08:00
										 |  |  | 		ImpliedPolicy: impliedPolicy, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		Policy:        string(policyJSON), | 
					
						
							| 
									
										
										
										
											2023-02-28 02:10:22 +08:00
										 |  |  | 		Expiration:    expiration, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(infoResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | // ListServiceAccounts - GET /minio/admin/v3/list-service-accounts
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListServiceAccounts(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	// Get current object layer instance.
 | 
					
						
							| 
									
										
										
										
											2020-10-10 00:59:52 +08:00
										 |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							| 
									
										
										
										
											2020-10-20 00:54:40 +08:00
										 |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	var targetAccount string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 	// If listing is requested for a specific user (who is not the request
 | 
					
						
							|  |  |  | 	// sender), check that the user has permissions.
 | 
					
						
							| 
									
										
										
										
											2021-08-08 13:43:01 +08:00
										 |  |  | 	user := r.Form.Get("user") | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 	if user != "" && user != cred.AccessKey { | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 			Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 			IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		}) { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		targetAccount = user | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		targetAccount = cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			targetAccount = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-01 23:05:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	serviceAccounts, err := globalIAMSys.ListServiceAccounts(ctx, targetAccount) | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-03 07:17:26 +08:00
										 |  |  | 	var serviceAccountList []madmin.ServiceAccountInfo | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, svc := range serviceAccounts { | 
					
						
							| 
									
										
										
										
											2023-06-03 07:17:26 +08:00
										 |  |  | 		expiryTime := svc.Expiration | 
					
						
							|  |  |  | 		serviceAccountList = append(serviceAccountList, madmin.ServiceAccountInfo{ | 
					
						
							| 
									
										
										
										
											2024-05-01 20:41:13 +08:00
										 |  |  | 			Description:   svc.Description, | 
					
						
							|  |  |  | 			ParentUser:    svc.ParentUser, | 
					
						
							|  |  |  | 			Name:          svc.Name, | 
					
						
							|  |  |  | 			AccountStatus: svc.Status, | 
					
						
							|  |  |  | 			AccessKey:     svc.AccessKey, | 
					
						
							|  |  |  | 			ImpliedPolicy: svc.IsImpliedPolicy(), | 
					
						
							|  |  |  | 			Expiration:    &expiryTime, | 
					
						
							| 
									
										
										
										
											2023-06-03 07:17:26 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	listResp := madmin.ListServiceAccountsResp{ | 
					
						
							| 
									
										
										
										
											2023-06-03 07:17:26 +08:00
										 |  |  | 		Accounts: serviceAccountList, | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(listResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteServiceAccount - DELETE /minio/admin/v3/delete-service-account
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	// Get current object layer instance.
 | 
					
						
							| 
									
										
										
										
											2020-10-10 00:59:52 +08:00
										 |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							| 
									
										
										
										
											2020-10-20 00:54:40 +08:00
										 |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	serviceAccount := mux.Vars(r)["accessKey"] | 
					
						
							|  |  |  | 	if serviceAccount == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-21 18:09:33 +08:00
										 |  |  | 	if serviceAccount == siteReplicatorSvcAcc && globalSiteReplicationSys.isEnabled() { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-03 08:56:19 +08:00
										 |  |  | 	// We do not care if service account is readable or not at this point,
 | 
					
						
							|  |  |  | 	// since this is a delete call we shall allow it to be deleted if possible.
 | 
					
						
							| 
									
										
										
										
											2023-10-09 03:13:18 +08:00
										 |  |  | 	svcAccount, _, err := globalIAMSys.GetServiceAccount(ctx, serviceAccount) | 
					
						
							|  |  |  | 	if errors.Is(err, errNoSuchServiceAccount) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminServiceAccountNotFound), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	adminPrivilege := globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		Action:          policy.RemoveServiceAccountAdminAction, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2020-05-01 23:05:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 	if !adminPrivilege { | 
					
						
							|  |  |  | 		parentUser := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			parentUser = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-03 08:56:19 +08:00
										 |  |  | 		if svcAccount.ParentUser != "" && parentUser != svcAccount.ParentUser { | 
					
						
							| 
									
										
										
										
											2021-04-15 13:51:14 +08:00
										 |  |  | 			// The service account belongs to another user but return not
 | 
					
						
							|  |  |  | 			// found error to mitigate brute force attacks. or the
 | 
					
						
							|  |  |  | 			// serviceAccount doesn't exist.
 | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminServiceAccountNotFound), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-03 08:56:19 +08:00
										 |  |  | 	if err := globalIAMSys.DeleteServiceAccount(ctx, serviceAccount, true); err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-15 12:28:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 09:41:43 +08:00
										 |  |  | 	// Call site replication hook - non-root user accounts are replicated.
 | 
					
						
							| 
									
										
										
										
											2022-05-03 08:56:19 +08:00
										 |  |  | 	if svcAccount.ParentUser != "" && svcAccount.ParentUser != globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 			Type: madmin.SRIAMItemSvcAcc, | 
					
						
							|  |  |  | 			SvcAccChange: &madmin.SRSvcAccChange{ | 
					
						
							|  |  |  | 				Delete: &madmin.SRSvcAccDelete{ | 
					
						
							|  |  |  | 					AccessKey: serviceAccount, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			UpdatedAt: UTCNow(), | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 03:10:09 +08:00
										 |  |  | 	writeSuccessNoContent(w) | 
					
						
							| 
									
										
										
										
											2020-03-18 01:36:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | // ListAccessKeysBulk - GET /minio/admin/v3/list-access-keys-bulk
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListAccessKeysBulk(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := r.Context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							|  |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	users := r.Form["users"] | 
					
						
							|  |  |  | 	isAll := r.Form.Get("all") == "true" | 
					
						
							|  |  |  | 	selfOnly := !isAll && len(users) == 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if isAll && len(users) > 0 { | 
					
						
							|  |  |  | 		// This should be checked on client side, so return generic error
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Empty user list and not self, list access keys for all users
 | 
					
						
							|  |  |  | 	if isAll { | 
					
						
							|  |  |  | 		if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 			Groups:          cred.Groups, | 
					
						
							|  |  |  | 			Action:          policy.ListUsersAdminAction, | 
					
						
							|  |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			Claims:          cred.Claims, | 
					
						
							|  |  |  | 		}) { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if len(users) == 1 { | 
					
						
							|  |  |  | 		if users[0] == cred.AccessKey || users[0] == cred.ParentUser { | 
					
						
							|  |  |  | 			selfOnly = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							|  |  |  | 		Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							|  |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 		IsOwner:         owner, | 
					
						
							|  |  |  | 		Claims:          cred.Claims, | 
					
						
							|  |  |  | 		DenyOnly:        selfOnly, | 
					
						
							|  |  |  | 	}) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if selfOnly && len(users) == 0 { | 
					
						
							|  |  |  | 		selfUser := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			selfUser = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		users = append(users, selfUser) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var checkedUserList []string | 
					
						
							|  |  |  | 	if isAll { | 
					
						
							|  |  |  | 		users, err := globalIAMSys.ListUsers(ctx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for user := range users { | 
					
						
							|  |  |  | 			checkedUserList = append(checkedUserList, user) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-10-04 07:11:02 +08:00
										 |  |  | 		checkedUserList = append(checkedUserList, globalActiveCred.AccessKey) | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		for _, user := range users { | 
					
						
							|  |  |  | 			// Validate the user
 | 
					
						
							|  |  |  | 			_, ok := globalIAMSys.GetUser(ctx, user) | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			checkedUserList = append(checkedUserList, user) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	listType := r.Form.Get("listType") | 
					
						
							|  |  |  | 	var listSTSKeys, listServiceAccounts bool | 
					
						
							|  |  |  | 	switch listType { | 
					
						
							|  |  |  | 	case madmin.AccessKeyListUsersOnly: | 
					
						
							|  |  |  | 		listSTSKeys = false | 
					
						
							|  |  |  | 		listServiceAccounts = false | 
					
						
							|  |  |  | 	case madmin.AccessKeyListSTSOnly: | 
					
						
							|  |  |  | 		listSTSKeys = true | 
					
						
							|  |  |  | 		listServiceAccounts = false | 
					
						
							|  |  |  | 	case madmin.AccessKeyListSvcaccOnly: | 
					
						
							|  |  |  | 		listSTSKeys = false | 
					
						
							|  |  |  | 		listServiceAccounts = true | 
					
						
							|  |  |  | 	case madmin.AccessKeyListAll: | 
					
						
							|  |  |  | 		listSTSKeys = true | 
					
						
							|  |  |  | 		listServiceAccounts = true | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		err := errors.New("invalid list type") | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrInvalidRequest, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKeyMap := make(map[string]madmin.ListAccessKeysResp) | 
					
						
							|  |  |  | 	for _, user := range checkedUserList { | 
					
						
							|  |  |  | 		accessKeys := madmin.ListAccessKeysResp{} | 
					
						
							|  |  |  | 		if listSTSKeys { | 
					
						
							|  |  |  | 			stsKeys, err := globalIAMSys.ListSTSAccounts(ctx, user) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, sts := range stsKeys { | 
					
						
							|  |  |  | 				accessKeys.STSKeys = append(accessKeys.STSKeys, madmin.ServiceAccountInfo{ | 
					
						
							|  |  |  | 					AccessKey:  sts.AccessKey, | 
					
						
							|  |  |  | 					Expiration: &sts.Expiration, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// if only STS keys, skip if user has no STS keys
 | 
					
						
							|  |  |  | 			if !listServiceAccounts && len(stsKeys) == 0 { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if listServiceAccounts { | 
					
						
							|  |  |  | 			serviceAccounts, err := globalIAMSys.ListServiceAccounts(ctx, user) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, svc := range serviceAccounts { | 
					
						
							|  |  |  | 				accessKeys.ServiceAccounts = append(accessKeys.ServiceAccounts, madmin.ServiceAccountInfo{ | 
					
						
							|  |  |  | 					AccessKey:  svc.AccessKey, | 
					
						
							|  |  |  | 					Expiration: &svc.Expiration, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// if only service accounts, skip if user has no service accounts
 | 
					
						
							|  |  |  | 			if !listSTSKeys && len(serviceAccounts) == 0 { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		accessKeyMap[user] = accessKeys | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(accessKeyMap) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | // AccountInfoHandler returns usage, permissions and other bucket metadata for incoming us
 | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							| 
									
										
										
										
											2020-10-10 00:59:52 +08:00
										 |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							| 
									
										
										
										
											2020-10-20 00:54:40 +08:00
										 |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set prefix value for "s3:prefix" policy conditionals.
 | 
					
						
							|  |  |  | 	r.Header.Set("prefix", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set delimiter value for "s3:delimiter" policy conditionals.
 | 
					
						
							|  |  |  | 	r.Header.Set("delimiter", SlashSeparator) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 23:51:10 +08:00
										 |  |  | 	// Check if we are asked to return prefix usage
 | 
					
						
							| 
									
										
										
										
											2021-08-08 13:43:01 +08:00
										 |  |  | 	enablePrefixUsage := r.Form.Get("prefix-usage") == "true" | 
					
						
							| 
									
										
										
										
											2021-07-14 23:51:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 	isAllowedAccess := func(bucketName string) (rd, wr bool) { | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		if globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-07-12 08:39:52 +08:00
										 |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2021-03-24 06:15:51 +08:00
										 |  |  | 			Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 			Action:          policy.ListBucketAction, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 			BucketName:      bucketName, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			ObjectName:      "", | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 		}) { | 
					
						
							|  |  |  | 			rd = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		if globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2022-05-13 01:46:20 +08:00
										 |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 			Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 			Action:          policy.GetBucketLocationAction, | 
					
						
							| 
									
										
										
										
											2022-05-13 01:46:20 +08:00
										 |  |  | 			BucketName:      bucketName, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2022-05-13 01:46:20 +08:00
										 |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			ObjectName:      "", | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2022-05-13 01:46:20 +08:00
										 |  |  | 		}) { | 
					
						
							|  |  |  | 			rd = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		if globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							| 
									
										
										
										
											2021-07-12 08:39:52 +08:00
										 |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							| 
									
										
										
										
											2021-03-24 06:15:51 +08:00
										 |  |  | 			Groups:          cred.Groups, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 			Action:          policy.PutObjectAction, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 			BucketName:      bucketName, | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			ObjectName:      "", | 
					
						
							| 
									
										
										
										
											2023-02-07 01:27:29 +08:00
										 |  |  | 			Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 		}) { | 
					
						
							|  |  |  | 			wr = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return rd, wr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 01:53:07 +08:00
										 |  |  | 	// If etcd, dns federation configured list buckets from etcd.
 | 
					
						
							| 
									
										
										
										
											2022-10-25 08:44:15 +08:00
										 |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	var buckets []BucketInfo | 
					
						
							| 
									
										
										
										
											2021-02-10 01:53:07 +08:00
										 |  |  | 	if globalDNSConfig != nil && globalBucketFederation { | 
					
						
							|  |  |  | 		dnsBuckets, err := globalDNSConfig.List() | 
					
						
							|  |  |  | 		if err != nil && !IsErrIgnored(err, | 
					
						
							|  |  |  | 			dns.ErrNoEntriesFound, | 
					
						
							|  |  |  | 			dns.ErrDomainMissing) { | 
					
						
							| 
									
										
										
										
											2021-06-16 09:52:01 +08:00
										 |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2021-02-10 01:53:07 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, dnsRecords := range dnsBuckets { | 
					
						
							|  |  |  | 			buckets = append(buckets, BucketInfo{ | 
					
						
							|  |  |  | 				Name:    dnsRecords[0].Key, | 
					
						
							|  |  |  | 				Created: dnsRecords[0].CreationDate, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		sort.Slice(buckets, func(i, j int) bool { | 
					
						
							|  |  |  | 			return buckets[i].Name < buckets[j].Name | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 		buckets, err = objectAPI.ListBuckets(ctx, BucketOptions{Cached: true}) | 
					
						
							| 
									
										
										
										
											2021-02-10 01:53:07 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 	accountName := cred.AccessKey | 
					
						
							| 
									
										
										
										
											2021-12-21 06:07:16 +08:00
										 |  |  | 	if cred.IsTemp() || cred.IsServiceAccount() { | 
					
						
							|  |  |  | 		// For derived credentials, check the parent user's permissions.
 | 
					
						
							|  |  |  | 		accountName = cred.ParentUser | 
					
						
							| 
									
										
										
										
											2021-03-24 08:39:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	roleArn := policy.Args{Claims: cred.Claims}.GetRoleArn() | 
					
						
							|  |  |  | 	policySetFromClaims, hasPolicyClaim := policy.GetPoliciesFromClaims(cred.Claims, iamPolicyClaimNameOpenID()) | 
					
						
							|  |  |  | 	var effectivePolicy policy.Policy | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 	var buf []byte | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 	switch { | 
					
						
							| 
									
										
										
										
											2024-09-27 14:44:44 +08:00
										 |  |  | 	case accountName == globalActiveCred.AccessKey || newGlobalAuthZPluginFn() != nil: | 
					
						
							|  |  |  | 		// For owner account and when plugin authZ is configured always set
 | 
					
						
							|  |  |  | 		// effective policy as `consoleAdmin`.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// In the latter case, we let the UI render everything, but individual
 | 
					
						
							|  |  |  | 		// actions would fail if not permitted by the external authZ service.
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		for _, policy := range policy.DefaultPolicies { | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 			if policy.Name == "consoleAdmin" { | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 				effectivePolicy = policy.Definition | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-11-30 07:40:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 	case roleArn != "": | 
					
						
							|  |  |  | 		_, policy, err := globalIAMSys.GetRolePolicy(roleArn) | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 		policySlice := newMappedPolicy(policy).toSlice() | 
					
						
							|  |  |  | 		effectivePolicy = globalIAMSys.GetCombinedPolicy(policySlice...) | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-30 07:40:49 +08:00
										 |  |  | 	case hasPolicyClaim: | 
					
						
							|  |  |  | 		effectivePolicy = globalIAMSys.GetCombinedPolicy(policySetFromClaims.ToSlice()...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2023-11-30 08:07:35 +08:00
										 |  |  | 		policies, err := globalIAMSys.PolicyDBGet(accountName, cred.Groups...) | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2022-07-30 11:58:03 +08:00
										 |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 		effectivePolicy = globalIAMSys.GetCombinedPolicy(policies...) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-02-19 00:25:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-20 08:54:41 +08:00
										 |  |  | 	buf, err = json.MarshalIndent(effectivePolicy, "", " ") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 09:23:57 +08:00
										 |  |  | 	acctInfo := madmin.AccountInfo{ | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 		AccountName: accountName, | 
					
						
							| 
									
										
										
										
											2021-07-17 05:37:06 +08:00
										 |  |  | 		Server:      objectAPI.BackendInfo(), | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 		Policy:      buf, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, bucket := range buckets { | 
					
						
							|  |  |  | 		rd, wr := isAllowedAccess(bucket.Name) | 
					
						
							|  |  |  | 		if rd || wr { | 
					
						
							|  |  |  | 			// Fetch the data usage of the current bucket
 | 
					
						
							| 
									
										
										
										
											2024-08-15 08:34:56 +08:00
										 |  |  | 			bui := globalBucketQuotaSys.GetBucketUsageInfo(ctx, bucket.Name) | 
					
						
							|  |  |  | 			size := bui.Size | 
					
						
							|  |  |  | 			objectsCount := bui.ObjectsCount | 
					
						
							|  |  |  | 			objectsHist := bui.ObjectSizesHistogram | 
					
						
							|  |  |  | 			versionsHist := bui.ObjectVersionsHistogram | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 23:51:10 +08:00
										 |  |  | 			// Fetch the prefix usage of the current bucket
 | 
					
						
							|  |  |  | 			var prefixUsage map[string]uint64 | 
					
						
							|  |  |  | 			if enablePrefixUsage { | 
					
						
							| 
									
										
										
										
											2022-01-12 00:43:18 +08:00
										 |  |  | 				prefixUsage, _ = loadPrefixUsageFromBackend(ctx, objectAPI, bucket.Name) | 
					
						
							| 
									
										
										
										
											2021-07-14 23:51:10 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-09-18 06:02:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			lcfg, _ := globalBucketObjectLockSys.Get(bucket.Name) | 
					
						
							| 
									
										
										
										
											2022-02-01 09:27:43 +08:00
										 |  |  | 			quota, _ := globalBucketQuotaSys.Get(ctx, bucket.Name) | 
					
						
							| 
									
										
										
										
											2022-04-24 17:36:31 +08:00
										 |  |  | 			rcfg, _, _ := globalBucketMetadataSys.GetReplicationConfig(ctx, bucket.Name) | 
					
						
							|  |  |  | 			tcfg, _, _ := globalBucketMetadataSys.GetTaggingConfig(bucket.Name) | 
					
						
							| 
									
										
										
										
											2021-09-18 06:02:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-04 00:03:42 +08:00
										 |  |  | 			acctInfo.Buckets = append(acctInfo.Buckets, madmin.BucketAccessInfo{ | 
					
						
							| 
									
										
										
										
											2023-03-11 00:53:59 +08:00
										 |  |  | 				Name:                    bucket.Name, | 
					
						
							|  |  |  | 				Created:                 bucket.Created, | 
					
						
							|  |  |  | 				Size:                    size, | 
					
						
							|  |  |  | 				Objects:                 objectsCount, | 
					
						
							|  |  |  | 				ObjectSizesHistogram:    objectsHist, | 
					
						
							|  |  |  | 				ObjectVersionsHistogram: versionsHist, | 
					
						
							|  |  |  | 				PrefixUsage:             prefixUsage, | 
					
						
							| 
									
										
										
										
											2021-09-18 06:02:21 +08:00
										 |  |  | 				Details: &madmin.BucketDetails{ | 
					
						
							|  |  |  | 					Versioning:          globalBucketVersioningSys.Enabled(bucket.Name), | 
					
						
							|  |  |  | 					VersioningSuspended: globalBucketVersioningSys.Suspended(bucket.Name), | 
					
						
							|  |  |  | 					Replication:         rcfg != nil, | 
					
						
							|  |  |  | 					Locking:             lcfg.LockEnabled, | 
					
						
							|  |  |  | 					Quota:               quota, | 
					
						
							|  |  |  | 					Tagging:             tcfg, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-05-16 09:16:45 +08:00
										 |  |  | 				Access: madmin.AccountAccess{ | 
					
						
							|  |  |  | 					Read:  rd, | 
					
						
							|  |  |  | 					Write: wr, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usageInfoJSON, err := json.Marshal(acctInfo) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, usageInfoJSON) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // InfoCannedPolicy - GET /minio/admin/v3/info-canned-policy?name={policyName}
 | 
					
						
							| 
									
										
										
										
											2021-12-12 01:03:39 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Newer API response with policy timestamps is returned with query parameter
 | 
					
						
							|  |  |  | // `v=2` like:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GET /minio/admin/v3/info-canned-policy?name={policyName}&v=2
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The newer API will eventually become the default (and only) one. The older
 | 
					
						
							|  |  |  | // response is to return only the policy JSON. The newer response returns
 | 
					
						
							|  |  |  | // timestamps along with the policy JSON. Both versions are supported for now,
 | 
					
						
							|  |  |  | // for smooth transition to new API.
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) InfoCannedPolicy(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.GetPolicyAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 01:03:39 +08:00
										 |  |  | 	name := mux.Vars(r)["name"] | 
					
						
							|  |  |  | 	policies := newMappedPolicy(name).toSlice() | 
					
						
							|  |  |  | 	if len(policies) != 1 { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errTooManyPolicies), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	setReqInfoPolicyName(ctx, name) | 
					
						
							| 
									
										
										
										
											2021-12-12 01:03:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	policyDoc, err := globalIAMSys.InfoPolicy(name) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 01:03:39 +08:00
										 |  |  | 	// Is the new API version being requested?
 | 
					
						
							|  |  |  | 	infoPolicyAPIVersion := r.Form.Get("v") | 
					
						
							|  |  |  | 	if infoPolicyAPIVersion == "2" { | 
					
						
							|  |  |  | 		buf, err := json.MarshalIndent(policyDoc, "", " ") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		w.Write(buf) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} else if infoPolicyAPIVersion != "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errors.New("invalid version parameter 'v' supplied")), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return the older API response value of just the policy json.
 | 
					
						
							|  |  |  | 	buf, err := json.MarshalIndent(policyDoc.Policy, "", " ") | 
					
						
							| 
									
										
										
										
											2021-05-30 00:22:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-09-28 01:24:04 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-30 00:22:22 +08:00
										 |  |  | 	w.Write(buf) | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | // ListBucketPolicies - GET /minio/admin/v3/list-canned-policies?bucket={bucket}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListBucketPolicies(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.ListUserPoliciesAdminAction) | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 	bucket := mux.Vars(r)["bucket"] | 
					
						
							| 
									
										
										
										
											2021-11-16 06:14:22 +08:00
										 |  |  | 	policies, err := globalIAMSys.ListPolicies(ctx, bucket) | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	newPolicies := make(map[string]policy.Policy) | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 	for name, p := range policies { | 
					
						
							|  |  |  | 		_, err = json.Marshal(p) | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 		newPolicies[name] = p | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-28 01:15:02 +08:00
										 |  |  | 	if err = json.NewEncoder(w).Encode(newPolicies); err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // ListCannedPolicies - GET /minio/admin/v3/list-canned-policies
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) ListCannedPolicies(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.ListUserPoliciesAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-16 06:14:22 +08:00
										 |  |  | 	policies, err := globalIAMSys.ListPolicies(ctx, "") | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	newPolicies := make(map[string]policy.Policy) | 
					
						
							| 
									
										
										
										
											2020-04-16 03:16:40 +08:00
										 |  |  | 	for name, p := range policies { | 
					
						
							|  |  |  | 		_, err = json.Marshal(p) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2020-04-16 03:16:40 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		newPolicies[name] = p | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err = json.NewEncoder(w).Encode(newPolicies); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // RemoveCannedPolicy - DELETE /minio/admin/v3/remove-canned-policy?name=<policy_name>
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.DeletePolicyAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	policyName := vars["name"] | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	setReqInfoPolicyName(ctx, policyName) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 06:38:57 +08:00
										 |  |  | 	if err := globalIAMSys.DeletePolicy(ctx, policyName, true); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	// Call cluster-replication policy creation hook to replicate policy deletion to
 | 
					
						
							|  |  |  | 	// other minio clusters.
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		Type:      madmin.SRIAMItemPolicy, | 
					
						
							|  |  |  | 		Name:      policyName, | 
					
						
							|  |  |  | 		UpdatedAt: UTCNow(), | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:30:59 +08:00
										 |  |  | // AddCannedPolicy - PUT /minio/admin/v3/add-canned-policy?name=<policy_name>
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.CreatePolicyAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	policyName := vars["name"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-03 00:27:35 +08:00
										 |  |  | 	// Policy has space characters in begin and end reject such inputs.
 | 
					
						
							|  |  |  | 	if hasSpaceBE(policyName) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	setReqInfoPolicyName(ctx, policyName) | 
					
						
							| 
									
										
										
										
											2022-05-03 00:27:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-04 19:51:26 +08:00
										 |  |  | 	// Reject policy names with commas.
 | 
					
						
							|  |  |  | 	if strings.Contains(policyName, ",") { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrPolicyInvalidName), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	// Error out if Content-Length is missing.
 | 
					
						
							|  |  |  | 	if r.ContentLength <= 0 { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Error out if Content-Length is beyond allowed size.
 | 
					
						
							|  |  |  | 	if r.ContentLength > maxBucketPolicySize { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	iamPolicyBytes, err := io.ReadAll(io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	iamPolicy, err := policy.ParseConfig(bytes.NewReader(iamPolicyBytes)) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-01-04 03:28:52 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Version in policy must not be empty
 | 
					
						
							|  |  |  | 	if iamPolicy.Version == "" { | 
					
						
							| 
									
										
										
										
											2022-12-07 00:07:24 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrPolicyInvalidVersion), r.URL) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	updatedAt, err := globalIAMSys.SetPolicy(ctx, policyName, *iamPolicy) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 	// Call cluster-replication policy creation hook to replicate policy to
 | 
					
						
							|  |  |  | 	// other minio clusters.
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		Type:      madmin.SRIAMItemPolicy, | 
					
						
							|  |  |  | 		Name:      policyName, | 
					
						
							|  |  |  | 		Policy:    iamPolicyBytes, | 
					
						
							|  |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | // SetPolicyForUserOrGroup - sets a policy on a user or a group.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // PUT /minio/admin/v3/set-policy?policy=xxx&user-or-group=?[&is-group]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Deprecated: This API is replaced by attach/detach policy APIs for specific
 | 
					
						
							|  |  |  | // type of users (builtin or LDAP).
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2020-05-12 01:34:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.AttachPolicyAdminAction) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	policyName := vars["policyName"] | 
					
						
							|  |  |  | 	entityName := vars["userOrGroup"] | 
					
						
							|  |  |  | 	isGroup := vars["isGroup"] == "true" | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	setReqInfoPolicyName(ctx, policyName) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-20 06:21:21 +08:00
										 |  |  | 	if !isGroup { | 
					
						
							| 
									
										
										
										
											2021-02-26 05:49:59 +08:00
										 |  |  | 		ok, _, err := globalIAMSys.IsTempUser(entityName) | 
					
						
							| 
									
										
										
										
											2020-04-09 16:04:08 +08:00
										 |  |  | 		if err != nil && err != errNoSuchUser { | 
					
						
							| 
									
										
										
										
											2019-12-20 06:21:21 +08:00
										 |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if ok { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 		// When the user is root credential you are not allowed to
 | 
					
						
							|  |  |  | 		// add policies for root user.
 | 
					
						
							|  |  |  | 		if entityName == globalActiveCred.AccessKey { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-12-20 06:21:21 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 	// Validate that user or group exists.
 | 
					
						
							|  |  |  | 	if !isGroup { | 
					
						
							|  |  |  | 		if globalIAMSys.GetUsersSysType() == MinIOUsersSysType { | 
					
						
							|  |  |  | 			_, ok := globalIAMSys.GetUser(ctx, entityName) | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errNoSuchUser), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		_, err := globalIAMSys.GetGroupDescription(entityName) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	userType := regUser | 
					
						
							|  |  |  | 	if globalIAMSys.GetUsersSysType() == LDAPUsersSysType { | 
					
						
							|  |  |  | 		userType = stsUser | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Validate that the user or group exists in LDAP and use the normalized
 | 
					
						
							|  |  |  | 		// form of the entityName (which will be an LDAP DN).
 | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		if isGroup { | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 			var foundGroupDN *xldap.DNSearchResult | 
					
						
							| 
									
										
										
										
											2024-04-25 23:50:16 +08:00
										 |  |  | 			var underBaseDN bool | 
					
						
							|  |  |  | 			if foundGroupDN, underBaseDN, err = globalIAMSys.LDAPConfig.GetValidatedGroupDN(nil, entityName); err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 				iamLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 			} else if foundGroupDN == nil || !underBaseDN { | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 				err = errNoSuchGroup | 
					
						
							| 
									
										
										
										
											2025-07-02 00:00:17 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				entityName = foundGroupDN.NormDN | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 			var foundUserDN *xldap.DNSearchResult | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 			if foundUserDN, err = globalIAMSys.LDAPConfig.GetValidatedDNForUsername(entityName); err != nil { | 
					
						
							|  |  |  | 				iamLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 			} else if foundUserDN == nil { | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 				err = errNoSuchUser | 
					
						
							| 
									
										
										
										
											2025-07-02 00:00:17 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				entityName = foundUserDN.NormDN | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	updatedAt, err := globalIAMSys.PolicyDBSet(ctx, entityName, policyName, userType, isGroup) | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 	replLogIf(ctx, globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{ | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 		Type: madmin.SRIAMItemPolicyMapping, | 
					
						
							|  |  |  | 		PolicyMapping: &madmin.SRPolicyMapping{ | 
					
						
							|  |  |  | 			UserOrGroup: entityName, | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 			UserType:    int(userType), | 
					
						
							| 
									
										
										
										
											2021-10-07 07:36:31 +08:00
										 |  |  | 			IsGroup:     isGroup, | 
					
						
							|  |  |  | 			Policy:      policyName, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2023-01-27 03:11:54 +08:00
										 |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | // ListPolicyMappingEntities - GET /minio/admin/v3/idp/builtin/policy-entities?policy=xxx&user=xxx&group=xxx
 | 
					
						
							| 
									
										
										
										
											2022-12-20 02:37:03 +08:00
										 |  |  | func (a adminAPIHandlers) ListPolicyMappingEntities(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-12-20 02:37:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check authorization.
 | 
					
						
							|  |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 		policy.ListGroupsAdminAction, policy.ListUsersAdminAction, policy.ListUserPoliciesAdminAction) | 
					
						
							| 
									
										
										
										
											2022-12-20 02:37:03 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate API arguments.
 | 
					
						
							|  |  |  | 	q := madmin.PolicyEntitiesQuery{ | 
					
						
							|  |  |  | 		Users:  r.Form["user"], | 
					
						
							|  |  |  | 		Groups: r.Form["group"], | 
					
						
							|  |  |  | 		Policy: r.Form["policy"], | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Query IAM
 | 
					
						
							|  |  |  | 	res, err := globalIAMSys.QueryPolicyEntities(r.Context(), q) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Encode result and send response.
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(res) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 	econfigData, err := madmin.EncryptData(password, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | // AttachDetachPolicyBuiltin - POST /minio/admin/v3/idp/builtin/policy/{operation}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) AttachDetachPolicyBuiltin(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, policy.UpdatePolicyAssociationAction, | 
					
						
							|  |  |  | 		policy.AttachPolicyAdminAction) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	// Ensure body content type is opaque to ensure that request body has not
 | 
					
						
							|  |  |  | 	// been interpreted as form data.
 | 
					
						
							|  |  |  | 	contentType := r.Header.Get("Content-Type") | 
					
						
							|  |  |  | 	if contentType != "application/octet-stream" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrBadRequest), r.URL) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	operation := mux.Vars(r)["operation"] | 
					
						
							|  |  |  | 	if operation != "attach" && operation != "detach" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminInvalidArgument), r.URL) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	isAttach := operation == "attach" | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var par madmin.PolicyAssociationReq | 
					
						
							|  |  |  | 	if err = json.Unmarshal(reqBytes, &par); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = par.IsValid(); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	updatedAt, addedOrRemoved, _, err := globalIAMSys.PolicyDBUpdateBuiltin(ctx, isAttach, par) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if err == errNoSuchUser || err == errNoSuchGroup { | 
					
						
							| 
									
										
										
										
											2023-05-26 21:31:24 +08:00
										 |  |  | 			if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 				// When LDAP is enabled, warn user that they are using the wrong
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 				// API. FIXME: error can be no such group as well - fix errNoSuchUserLDAPWarn
 | 
					
						
							| 
									
										
										
										
											2023-05-26 21:31:24 +08:00
										 |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errNoSuchUserLDAPWarn), r.URL) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 	setReqInfoPolicyName(ctx, strings.Join(addedOrRemoved, ",")) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	respBody := madmin.PolicyAssociationResp{ | 
					
						
							|  |  |  | 		UpdatedAt: updatedAt, | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	if isAttach { | 
					
						
							|  |  |  | 		respBody.PoliciesAttached = addedOrRemoved | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 		respBody.PoliciesDetached = addedOrRemoved | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(respBody) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	encryptedData, err := madmin.EncryptData(password, data) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							| 
									
										
										
										
											2022-12-14 04:13:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 02:51:24 +08:00
										 |  |  | // RevokeTokens - POST /minio/admin/v3/revoke-tokens/{userProvider}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) RevokeTokens(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := r.Context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							|  |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	userProvider := mux.Vars(r)["userProvider"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	user := r.Form.Get("user") | 
					
						
							|  |  |  | 	tokenRevokeType := r.Form.Get("tokenRevokeType") | 
					
						
							|  |  |  | 	fullRevoke := r.Form.Get("fullRevoke") == "true" | 
					
						
							|  |  |  | 	isTokenSelfRevoke := user == "" | 
					
						
							|  |  |  | 	if !isTokenSelfRevoke { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		user, err = getUserWithProvider(ctx, userProvider, user, false) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (user != "" && tokenRevokeType == "" && !fullRevoke) || (tokenRevokeType != "" && fullRevoke) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	adminPrivilege := globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							|  |  |  | 		Action:          policy.RemoveServiceAccountAdminAction, | 
					
						
							|  |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 		IsOwner:         owner, | 
					
						
							|  |  |  | 		Claims:          cred.Claims, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !adminPrivilege || isTokenSelfRevoke { | 
					
						
							|  |  |  | 		parentUser := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			parentUser = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !isTokenSelfRevoke && user != parentUser { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		user = parentUser | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Infer token revoke type from the request if requestor is STS.
 | 
					
						
							|  |  |  | 	if isTokenSelfRevoke && tokenRevokeType == "" && !fullRevoke { | 
					
						
							|  |  |  | 		if cred.IsTemp() { | 
					
						
							|  |  |  | 			tokenRevokeType, _ = cred.Claims[tokenRevokeTypeClaim].(string) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tokenRevokeType == "" { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNoTokenRevokeType), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := globalIAMSys.RevokeTokens(ctx, user, tokenRevokeType) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessNoContent(w) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:06:31 +08:00
										 |  |  | // InfoAccessKey - GET /minio/admin/v3/info-access-key?access-key=<access-key>
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) InfoAccessKey(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := r.Context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							|  |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey := mux.Vars(r)["accessKey"] | 
					
						
							|  |  |  | 	if accessKey == "" { | 
					
						
							|  |  |  | 		accessKey = cred.AccessKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u, ok := globalIAMSys.GetUser(ctx, accessKey) | 
					
						
							|  |  |  | 	targetCred := u.Credentials | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							|  |  |  | 		Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							|  |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 		IsOwner:         owner, | 
					
						
							|  |  |  | 		Claims:          cred.Claims, | 
					
						
							|  |  |  | 	}) { | 
					
						
							|  |  |  | 		// If requested user does not exist and requestor is not allowed to list service accounts, return access denied.
 | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		requestUser := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			requestUser = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if requestUser != targetCred.ParentUser { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminNoSuchAccessKey), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		sessionPolicy *policy.Policy | 
					
						
							|  |  |  | 		err           error | 
					
						
							|  |  |  | 		userType      string | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case targetCred.IsTemp(): | 
					
						
							|  |  |  | 		userType = "STS" | 
					
						
							|  |  |  | 		_, sessionPolicy, err = globalIAMSys.GetTemporaryAccount(ctx, accessKey) | 
					
						
							|  |  |  | 		if err == errNoSuchTempAccount { | 
					
						
							|  |  |  | 			err = errNoSuchAccessKey | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case targetCred.IsServiceAccount(): | 
					
						
							|  |  |  | 		userType = "Service Account" | 
					
						
							|  |  |  | 		_, sessionPolicy, err = globalIAMSys.GetServiceAccount(ctx, accessKey) | 
					
						
							|  |  |  | 		if err == errNoSuchServiceAccount { | 
					
						
							|  |  |  | 			err = errNoSuchAccessKey | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		err = errNoSuchAccessKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if session policy is nil or empty, then it is implied policy
 | 
					
						
							|  |  |  | 	impliedPolicy := sessionPolicy == nil || (sessionPolicy.Version == "" && len(sessionPolicy.Statements) == 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var svcAccountPolicy policy.Policy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !impliedPolicy { | 
					
						
							|  |  |  | 		svcAccountPolicy = *sessionPolicy | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		policiesNames, err := globalIAMSys.PolicyDBGet(targetCred.ParentUser, targetCred.Groups...) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		svcAccountPolicy = globalIAMSys.GetCombinedPolicy(policiesNames...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policyJSON, err := json.MarshalIndent(svcAccountPolicy, "", " ") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var expiration *time.Time | 
					
						
							|  |  |  | 	if !targetCred.Expiration.IsZero() && !targetCred.Expiration.Equal(timeSentinel) { | 
					
						
							|  |  |  | 		expiration = &targetCred.Expiration | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	userProvider := guessUserProvider(targetCred) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	infoResp := madmin.InfoAccessKeyResp{ | 
					
						
							|  |  |  | 		AccessKey: accessKey, | 
					
						
							|  |  |  | 		InfoServiceAccountResp: madmin.InfoServiceAccountResp{ | 
					
						
							|  |  |  | 			ParentUser:    targetCred.ParentUser, | 
					
						
							|  |  |  | 			Name:          targetCred.Name, | 
					
						
							|  |  |  | 			Description:   targetCred.Description, | 
					
						
							|  |  |  | 			AccountStatus: targetCred.Status, | 
					
						
							|  |  |  | 			ImpliedPolicy: impliedPolicy, | 
					
						
							|  |  |  | 			Policy:        string(policyJSON), | 
					
						
							|  |  |  | 			Expiration:    expiration, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		UserType:     userType, | 
					
						
							|  |  |  | 		UserProvider: userProvider, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	populateProviderInfoFromClaims(targetCred.Claims, userProvider, &infoResp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(infoResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(cred.SecretKey, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2024-04-06 11:13:35 +08:00
										 |  |  | 	allPoliciesFile           = "policies.json" | 
					
						
							|  |  |  | 	allUsersFile              = "users.json" | 
					
						
							|  |  |  | 	allGroupsFile             = "groups.json" | 
					
						
							|  |  |  | 	allSvcAcctsFile           = "svcaccts.json" | 
					
						
							|  |  |  | 	userPolicyMappingsFile    = "user_mappings.json" | 
					
						
							|  |  |  | 	groupPolicyMappingsFile   = "group_mappings.json" | 
					
						
							|  |  |  | 	stsUserPolicyMappingsFile = "stsuser_mappings.json" | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	iamAssetsDir = "iam-assets" | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | var iamExportFiles = []string{ | 
					
						
							|  |  |  | 	allPoliciesFile, | 
					
						
							|  |  |  | 	allUsersFile, | 
					
						
							|  |  |  | 	allGroupsFile, | 
					
						
							|  |  |  | 	allSvcAcctsFile, | 
					
						
							|  |  |  | 	userPolicyMappingsFile, | 
					
						
							|  |  |  | 	groupPolicyMappingsFile, | 
					
						
							|  |  |  | 	stsUserPolicyMappingsFile, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | // ExportIAMHandler - exports all iam info as a zipped file
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.ExportIAMAction) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							| 
									
										
										
										
											2024-12-12 10:09:40 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Initialize a zip writer which will provide a zipped content
 | 
					
						
							|  |  |  | 	// of bucket metadata
 | 
					
						
							|  |  |  | 	zipWriter := zip.NewWriter(w) | 
					
						
							|  |  |  | 	defer zipWriter.Close() | 
					
						
							|  |  |  | 	rawDataFn := func(r io.Reader, filename string, sz int) error { | 
					
						
							|  |  |  | 		header, zerr := zip.FileInfoHeader(dummyFileInfo{ | 
					
						
							|  |  |  | 			name:    filename, | 
					
						
							|  |  |  | 			size:    int64(sz), | 
					
						
							|  |  |  | 			mode:    0o600, | 
					
						
							|  |  |  | 			modTime: time.Now(), | 
					
						
							|  |  |  | 			isDir:   false, | 
					
						
							|  |  |  | 			sys:     nil, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		if zerr != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, zerr) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		header.Method = zip.Deflate | 
					
						
							|  |  |  | 		zwriter, zerr := zipWriter.CreateHeader(header) | 
					
						
							|  |  |  | 		if zerr != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, zerr) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := io.Copy(zwriter, r); err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 	for _, f := range iamExportFiles { | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		iamFile := pathJoin(iamAssetsDir, f) | 
					
						
							|  |  |  | 		switch f { | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		case allPoliciesFile: | 
					
						
							|  |  |  | 			allPolicies, err := globalIAMSys.ListPolicies(ctx, "") | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 				adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			policiesData, err := json.Marshal(allPolicies) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(policiesData), iamFile, len(policiesData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case allUsersFile: | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			userIdentities := make(map[string]UserIdentity) | 
					
						
							|  |  |  | 			err := globalIAMSys.store.loadUsers(ctx, regUser, userIdentities) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			userAccounts := make(map[string]madmin.AddOrUpdateUserReq) | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			for u, uid := range userIdentities { | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				userAccounts[u] = madmin.AddOrUpdateUserReq{ | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 					SecretKey: uid.Credentials.SecretKey, | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 					Status: func() madmin.AccountStatus { | 
					
						
							|  |  |  | 						// Export current credential status
 | 
					
						
							|  |  |  | 						if uid.Credentials.Status == auth.AccountOff { | 
					
						
							|  |  |  | 							return madmin.AccountDisabled | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return madmin.AccountEnabled | 
					
						
							|  |  |  | 					}(), | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			userData, err := json.Marshal(userAccounts) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(userData), iamFile, len(userData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case allGroupsFile: | 
					
						
							|  |  |  | 			groups := make(map[string]GroupInfo) | 
					
						
							|  |  |  | 			err := globalIAMSys.store.loadGroups(ctx, groups) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			groupData, err := json.Marshal(groups) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(groupData), iamFile, len(groupData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case allSvcAcctsFile: | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 			serviceAccounts := make(map[string]UserIdentity) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			err := globalIAMSys.store.loadUsers(ctx, svcUser, serviceAccounts) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			svcAccts := make(map[string]madmin.SRSvcAccCreate) | 
					
						
							|  |  |  | 			for user, acc := range serviceAccounts { | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 				if user == siteReplicatorSvcAcc { | 
					
						
							|  |  |  | 					// skip site-replication service account.
 | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 				claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, acc.Credentials.AccessKey) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 				sa, policy, err := globalIAMSys.GetServiceAccount(ctx, acc.Credentials.AccessKey) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var policyJSON []byte | 
					
						
							|  |  |  | 				if policy != nil { | 
					
						
							|  |  |  | 					policyJSON, err = json.Marshal(policy) | 
					
						
							|  |  |  | 					if err != nil { | 
					
						
							|  |  |  | 						writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				svcAccts[user] = madmin.SRSvcAccCreate{ | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 					Parent:        acc.Credentials.ParentUser, | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					AccessKey:     user, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 					SecretKey:     acc.Credentials.SecretKey, | 
					
						
							|  |  |  | 					Groups:        acc.Credentials.Groups, | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					Claims:        claims, | 
					
						
							| 
									
										
										
										
											2025-02-25 09:43:59 +08:00
										 |  |  | 					SessionPolicy: policyJSON, | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 					Status:        acc.Credentials.Status, | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 					Name:          sa.Name, | 
					
						
							|  |  |  | 					Description:   sa.Description, | 
					
						
							|  |  |  | 					Expiration:    &sa.Expiration, | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			svcAccData, err := json.Marshal(svcAccts) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(svcAccData), iamFile, len(svcAccData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case userPolicyMappingsFile: | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			userPolicyMap := xsync.NewMapOf[string, MappedPolicy]() | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			err := globalIAMSys.store.loadMappedPolicies(ctx, regUser, false, userPolicyMap) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			userPolData, err := json.Marshal(mappedPoliciesToMap(userPolicyMap)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(userPolData), iamFile, len(userPolData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case groupPolicyMappingsFile: | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			groupPolicyMap := xsync.NewMapOf[string, MappedPolicy]() | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			err := globalIAMSys.store.loadMappedPolicies(ctx, regUser, true, groupPolicyMap) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			grpPolData, err := json.Marshal(mappedPoliciesToMap(groupPolicyMap)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(grpPolData), iamFile, len(grpPolData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case stsUserPolicyMappingsFile: | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			userPolicyMap := xsync.NewMapOf[string, MappedPolicy]() | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			err := globalIAMSys.store.loadMappedPolicies(ctx, stsUser, false, userPolicyMap) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-27 02:12:57 +08:00
										 |  |  | 			userPolData, err := json.Marshal(mappedPoliciesToMap(userPolicyMap)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = rawDataFn(bytes.NewReader(userPolData), iamFile, len(userPolData)); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ImportIAM - imports all IAM info into MinIO
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 	a.importIAM(w, r, "") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ImportIAMV2 - imports all IAM info into MinIO
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ImportIAMV2(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	a.importIAM(w, r, "v2") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ImportIAM - imports all IAM info into MinIO
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) importIAM(w http.ResponseWriter, r *http.Request, apiVer string) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 10:09:40 +08:00
										 |  |  | 	// Validate signature, permissions and get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI, _ := validateAdminReq(ctx, w, r, policy.ImportIAMAction) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-12-12 10:09:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	data, err := io.ReadAll(r.Body) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	reader := bytes.NewReader(data) | 
					
						
							|  |  |  | 	zr, err := zip.NewReader(reader, int64(len(data))) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var skipped, removed, added madmin.IAMEntities | 
					
						
							|  |  |  | 	var failed madmin.IAMErrEntities | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 	// import policies first
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, allPoliciesFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allPoliciesFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 			var allPolicies map[string]policy.Policy | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err = io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allPoliciesFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			err = json.Unmarshal(data, &allPolicies) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, allPoliciesFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for policyName, policy := range allPolicies { | 
					
						
							|  |  |  | 				if policy.IsEmpty() { | 
					
						
							|  |  |  | 					err = globalIAMSys.DeletePolicy(ctx, policyName, true) | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					removed.Policies = append(removed.Policies, policyName) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 					_, err = globalIAMSys.SetPolicy(ctx, policyName, policy) | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					added.Policies = append(added.Policies, policyName) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, allPoliciesFile, policyName), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import users
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, allUsersFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allUsersFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var userAccts map[string]madmin.AddOrUpdateUserReq | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allUsersFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			err = json.Unmarshal(data, &userAccts) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, allUsersFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for accessKey, ureq := range userAccts { | 
					
						
							|  |  |  | 				// Not allowed to add a user with same access key as root credential
 | 
					
						
							| 
									
										
										
										
											2023-03-14 03:46:17 +08:00
										 |  |  | 				if accessKey == globalActiveCred.AccessKey { | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAddUserInvalidArgument, err, allUsersFile, accessKey), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 				user, exists := globalIAMSys.GetUser(ctx, accessKey) | 
					
						
							|  |  |  | 				if exists && (user.Credentials.IsTemp() || user.Credentials.IsServiceAccount()) { | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					// Updating STS credential is not allowed, and this API does not
 | 
					
						
							|  |  |  | 					// support updating service accounts.
 | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAddUserInvalidArgument, err, allUsersFile, accessKey), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Check if accessKey has beginning and end space characters, this only applies to new users.
 | 
					
						
							|  |  |  | 				if !exists && hasSpaceBE(accessKey) { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminResourceInvalidArgument, err, allUsersFile, accessKey), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 				if _, err = globalIAMSys.CreateUser(ctx, accessKey, ureq); err != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.Users = append(failed.Users, madmin.IAMErrEntity{Name: accessKey, Error: err}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.Users = append(added.Users, accessKey) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import groups
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, allGroupsFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allGroupsFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var grpInfos map[string]GroupInfo | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allGroupsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = json.Unmarshal(data, &grpInfos); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, allGroupsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for group, grpInfo := range grpInfos { | 
					
						
							|  |  |  | 				// Check if group already exists
 | 
					
						
							|  |  |  | 				if _, gerr := globalIAMSys.GetGroupDescription(group); gerr != nil { | 
					
						
							|  |  |  | 					// If group does not exist, then check if the group has beginning and end space characters
 | 
					
						
							|  |  |  | 					// we will reject such group names.
 | 
					
						
							|  |  |  | 					if errors.Is(gerr, errNoSuchGroup) && hasSpaceBE(group) { | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 						writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminResourceInvalidArgument, gerr, allGroupsFile, group), r.URL) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 				if _, gerr := globalIAMSys.AddUsersToGroup(ctx, group, grpInfo.Members); gerr != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.Groups = append(failed.Groups, madmin.IAMErrEntity{Name: group, Error: err}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.Groups = append(added.Groups, group) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import service accounts
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, allSvcAcctsFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allSvcAcctsFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var serviceAcctReqs map[string]madmin.SRSvcAccCreate | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, allSvcAcctsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = json.Unmarshal(data, &serviceAcctReqs); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, allSvcAcctsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Validations for LDAP enabled deployments.
 | 
					
						
							|  |  |  | 			if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				skippedAccessKeys, err := globalIAMSys.NormalizeLDAPAccessKeypairs(ctx, serviceAcctReqs) | 
					
						
							|  |  |  | 				skipped.ServiceAccounts = append(skipped.ServiceAccounts, skippedAccessKeys...) | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, ""), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			for user, svcAcctReq := range serviceAcctReqs { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				if slices.Contains(skipped.ServiceAccounts, user) { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 				var sp *policy.Policy | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				var err error | 
					
						
							| 
									
										
										
										
											2025-02-25 09:43:59 +08:00
										 |  |  | 				if len(svcAcctReq.SessionPolicy) > 0 { | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 					sp, err = policy.ParseConfig(bytes.NewReader(svcAcctReq.SessionPolicy)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					if err != nil { | 
					
						
							|  |  |  | 						writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL) | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 				// service account access key cannot have space characters
 | 
					
						
							|  |  |  | 				// beginning and end of the string.
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				if hasSpaceBE(svcAcctReq.AccessKey) { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				updateReq := true | 
					
						
							|  |  |  | 				_, _, err = globalIAMSys.GetServiceAccount(ctx, svcAcctReq.AccessKey) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					if !errors.Is(err, errNoSuchServiceAccount) { | 
					
						
							|  |  |  | 						writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL) | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					updateReq = false | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if updateReq { | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 					// If the service account exists, we remove it to ensure a
 | 
					
						
							|  |  |  | 					// clean import.
 | 
					
						
							|  |  |  | 					err := globalIAMSys.DeleteServiceAccount(ctx, svcAcctReq.AccessKey, true) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 					if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-15 02:12:07 +08:00
										 |  |  | 						delErr := fmt.Errorf("failed to delete existing service account (%s) before importing it: %w", svcAcctReq.AccessKey, err) | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 						writeErrorResponseJSON(ctx, w, importError(ctx, delErr, allSvcAcctsFile, user), r.URL) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				opts := newServiceAccountOpts{ | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 					accessKey:                  user, | 
					
						
							|  |  |  | 					secretKey:                  svcAcctReq.SecretKey, | 
					
						
							|  |  |  | 					sessionPolicy:              sp, | 
					
						
							|  |  |  | 					claims:                     svcAcctReq.Claims, | 
					
						
							| 
									
										
										
										
											2023-05-18 08:05:36 +08:00
										 |  |  | 					name:                       svcAcctReq.Name, | 
					
						
							|  |  |  | 					description:                svcAcctReq.Description, | 
					
						
							| 
									
										
										
										
											2023-04-29 03:24:14 +08:00
										 |  |  | 					expiration:                 svcAcctReq.Expiration, | 
					
						
							|  |  |  | 					allowSiteReplicatorAccount: false, | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-02 04:19:13 +08:00
										 |  |  | 				if _, _, err = globalIAMSys.NewServiceAccount(ctx, svcAcctReq.Parent, svcAcctReq.Groups, opts); err != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.ServiceAccounts = append(failed.ServiceAccounts, madmin.IAMErrEntity{Name: user, Error: err}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.ServiceAccounts = append(added.ServiceAccounts, user) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import user policy mappings
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, userPolicyMappingsFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, userPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var userPolicyMap map[string]MappedPolicy | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, userPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = json.Unmarshal(data, &userPolicyMap); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, userPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for u, pm := range userPolicyMap { | 
					
						
							|  |  |  | 				// disallow setting policy mapping if user is a temporary user
 | 
					
						
							|  |  |  | 				ok, _, err := globalIAMSys.IsTempUser(u) | 
					
						
							|  |  |  | 				if err != nil && err != errNoSuchUser { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, userPolicyMappingsFile, u), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ok { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, userPolicyMappingsFile, u), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 				if _, err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, regUser, false); err != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.UserPolicies = append( | 
					
						
							|  |  |  | 						failed.UserPolicies, | 
					
						
							|  |  |  | 						madmin.IAMErrPolicyEntity{ | 
					
						
							|  |  |  | 							Name:     u, | 
					
						
							|  |  |  | 							Policies: strings.Split(pm.Policies, ","), | 
					
						
							|  |  |  | 							Error:    err, | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.UserPolicies = append(added.UserPolicies, map[string][]string{u: strings.Split(pm.Policies, ",")}) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import group policy mappings
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, groupPolicyMappingsFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, groupPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var grpPolicyMap map[string]MappedPolicy | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, groupPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = json.Unmarshal(data, &grpPolicyMap); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, groupPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Validations for LDAP enabled deployments.
 | 
					
						
							|  |  |  | 			if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 				isGroup := true | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				skippedDN, err := globalIAMSys.NormalizeLDAPMappingImport(ctx, isGroup, grpPolicyMap) | 
					
						
							|  |  |  | 				skipped.Groups = append(skipped.Groups, skippedDN...) | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, groupPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			for g, pm := range grpPolicyMap { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				if slices.Contains(skipped.Groups, g) { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 				if _, err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, unknownIAMUserType, true); err != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.GroupPolicies = append( | 
					
						
							|  |  |  | 						failed.GroupPolicies, | 
					
						
							|  |  |  | 						madmin.IAMErrPolicyEntity{ | 
					
						
							|  |  |  | 							Name:     g, | 
					
						
							|  |  |  | 							Policies: strings.Split(pm.Policies, ","), | 
					
						
							|  |  |  | 							Error:    err, | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.GroupPolicies = append(added.GroupPolicies, map[string][]string{g: strings.Split(pm.Policies, ",")}) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// import sts user policy mappings
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2022-07-22 08:51:33 +08:00
										 |  |  | 		f, err := zr.Open(pathJoin(iamAssetsDir, stsUserPolicyMappingsFile)) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsUserPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			defer f.Close() | 
					
						
							|  |  |  | 			var userPolicyMap map[string]MappedPolicy | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 			data, err := io.ReadAll(f) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsUserPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err = json.Unmarshal(data, &userPolicyMap); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, stsUserPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Validations for LDAP enabled deployments.
 | 
					
						
							|  |  |  | 			if globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 				isGroup := true | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				skippedDN, err := globalIAMSys.NormalizeLDAPMappingImport(ctx, !isGroup, userPolicyMap) | 
					
						
							|  |  |  | 				skipped.Users = append(skipped.Users, skippedDN...) | 
					
						
							| 
									
										
										
										
											2024-04-18 23:15:02 +08:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, stsUserPolicyMappingsFile, ""), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 			for u, pm := range userPolicyMap { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 				if slices.Contains(skipped.Users, u) { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				// disallow setting policy mapping if user is a temporary user
 | 
					
						
							|  |  |  | 				ok, _, err := globalIAMSys.IsTempUser(u) | 
					
						
							|  |  |  | 				if err != nil && err != errNoSuchUser { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, err, stsUserPolicyMappingsFile, u), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ok { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, stsUserPolicyMappingsFile, u), r.URL) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-04-24 09:23:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 02:11:45 +08:00
										 |  |  | 				if _, err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, stsUser, false); err != nil { | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 					failed.STSPolicies = append( | 
					
						
							|  |  |  | 						failed.STSPolicies, | 
					
						
							|  |  |  | 						madmin.IAMErrPolicyEntity{ | 
					
						
							|  |  |  | 							Name:     u, | 
					
						
							|  |  |  | 							Policies: strings.Split(pm.Policies, ","), | 
					
						
							|  |  |  | 							Error:    err, | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					added.STSPolicies = append(added.STSPolicies, map[string][]string{u: strings.Split(pm.Policies, ",")}) | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-10 00:59:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if apiVer == "v2" { | 
					
						
							|  |  |  | 		iamr := madmin.ImportIAMResult{ | 
					
						
							|  |  |  | 			Skipped: skipped, | 
					
						
							|  |  |  | 			Removed: removed, | 
					
						
							|  |  |  | 			Added:   added, | 
					
						
							|  |  |  | 			Failed:  failed, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b, err := json.Marshal(iamr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		writeSuccessResponseJSON(w, b) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-06-24 00:25:15 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-29 01:19:04 +08:00
										 |  |  | func addExpirationToCondValues(exp *time.Time, condValues map[string][]string) error { | 
					
						
							|  |  |  | 	if exp == nil || exp.IsZero() || exp.Equal(timeSentinel) { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-30 08:56:02 +08:00
										 |  |  | 	dur := time.Until(*exp) | 
					
						
							| 
									
										
										
										
											2024-05-29 01:19:04 +08:00
										 |  |  | 	if dur <= 0 { | 
					
						
							|  |  |  | 		return errors.New("unsupported expiration time") | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-29 01:19:04 +08:00
										 |  |  | 	condValues["DurationSeconds"] = []string{strconv.FormatInt(int64(dur.Seconds()), 10)} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | func commonAddServiceAccount(r *http.Request, ldap bool) (context.Context, auth.Credentials, newServiceAccountOpts, madmin.AddServiceAccountReq, string, APIError) { | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							|  |  |  | 	objectAPI := newObjectLayerFn() | 
					
						
							|  |  |  | 	if objectAPI == nil || globalNotificationSys == nil { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErr(ErrServerNotInitialized) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cred, owner, s3Err := validateAdminSignature(ctx, r, "") | 
					
						
							|  |  |  | 	if s3Err != ErrNone { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErr(s3Err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var createReq madmin.AddServiceAccountReq | 
					
						
							|  |  |  | 	if err = json.Unmarshal(reqBytes, &createReq); err != nil { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 02:08:04 +08:00
										 |  |  | 	if createReq.Expiration != nil && !createReq.Expiration.IsZero() { | 
					
						
							|  |  |  | 		// truncate expiration at the second.
 | 
					
						
							|  |  |  | 		truncateTime := createReq.Expiration.Truncate(time.Second) | 
					
						
							|  |  |  | 		createReq.Expiration = &truncateTime | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	// service account access key cannot have space characters beginning and end of the string.
 | 
					
						
							|  |  |  | 	if hasSpaceBE(createReq.AccessKey) { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := createReq.Validate(); err != nil { | 
					
						
							|  |  |  | 		// Since this validation would happen client side as well, we only send
 | 
					
						
							|  |  |  | 		// a generic error message here.
 | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErr(ErrAdminResourceInvalidArgument) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// If the request did not set a TargetUser, the service account is
 | 
					
						
							|  |  |  | 	// created for the request sender.
 | 
					
						
							|  |  |  | 	targetUser := createReq.TargetUser | 
					
						
							|  |  |  | 	if targetUser == "" { | 
					
						
							|  |  |  | 		targetUser = cred.AccessKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	description := createReq.Description | 
					
						
							|  |  |  | 	if description == "" { | 
					
						
							|  |  |  | 		description = createReq.Comment | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	opts := newServiceAccountOpts{ | 
					
						
							|  |  |  | 		accessKey:   createReq.AccessKey, | 
					
						
							|  |  |  | 		secretKey:   createReq.SecretKey, | 
					
						
							|  |  |  | 		name:        createReq.Name, | 
					
						
							|  |  |  | 		description: description, | 
					
						
							|  |  |  | 		expiration:  createReq.Expiration, | 
					
						
							| 
									
										
										
										
											2025-08-29 10:39:48 +08:00
										 |  |  | 		claims:      make(map[string]any), | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 	condValues := getConditionValues(r, "", cred) | 
					
						
							| 
									
										
										
										
											2024-05-29 01:19:04 +08:00
										 |  |  | 	err = addExpirationToCondValues(createReq.Expiration, condValues) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", toAdminAPIErr(ctx, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | 	denyOnly := (targetUser == cred.AccessKey || targetUser == cred.ParentUser) | 
					
						
							|  |  |  | 	if ldap && !denyOnly { | 
					
						
							|  |  |  | 		res, _ := globalIAMSys.LDAPConfig.GetValidatedDNForUsername(targetUser) | 
					
						
							| 
									
										
										
										
											2025-04-25 02:14:00 +08:00
										 |  |  | 		if res != nil && res.NormDN == cred.ParentUser { | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | 			denyOnly = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	// Check if action is allowed if creating access key for another user
 | 
					
						
							|  |  |  | 	// Check if action is explicitly denied if for self
 | 
					
						
							|  |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							|  |  |  | 		Action:          policy.CreateServiceAccountAdminAction, | 
					
						
							| 
									
										
										
										
											2024-02-13 00:36:16 +08:00
										 |  |  | 		ConditionValues: condValues, | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		IsOwner:         owner, | 
					
						
							|  |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | 		DenyOnly:        denyOnly, | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	}) { | 
					
						
							|  |  |  | 		return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", errorCodes.ToAPIErr(ErrAccessDenied) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var sp *policy.Policy | 
					
						
							|  |  |  | 	if len(createReq.Policy) > 0 { | 
					
						
							|  |  |  | 		sp, err = policy.ParseConfig(bytes.NewReader(createReq.Policy)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return ctx, auth.Credentials{}, newServiceAccountOpts{}, madmin.AddServiceAccountReq{}, "", toAdminAPIErr(ctx, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	opts.sessionPolicy = sp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ctx, cred, opts, createReq, targetUser, APIError{} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-11-26 01:17:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // setReqInfoPolicyName will set the given policyName as a tag on the context's request info,
 | 
					
						
							|  |  |  | // so that it appears in audit logs.
 | 
					
						
							|  |  |  | func setReqInfoPolicyName(ctx context.Context, policyName string) { | 
					
						
							|  |  |  | 	reqInfo := logger.GetReqInfo(ctx) | 
					
						
							|  |  |  | 	reqInfo.SetTags("policyName", policyName) | 
					
						
							|  |  |  | } |