| 
									
										
										
										
											2022-11-08 06:35:09 +08:00
										 |  |  | // Copyright (c) 2015-2022 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 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/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-06-04 03:58:48 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2022-11-08 06:35:09 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-11-08 06:35:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 08:53:08 +08:00
										 |  |  | 	"github.com/minio/madmin-go/v3" | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2022-11-08 06:35:09 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListLDAPPolicyMappingEntities lists users/groups mapped to given/all policies.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GET <admin-prefix>/idp/ldap/policy-entities?[query-params]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Query params:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	user=... -> repeatable query parameter, specifying users to query for
 | 
					
						
							|  |  |  | //	policy mapping
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	group=... -> repeatable query parameter, specifying groups to query for
 | 
					
						
							|  |  |  | //	policy mapping
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	policy=... -> repeatable query parameter, specifying policy to query for
 | 
					
						
							|  |  |  | //	user/group mapping
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // When all query parameters are omitted, returns mappings for all policies.
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListLDAPPolicyMappingEntities(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-11-08 06:35:09 +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-11-08 06:35:09 +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.QueryLDAPPolicyEntities(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) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // AttachDetachPolicyLDAP attaches or detaches policies from an LDAP entity
 | 
					
						
							|  |  |  | // (user or group).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // POST <admin-prefix>/idp/ldap/policy/{operation}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) AttachDetachPolicyLDAP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-07-14 05:52:21 +08:00
										 |  |  | 	ctx := r.Context() | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check authorization.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 05:50:16 +08:00
										 |  |  | 	objectAPI, cred := validateAdminReq(ctx, w, r, policy.UpdatePolicyAssociationAction) | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-06 13:26:02 +08:00
										 |  |  | 	// fail if ldap is not enabled
 | 
					
						
							|  |  |  | 	if !globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminLDAPNotEnabled), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate operation
 | 
					
						
							|  |  |  | 	operation := mux.Vars(r)["operation"] | 
					
						
							|  |  |  | 	if operation != "attach" && operation != "detach" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminInvalidArgument), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isAttach := operation == "attach" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate API arguments in body.
 | 
					
						
							|  |  |  | 	password := cred.SecretKey | 
					
						
							|  |  |  | 	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		adminLogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var par madmin.PolicyAssociationReq | 
					
						
							|  |  |  | 	err = json.Unmarshal(reqBytes, &par) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := par.IsValid(); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Call IAM subsystem
 | 
					
						
							| 
									
										
										
										
											2023-06-22 13:44:50 +08:00
										 |  |  | 	updatedAt, addedOrRemoved, _, err := globalIAMSys.PolicyDBUpdateLDAP(ctx, isAttach, par) | 
					
						
							| 
									
										
										
										
											2022-12-10 05:08:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	respBody := madmin.PolicyAssociationResp{ | 
					
						
							|  |  |  | 		UpdatedAt: updatedAt, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if isAttach { | 
					
						
							|  |  |  | 		respBody.PoliciesAttached = addedOrRemoved | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		respBody.PoliciesDetached = addedOrRemoved | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(respBody) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encryptedData, err := madmin.EncryptData(password, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, encryptedData) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // AddServiceAccountLDAP adds a new service account for provided LDAP username or DN
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // PUT /minio/admin/v3/idp/ldap/add-service-account
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) AddServiceAccountLDAP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2024-09-17 07:04:51 +08:00
										 |  |  | 	ctx, cred, opts, createReq, targetUser, APIError := commonAddServiceAccount(r, true) | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	if APIError.Code != "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, APIError, r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// fail if ldap is not enabled
 | 
					
						
							|  |  |  | 	if !globalIAMSys.LDAPConfig.Enabled() { | 
					
						
							| 
									
										
										
										
											2024-04-06 13:26:02 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminLDAPNotEnabled), r.URL) | 
					
						
							| 
									
										
										
										
											2024-03-26 22:51:56 +08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if we are creating svc account for request sender.
 | 
					
						
							| 
									
										
										
										
											2025-03-30 08:56:02 +08:00
										 |  |  | 	isSvcAccForRequestor := targetUser == requestorUser || targetUser == requestorParentUser | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		targetGroups []string | 
					
						
							|  |  |  | 		err          error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-25 23:50:16 +08:00
										 |  |  | 	// If we are creating svc account for request sender, ensure that targetUser
 | 
					
						
							|  |  |  | 	// is a real user (i.e. not derived credentials).
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Deny if the target user is not LDAP
 | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		foundResult, err := globalIAMSys.LDAPConfig.GetValidatedDNForUsername(targetUser) | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		if foundResult == nil { | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 			err := errors.New("Specified user does not exist on LDAP server") | 
					
						
							|  |  |  | 			APIErr := errorCodes.ToAPIErrWithErr(ErrAdminNoSuchUser, err) | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, APIErr, r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 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 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			opts.claims[k] = v | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2024-04-05 02:36:18 +08:00
										 |  |  | 		// We still need to ensure that the target user is a valid LDAP user.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// The target user may be supplied as a (short) username or a DN.
 | 
					
						
							|  |  |  | 		// However, for now, we only support using the short username.
 | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-06 13:26:02 +08:00
										 |  |  | 		isDN := globalIAMSys.LDAPConfig.ParsesAsDN(targetUser) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							|  |  |  | 			// if not found, check if DN
 | 
					
						
							| 
									
										
										
										
											2024-04-06 13:26:02 +08:00
										 |  |  | 			if strings.Contains(err.Error(), "User DN not found for:") { | 
					
						
							|  |  |  | 				if isDN { | 
					
						
							|  |  |  | 					// warn user that DNs are not allowed
 | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminLDAPExpectedLoginName, err), r.URL) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminNoSuchUser, err), r.URL) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 		targetUser = lookupResult.NormDN | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		opts.claims[ldapUser] = targetUser // DN
 | 
					
						
							| 
									
										
										
										
											2024-05-25 21:43:06 +08:00
										 |  |  | 		opts.claims[ldapActualUser] = lookupResult.ActualDN | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-04 03:58:48 +08:00
										 |  |  | 		// Check if this user or their groups have a policy applied.
 | 
					
						
							|  |  |  | 		ldapPolicies, err := globalIAMSys.PolicyDBGet(targetUser, targetGroups...) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(ldapPolicies) == 0 { | 
					
						
							|  |  |  | 			err = fmt.Errorf("No policy set for user `%s` or any of their groups: `%s`", opts.claims[ldapActualUser], strings.Join(targetGroups, "`,`")) | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminNoSuchUser, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newCred, updatedAt, err := globalIAMSys.NewServiceAccount(ctx, targetUser, targetGroups, opts) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	createResp := madmin.AddServiceAccountResp{ | 
					
						
							|  |  |  | 		Credentials: madmin.Credentials{ | 
					
						
							|  |  |  | 			AccessKey:  newCred.AccessKey, | 
					
						
							|  |  |  | 			SecretKey:  newCred.SecretKey, | 
					
						
							|  |  |  | 			Expiration: newCred.Expiration, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(createResp) | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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{ | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 			Type: madmin.SRIAMItemSvcAcc, | 
					
						
							|  |  |  | 			SvcAccChange: &madmin.SRSvcAccChange{ | 
					
						
							|  |  |  | 				Create: &madmin.SRSvcAccCreate{ | 
					
						
							|  |  |  | 					Parent:        newCred.ParentUser, | 
					
						
							|  |  |  | 					AccessKey:     newCred.AccessKey, | 
					
						
							|  |  |  | 					SecretKey:     newCred.SecretKey, | 
					
						
							|  |  |  | 					Groups:        newCred.Groups, | 
					
						
							|  |  |  | 					Name:          newCred.Name, | 
					
						
							|  |  |  | 					Description:   newCred.Description, | 
					
						
							|  |  |  | 					Claims:        opts.claims, | 
					
						
							| 
									
										
										
										
											2025-02-25 09:43:59 +08:00
										 |  |  | 					SessionPolicy: madmin.SRSessionPolicy(createReq.Policy), | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 					Status:        auth.AccountOn, | 
					
						
							|  |  |  | 					Expiration:    createReq.Expiration, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			UpdatedAt: updatedAt, | 
					
						
							|  |  |  | 		})) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListAccessKeysLDAP - GET /minio/admin/v3/idp/ldap/list-access-keys
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListAccessKeysLDAP(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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	userDN := r.Form.Get("userDN") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If listing is requested for a specific user (who is not the request
 | 
					
						
							|  |  |  | 	// sender), check that the user has permissions.
 | 
					
						
							|  |  |  | 	if userDN != "" && userDN != cred.ParentUser { | 
					
						
							|  |  |  | 		if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 			Groups:          cred.Groups, | 
					
						
							|  |  |  | 			Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							|  |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			Claims:          cred.Claims, | 
					
						
							|  |  |  | 		}) { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 			AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 			Groups:          cred.Groups, | 
					
						
							|  |  |  | 			Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							|  |  |  | 			ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 			IsOwner:         owner, | 
					
						
							|  |  |  | 			Claims:          cred.Claims, | 
					
						
							|  |  |  | 			DenyOnly:        true, | 
					
						
							|  |  |  | 		}) { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		userDN = cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			userDN = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 	dnResult, err := globalIAMSys.LDAPConfig.GetValidatedDNForUsername(userDN) | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2024-04-05 02:36:18 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 	if dnResult == nil { | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errNoSuchUser), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 	targetAccount := dnResult.NormDN | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	listType := r.Form.Get("listType") | 
					
						
							|  |  |  | 	if listType != "sts-only" && listType != "svcacc-only" && listType != "" { | 
					
						
							|  |  |  | 		// default to both
 | 
					
						
							|  |  |  | 		listType = "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var serviceAccounts []auth.Credentials | 
					
						
							|  |  |  | 	var stsKeys []auth.Credentials | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if listType == "" || listType == "sts-only" { | 
					
						
							|  |  |  | 		stsKeys, err = globalIAMSys.ListSTSAccounts(ctx, targetAccount) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if listType == "" || listType == "svcacc-only" { | 
					
						
							|  |  |  | 		serviceAccounts, err = globalIAMSys.ListServiceAccounts(ctx, targetAccount) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var serviceAccountList []madmin.ServiceAccountInfo | 
					
						
							|  |  |  | 	var stsKeyList []madmin.ServiceAccountInfo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, svc := range serviceAccounts { | 
					
						
							|  |  |  | 		expiryTime := svc.Expiration | 
					
						
							|  |  |  | 		serviceAccountList = append(serviceAccountList, madmin.ServiceAccountInfo{ | 
					
						
							| 
									
										
										
										
											2025-08-08 10:46:04 +08:00
										 |  |  | 			AccessKey:   svc.AccessKey, | 
					
						
							|  |  |  | 			Expiration:  &expiryTime, | 
					
						
							|  |  |  | 			Name:        svc.Name, | 
					
						
							|  |  |  | 			Description: svc.Description, | 
					
						
							| 
									
										
										
										
											2023-12-16 05:00:43 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, sts := range stsKeys { | 
					
						
							|  |  |  | 		expiryTime := sts.Expiration | 
					
						
							|  |  |  | 		stsKeyList = append(stsKeyList, madmin.ServiceAccountInfo{ | 
					
						
							|  |  |  | 			AccessKey:  sts.AccessKey, | 
					
						
							|  |  |  | 			Expiration: &expiryTime, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	listResp := madmin.ListAccessKeysLDAPResp{ | 
					
						
							|  |  |  | 		ServiceAccounts: serviceAccountList, | 
					
						
							|  |  |  | 		STSKeys:         stsKeyList, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ListAccessKeysLDAPBulk - GET /minio/admin/v3/idp/ldap/list-access-keys-bulk
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListAccessKeysLDAPBulk(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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dnList := r.Form["userDNs"] | 
					
						
							|  |  |  | 	isAll := r.Form.Get("all") == "true" | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 	selfOnly := !isAll && len(dnList) == 0 | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if isAll && len(dnList) > 0 { | 
					
						
							|  |  |  | 		// This should be checked on client side, so return generic error
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Empty DN 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(dnList) == 1 { | 
					
						
							|  |  |  | 		var dn string | 
					
						
							|  |  |  | 		foundResult, err := globalIAMSys.LDAPConfig.GetValidatedDNForUsername(dnList[0]) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			dn = foundResult.NormDN | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if dn == cred.ParentUser || dnList[0] == cred.ParentUser { | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 			selfOnly = true | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !globalIAMSys.IsAllowed(policy.Args{ | 
					
						
							|  |  |  | 		AccountName:     cred.AccessKey, | 
					
						
							|  |  |  | 		Groups:          cred.Groups, | 
					
						
							|  |  |  | 		Action:          policy.ListServiceAccountsAdminAction, | 
					
						
							|  |  |  | 		ConditionValues: getConditionValues(r, "", cred), | 
					
						
							|  |  |  | 		IsOwner:         owner, | 
					
						
							|  |  |  | 		Claims:          cred.Claims, | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 		DenyOnly:        selfOnly, | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 	}) { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 	if selfOnly && len(dnList) == 0 { | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 		selfDN := cred.AccessKey | 
					
						
							|  |  |  | 		if cred.ParentUser != "" { | 
					
						
							|  |  |  | 			selfDN = cred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dnList = append(dnList, selfDN) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 	var ldapUserList []string | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 	if isAll { | 
					
						
							|  |  |  | 		ldapUsers, err := globalIAMSys.ListLDAPUsers(ctx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for user := range ldapUsers { | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 			ldapUserList = append(ldapUserList, user) | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		for _, userDN := range dnList { | 
					
						
							|  |  |  | 			// Validate the userDN
 | 
					
						
							|  |  |  | 			foundResult, err := globalIAMSys.LDAPConfig.GetValidatedDNForUsername(userDN) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if foundResult == nil { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 			ldapUserList = append(ldapUserList, foundResult.NormDN) | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 	accessKeyMap := make(map[string]madmin.ListAccessKeysLDAPResp) | 
					
						
							|  |  |  | 	for _, internalDN := range ldapUserList { | 
					
						
							|  |  |  | 		externalDN := globalIAMSys.LDAPConfig.DecodeDN(internalDN) | 
					
						
							|  |  |  | 		accessKeys := madmin.ListAccessKeysLDAPResp{} | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 		if listSTSKeys { | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 			stsKeys, err := globalIAMSys.ListSTSAccounts(ctx, internalDN) | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 			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, | 
					
						
							| 
									
										
										
										
											2024-09-21 19:35:40 +08:00
										 |  |  | 					Expiration: &sts.Expiration, | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// if only STS keys, skip if user has no STS keys
 | 
					
						
							|  |  |  | 			if !listServiceAccounts && len(stsKeys) == 0 { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if listServiceAccounts { | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 			serviceAccounts, err := globalIAMSys.ListServiceAccounts(ctx, internalDN) | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, svc := range serviceAccounts { | 
					
						
							|  |  |  | 				accessKeys.ServiceAccounts = append(accessKeys.ServiceAccounts, madmin.ServiceAccountInfo{ | 
					
						
							| 
									
										
										
										
											2025-08-08 10:46:04 +08:00
										 |  |  | 					AccessKey:   svc.AccessKey, | 
					
						
							|  |  |  | 					Expiration:  &svc.Expiration, | 
					
						
							|  |  |  | 					Name:        svc.Name, | 
					
						
							|  |  |  | 					Description: svc.Description, | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// if only service accounts, skip if user has no service accounts
 | 
					
						
							|  |  |  | 			if !listSTSKeys && len(serviceAccounts) == 0 { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-07-12 09:04:53 +08:00
										 |  |  | 		accessKeyMap[externalDN] = accessKeys | 
					
						
							| 
									
										
										
										
											2024-06-26 05:21:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | } |