diff --git a/cmd/admin-handlers-idp-openid.go b/cmd/admin-handlers-idp-openid.go new file mode 100644 index 000000000..78e537d48 --- /dev/null +++ b/cmd/admin-handlers-idp-openid.go @@ -0,0 +1,246 @@ +// Copyright (c) 2015-2025 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 . + +package cmd + +import ( + "encoding/json" + "errors" + "net/http" + "sort" + + "github.com/minio/madmin-go/v3" + "github.com/minio/minio-go/v7/pkg/set" + "github.com/minio/pkg/v3/policy" +) + +const dummyRoleARN = "dummy-internal" + +// ListAccessKeysOpenIDBulk - GET /minio/admin/v3/idp/openid/list-access-keys-bulk +func (a adminAPIHandlers) ListAccessKeysOpenIDBulk(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 + } + + if !globalIAMSys.OpenIDConfig.Enabled { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminOpenIDNotEnabled), r.URL) + return + } + + userList := r.Form["users"] + isAll := r.Form.Get("all") == "true" + selfOnly := !isAll && len(userList) == 0 + cfgName := r.Form.Get("configName") + allConfigs := r.Form.Get("allConfigs") == "true" + if cfgName == "" && !allConfigs { + cfgName = madmin.Default + } + + if isAll && len(userList) > 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(userList) == 1 && userList[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(userList) == 0 { + selfDN := cred.AccessKey + if cred.ParentUser != "" { + selfDN = cred.ParentUser + } + userList = append(userList, selfDN) + } + + 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 + } + + s := globalServerConfig.Clone() + roleArnMap := make(map[string]string) + // Map of configs to a map of users to their access keys + cfgToUsersMap := make(map[string]map[string]madmin.OpenIDUserAccessKeys) + configs, err := globalIAMSys.OpenIDConfig.GetConfigList(s) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + for _, config := range configs { + if !allConfigs && cfgName != config.Name { + continue + } + arn := dummyRoleARN + if config.RoleARN != "" { + arn = config.RoleARN + } + roleArnMap[arn] = config.Name + newResp := make(map[string]madmin.OpenIDUserAccessKeys) + cfgToUsersMap[config.Name] = newResp + } + if len(roleArnMap) == 0 { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminNoSuchConfigTarget), r.URL) + return + } + + userSet := set.CreateStringSet(userList...) + accessKeys, err := globalIAMSys.ListAllAccessKeys(ctx) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + for _, accessKey := range accessKeys { + // Filter out any disqualifying access keys + _, ok := accessKey.Claims[subClaim] + if !ok { + continue // OpenID access keys must have a sub claim + } + if (!listSTSKeys && !accessKey.IsServiceAccount()) || (!listServiceAccounts && accessKey.IsServiceAccount()) { + continue // skip if not the type we want + } + arn, ok := accessKey.Claims[roleArnClaim].(string) + if !ok { + if _, ok := accessKey.Claims[iamPolicyClaimNameOpenID()]; !ok { + continue // skip if no roleArn and no policy claim + } + } + matchingCfgName, ok := roleArnMap[arn] + if !ok { + continue // skip if not part of the target config + } + var id string + if idClaim := globalIAMSys.OpenIDConfig.GetUserIDClaim(matchingCfgName); idClaim != "" { + id, _ = accessKey.Claims[idClaim].(string) + } + if !userSet.IsEmpty() && !userSet.Contains(accessKey.ParentUser) && !userSet.Contains(id) { + continue // skip if not in the user list + } + openIDUserAccessKeys, ok := cfgToUsersMap[matchingCfgName][accessKey.ParentUser] + + // Add new user to map if not already present + if !ok { + var readableClaim string + if rc := globalIAMSys.OpenIDConfig.GetUserReadableClaim(matchingCfgName); rc != "" { + readableClaim, _ = accessKey.Claims[rc].(string) + } + openIDUserAccessKeys = madmin.OpenIDUserAccessKeys{ + MinioAccessKey: accessKey.ParentUser, + ID: id, + ReadableName: readableClaim, + } + } + svcAccInfo := madmin.ServiceAccountInfo{ + AccessKey: accessKey.AccessKey, + Expiration: &accessKey.Expiration, + } + if accessKey.IsServiceAccount() { + openIDUserAccessKeys.ServiceAccounts = append(openIDUserAccessKeys.ServiceAccounts, svcAccInfo) + } else { + openIDUserAccessKeys.STSKeys = append(openIDUserAccessKeys.STSKeys, svcAccInfo) + } + cfgToUsersMap[matchingCfgName][accessKey.ParentUser] = openIDUserAccessKeys + } + + // Convert map to slice and sort + resp := make([]madmin.ListAccessKeysOpenIDResp, 0, len(cfgToUsersMap)) + for cfgName, usersMap := range cfgToUsersMap { + users := make([]madmin.OpenIDUserAccessKeys, 0, len(usersMap)) + for _, user := range usersMap { + users = append(users, user) + } + sort.Slice(users, func(i, j int) bool { + return users[i].MinioAccessKey < users[j].MinioAccessKey + }) + resp = append(resp, madmin.ListAccessKeysOpenIDResp{ + ConfigName: cfgName, + Users: users, + }) + } + sort.Slice(resp, func(i, j int) bool { + return resp[i].ConfigName < resp[j].ConfigName + }) + + data, err := json.Marshal(resp) + 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) +} diff --git a/cmd/admin-handlers-users.go b/cmd/admin-handlers-users.go index 8c0c74422..43f3d36c1 100644 --- a/cmd/admin-handlers-users.go +++ b/cmd/admin-handlers-users.go @@ -2068,6 +2068,149 @@ func (a adminAPIHandlers) RevokeTokens(w http.ResponseWriter, r *http.Request) { writeSuccessNoContent(w) } +// InfoAccessKey - GET /minio/admin/v3/info-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) +} + const ( allPoliciesFile = "policies.json" allUsersFile = "users.json" diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 4e5ac8dba..2527b0615 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -246,6 +246,7 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) { // Access key (service account/STS) operations adminRouter.Methods(http.MethodGet).Path(adminVersion+"/list-access-keys-bulk").HandlerFunc(adminMiddleware(adminAPI.ListAccessKeysBulk)).Queries("listType", "{listType:.*}") + adminRouter.Methods(http.MethodGet).Path(adminVersion+"/info-access-key").HandlerFunc(adminMiddleware(adminAPI.InfoAccessKey)).Queries("accessKey", "{accessKey:.*}") // Info policy IAM latest adminRouter.Methods(http.MethodGet).Path(adminVersion+"/info-canned-policy").HandlerFunc(adminMiddleware(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}") @@ -312,6 +313,11 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) { // LDAP IAM operations adminRouter.Methods(http.MethodGet).Path(adminVersion + "/idp/ldap/policy-entities").HandlerFunc(adminMiddleware(adminAPI.ListLDAPPolicyMappingEntities)) adminRouter.Methods(http.MethodPost).Path(adminVersion + "/idp/ldap/policy/{operation}").HandlerFunc(adminMiddleware(adminAPI.AttachDetachPolicyLDAP)) + + // OpenID specific service accounts ops + adminRouter.Methods(http.MethodGet).Path(adminVersion+"/idp/openid/list-access-keys-bulk"). + HandlerFunc(adminMiddleware(adminAPI.ListAccessKeysOpenIDBulk)).Queries("listType", "{listType:.*}") + // -- END IAM APIs -- // GetBucketQuotaConfig diff --git a/cmd/api-errors.go b/cmd/api-errors.go index bc108814a..6ccd5fab2 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -215,6 +215,8 @@ const ( ErrExcessData ErrPolicyInvalidName ErrNoTokenRevokeType + ErrAdminOpenIDNotEnabled + ErrAdminNoSuchAccessKey // Add new error codes here. // SSE-S3/SSE-KMS related API errors @@ -568,6 +570,11 @@ var errorCodes = errorCodeMap{ Description: "Policy name may not contain comma", HTTPStatusCode: http.StatusBadRequest, }, + ErrAdminOpenIDNotEnabled: { + Code: "OpenIDNotEnabled", + Description: "No enabled OpenID Connect identity providers", + HTTPStatusCode: http.StatusBadRequest, + }, ErrPolicyTooLarge: { Code: "PolicyTooLarge", Description: "Policy exceeds the maximum allowed document size.", @@ -1270,6 +1277,11 @@ var errorCodes = errorCodeMap{ Description: "No token revoke type specified and one could not be inferred from the request", HTTPStatusCode: http.StatusBadRequest, }, + ErrAdminNoSuchAccessKey: { + Code: "XMinioAdminNoSuchAccessKey", + Description: "The specified access key does not exist.", + HTTPStatusCode: http.StatusNotFound, + }, // S3 extensions. ErrContentSHA256Mismatch: { @@ -2167,6 +2179,8 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) { apiErr = ErrAdminNoSuchUserLDAPWarn case errNoSuchServiceAccount: apiErr = ErrAdminServiceAccountNotFound + case errNoSuchAccessKey: + apiErr = ErrAdminNoSuchAccessKey case errNoSuchGroup: apiErr = ErrAdminNoSuchGroup case errGroupNotEmpty: diff --git a/cmd/apierrorcode_string.go b/cmd/apierrorcode_string.go index 2953a8616..d9973d887 100644 --- a/cmd/apierrorcode_string.go +++ b/cmd/apierrorcode_string.go @@ -141,208 +141,210 @@ func _() { _ = x[ErrExcessData-130] _ = x[ErrPolicyInvalidName-131] _ = x[ErrNoTokenRevokeType-132] - _ = x[ErrInvalidEncryptionMethod-133] - _ = x[ErrInvalidEncryptionKeyID-134] - _ = x[ErrInsecureSSECustomerRequest-135] - _ = x[ErrSSEMultipartEncrypted-136] - _ = x[ErrSSEEncryptedObject-137] - _ = x[ErrInvalidEncryptionParameters-138] - _ = x[ErrInvalidEncryptionParametersSSEC-139] - _ = x[ErrInvalidSSECustomerAlgorithm-140] - _ = x[ErrInvalidSSECustomerKey-141] - _ = x[ErrMissingSSECustomerKey-142] - _ = x[ErrMissingSSECustomerKeyMD5-143] - _ = x[ErrSSECustomerKeyMD5Mismatch-144] - _ = x[ErrInvalidSSECustomerParameters-145] - _ = x[ErrIncompatibleEncryptionMethod-146] - _ = x[ErrKMSNotConfigured-147] - _ = x[ErrKMSKeyNotFoundException-148] - _ = x[ErrKMSDefaultKeyAlreadyConfigured-149] - _ = x[ErrNoAccessKey-150] - _ = x[ErrInvalidToken-151] - _ = x[ErrEventNotification-152] - _ = x[ErrARNNotification-153] - _ = x[ErrRegionNotification-154] - _ = x[ErrOverlappingFilterNotification-155] - _ = x[ErrFilterNameInvalid-156] - _ = x[ErrFilterNamePrefix-157] - _ = x[ErrFilterNameSuffix-158] - _ = x[ErrFilterValueInvalid-159] - _ = x[ErrOverlappingConfigs-160] - _ = x[ErrUnsupportedNotification-161] - _ = x[ErrContentSHA256Mismatch-162] - _ = x[ErrContentChecksumMismatch-163] - _ = x[ErrStorageFull-164] - _ = x[ErrRequestBodyParse-165] - _ = x[ErrObjectExistsAsDirectory-166] - _ = x[ErrInvalidObjectName-167] - _ = x[ErrInvalidObjectNamePrefixSlash-168] - _ = x[ErrInvalidResourceName-169] - _ = x[ErrInvalidLifecycleQueryParameter-170] - _ = x[ErrServerNotInitialized-171] - _ = x[ErrBucketMetadataNotInitialized-172] - _ = x[ErrRequestTimedout-173] - _ = x[ErrClientDisconnected-174] - _ = x[ErrTooManyRequests-175] - _ = x[ErrInvalidRequest-176] - _ = x[ErrTransitionStorageClassNotFoundError-177] - _ = x[ErrInvalidStorageClass-178] - _ = x[ErrBackendDown-179] - _ = x[ErrMalformedJSON-180] - _ = x[ErrAdminNoSuchUser-181] - _ = x[ErrAdminNoSuchUserLDAPWarn-182] - _ = x[ErrAdminLDAPExpectedLoginName-183] - _ = x[ErrAdminNoSuchGroup-184] - _ = x[ErrAdminGroupNotEmpty-185] - _ = x[ErrAdminGroupDisabled-186] - _ = x[ErrAdminInvalidGroupName-187] - _ = x[ErrAdminNoSuchJob-188] - _ = x[ErrAdminNoSuchPolicy-189] - _ = x[ErrAdminPolicyChangeAlreadyApplied-190] - _ = x[ErrAdminInvalidArgument-191] - _ = x[ErrAdminInvalidAccessKey-192] - _ = x[ErrAdminInvalidSecretKey-193] - _ = x[ErrAdminConfigNoQuorum-194] - _ = x[ErrAdminConfigTooLarge-195] - _ = x[ErrAdminConfigBadJSON-196] - _ = x[ErrAdminNoSuchConfigTarget-197] - _ = x[ErrAdminConfigEnvOverridden-198] - _ = x[ErrAdminConfigDuplicateKeys-199] - _ = x[ErrAdminConfigInvalidIDPType-200] - _ = x[ErrAdminConfigLDAPNonDefaultConfigName-201] - _ = x[ErrAdminConfigLDAPValidation-202] - _ = x[ErrAdminConfigIDPCfgNameAlreadyExists-203] - _ = x[ErrAdminConfigIDPCfgNameDoesNotExist-204] - _ = x[ErrInsecureClientRequest-205] - _ = x[ErrObjectTampered-206] - _ = x[ErrAdminLDAPNotEnabled-207] - _ = x[ErrSiteReplicationInvalidRequest-208] - _ = x[ErrSiteReplicationPeerResp-209] - _ = x[ErrSiteReplicationBackendIssue-210] - _ = x[ErrSiteReplicationServiceAccountError-211] - _ = x[ErrSiteReplicationBucketConfigError-212] - _ = x[ErrSiteReplicationBucketMetaError-213] - _ = x[ErrSiteReplicationIAMError-214] - _ = x[ErrSiteReplicationConfigMissing-215] - _ = x[ErrSiteReplicationIAMConfigMismatch-216] - _ = x[ErrAdminRebalanceAlreadyStarted-217] - _ = x[ErrAdminRebalanceNotStarted-218] - _ = x[ErrAdminBucketQuotaExceeded-219] - _ = x[ErrAdminNoSuchQuotaConfiguration-220] - _ = x[ErrHealNotImplemented-221] - _ = x[ErrHealNoSuchProcess-222] - _ = x[ErrHealInvalidClientToken-223] - _ = x[ErrHealMissingBucket-224] - _ = x[ErrHealAlreadyRunning-225] - _ = x[ErrHealOverlappingPaths-226] - _ = x[ErrIncorrectContinuationToken-227] - _ = x[ErrEmptyRequestBody-228] - _ = x[ErrUnsupportedFunction-229] - _ = x[ErrInvalidExpressionType-230] - _ = x[ErrBusy-231] - _ = x[ErrUnauthorizedAccess-232] - _ = x[ErrExpressionTooLong-233] - _ = x[ErrIllegalSQLFunctionArgument-234] - _ = x[ErrInvalidKeyPath-235] - _ = x[ErrInvalidCompressionFormat-236] - _ = x[ErrInvalidFileHeaderInfo-237] - _ = x[ErrInvalidJSONType-238] - _ = x[ErrInvalidQuoteFields-239] - _ = x[ErrInvalidRequestParameter-240] - _ = x[ErrInvalidDataType-241] - _ = x[ErrInvalidTextEncoding-242] - _ = x[ErrInvalidDataSource-243] - _ = x[ErrInvalidTableAlias-244] - _ = x[ErrMissingRequiredParameter-245] - _ = x[ErrObjectSerializationConflict-246] - _ = x[ErrUnsupportedSQLOperation-247] - _ = x[ErrUnsupportedSQLStructure-248] - _ = x[ErrUnsupportedSyntax-249] - _ = x[ErrUnsupportedRangeHeader-250] - _ = x[ErrLexerInvalidChar-251] - _ = x[ErrLexerInvalidOperator-252] - _ = x[ErrLexerInvalidLiteral-253] - _ = x[ErrLexerInvalidIONLiteral-254] - _ = x[ErrParseExpectedDatePart-255] - _ = x[ErrParseExpectedKeyword-256] - _ = x[ErrParseExpectedTokenType-257] - _ = x[ErrParseExpected2TokenTypes-258] - _ = x[ErrParseExpectedNumber-259] - _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-260] - _ = x[ErrParseExpectedTypeName-261] - _ = x[ErrParseExpectedWhenClause-262] - _ = x[ErrParseUnsupportedToken-263] - _ = x[ErrParseUnsupportedLiteralsGroupBy-264] - _ = x[ErrParseExpectedMember-265] - _ = x[ErrParseUnsupportedSelect-266] - _ = x[ErrParseUnsupportedCase-267] - _ = x[ErrParseUnsupportedCaseClause-268] - _ = x[ErrParseUnsupportedAlias-269] - _ = x[ErrParseUnsupportedSyntax-270] - _ = x[ErrParseUnknownOperator-271] - _ = x[ErrParseMissingIdentAfterAt-272] - _ = x[ErrParseUnexpectedOperator-273] - _ = x[ErrParseUnexpectedTerm-274] - _ = x[ErrParseUnexpectedToken-275] - _ = x[ErrParseUnexpectedKeyword-276] - _ = x[ErrParseExpectedExpression-277] - _ = x[ErrParseExpectedLeftParenAfterCast-278] - _ = x[ErrParseExpectedLeftParenValueConstructor-279] - _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-280] - _ = x[ErrParseExpectedArgumentDelimiter-281] - _ = x[ErrParseCastArity-282] - _ = x[ErrParseInvalidTypeParam-283] - _ = x[ErrParseEmptySelect-284] - _ = x[ErrParseSelectMissingFrom-285] - _ = x[ErrParseExpectedIdentForGroupName-286] - _ = x[ErrParseExpectedIdentForAlias-287] - _ = x[ErrParseUnsupportedCallWithStar-288] - _ = x[ErrParseNonUnaryAggregateFunctionCall-289] - _ = x[ErrParseMalformedJoin-290] - _ = x[ErrParseExpectedIdentForAt-291] - _ = x[ErrParseAsteriskIsNotAloneInSelectList-292] - _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-293] - _ = x[ErrParseInvalidContextForWildcardInSelectList-294] - _ = x[ErrIncorrectSQLFunctionArgumentType-295] - _ = x[ErrValueParseFailure-296] - _ = x[ErrEvaluatorInvalidArguments-297] - _ = x[ErrIntegerOverflow-298] - _ = x[ErrLikeInvalidInputs-299] - _ = x[ErrCastFailed-300] - _ = x[ErrInvalidCast-301] - _ = x[ErrEvaluatorInvalidTimestampFormatPattern-302] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-303] - _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-304] - _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-305] - _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-306] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-307] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-308] - _ = x[ErrEvaluatorBindingDoesNotExist-309] - _ = x[ErrMissingHeaders-310] - _ = x[ErrInvalidColumnIndex-311] - _ = x[ErrAdminConfigNotificationTargetsFailed-312] - _ = x[ErrAdminProfilerNotEnabled-313] - _ = x[ErrInvalidDecompressedSize-314] - _ = x[ErrAddUserInvalidArgument-315] - _ = x[ErrAddUserValidUTF-316] - _ = x[ErrAdminResourceInvalidArgument-317] - _ = x[ErrAdminAccountNotEligible-318] - _ = x[ErrAccountNotEligible-319] - _ = x[ErrAdminServiceAccountNotFound-320] - _ = x[ErrPostPolicyConditionInvalidFormat-321] - _ = x[ErrInvalidChecksum-322] - _ = x[ErrLambdaARNInvalid-323] - _ = x[ErrLambdaARNNotFound-324] - _ = x[ErrInvalidAttributeName-325] - _ = x[ErrAdminNoAccessKey-326] - _ = x[ErrAdminNoSecretKey-327] - _ = x[ErrIAMNotInitialized-328] - _ = x[apiErrCodeEnd-329] + _ = x[ErrAdminOpenIDNotEnabled-133] + _ = x[ErrAdminNoSuchAccessKey-134] + _ = x[ErrInvalidEncryptionMethod-135] + _ = x[ErrInvalidEncryptionKeyID-136] + _ = x[ErrInsecureSSECustomerRequest-137] + _ = x[ErrSSEMultipartEncrypted-138] + _ = x[ErrSSEEncryptedObject-139] + _ = x[ErrInvalidEncryptionParameters-140] + _ = x[ErrInvalidEncryptionParametersSSEC-141] + _ = x[ErrInvalidSSECustomerAlgorithm-142] + _ = x[ErrInvalidSSECustomerKey-143] + _ = x[ErrMissingSSECustomerKey-144] + _ = x[ErrMissingSSECustomerKeyMD5-145] + _ = x[ErrSSECustomerKeyMD5Mismatch-146] + _ = x[ErrInvalidSSECustomerParameters-147] + _ = x[ErrIncompatibleEncryptionMethod-148] + _ = x[ErrKMSNotConfigured-149] + _ = x[ErrKMSKeyNotFoundException-150] + _ = x[ErrKMSDefaultKeyAlreadyConfigured-151] + _ = x[ErrNoAccessKey-152] + _ = x[ErrInvalidToken-153] + _ = x[ErrEventNotification-154] + _ = x[ErrARNNotification-155] + _ = x[ErrRegionNotification-156] + _ = x[ErrOverlappingFilterNotification-157] + _ = x[ErrFilterNameInvalid-158] + _ = x[ErrFilterNamePrefix-159] + _ = x[ErrFilterNameSuffix-160] + _ = x[ErrFilterValueInvalid-161] + _ = x[ErrOverlappingConfigs-162] + _ = x[ErrUnsupportedNotification-163] + _ = x[ErrContentSHA256Mismatch-164] + _ = x[ErrContentChecksumMismatch-165] + _ = x[ErrStorageFull-166] + _ = x[ErrRequestBodyParse-167] + _ = x[ErrObjectExistsAsDirectory-168] + _ = x[ErrInvalidObjectName-169] + _ = x[ErrInvalidObjectNamePrefixSlash-170] + _ = x[ErrInvalidResourceName-171] + _ = x[ErrInvalidLifecycleQueryParameter-172] + _ = x[ErrServerNotInitialized-173] + _ = x[ErrBucketMetadataNotInitialized-174] + _ = x[ErrRequestTimedout-175] + _ = x[ErrClientDisconnected-176] + _ = x[ErrTooManyRequests-177] + _ = x[ErrInvalidRequest-178] + _ = x[ErrTransitionStorageClassNotFoundError-179] + _ = x[ErrInvalidStorageClass-180] + _ = x[ErrBackendDown-181] + _ = x[ErrMalformedJSON-182] + _ = x[ErrAdminNoSuchUser-183] + _ = x[ErrAdminNoSuchUserLDAPWarn-184] + _ = x[ErrAdminLDAPExpectedLoginName-185] + _ = x[ErrAdminNoSuchGroup-186] + _ = x[ErrAdminGroupNotEmpty-187] + _ = x[ErrAdminGroupDisabled-188] + _ = x[ErrAdminInvalidGroupName-189] + _ = x[ErrAdminNoSuchJob-190] + _ = x[ErrAdminNoSuchPolicy-191] + _ = x[ErrAdminPolicyChangeAlreadyApplied-192] + _ = x[ErrAdminInvalidArgument-193] + _ = x[ErrAdminInvalidAccessKey-194] + _ = x[ErrAdminInvalidSecretKey-195] + _ = x[ErrAdminConfigNoQuorum-196] + _ = x[ErrAdminConfigTooLarge-197] + _ = x[ErrAdminConfigBadJSON-198] + _ = x[ErrAdminNoSuchConfigTarget-199] + _ = x[ErrAdminConfigEnvOverridden-200] + _ = x[ErrAdminConfigDuplicateKeys-201] + _ = x[ErrAdminConfigInvalidIDPType-202] + _ = x[ErrAdminConfigLDAPNonDefaultConfigName-203] + _ = x[ErrAdminConfigLDAPValidation-204] + _ = x[ErrAdminConfigIDPCfgNameAlreadyExists-205] + _ = x[ErrAdminConfigIDPCfgNameDoesNotExist-206] + _ = x[ErrInsecureClientRequest-207] + _ = x[ErrObjectTampered-208] + _ = x[ErrAdminLDAPNotEnabled-209] + _ = x[ErrSiteReplicationInvalidRequest-210] + _ = x[ErrSiteReplicationPeerResp-211] + _ = x[ErrSiteReplicationBackendIssue-212] + _ = x[ErrSiteReplicationServiceAccountError-213] + _ = x[ErrSiteReplicationBucketConfigError-214] + _ = x[ErrSiteReplicationBucketMetaError-215] + _ = x[ErrSiteReplicationIAMError-216] + _ = x[ErrSiteReplicationConfigMissing-217] + _ = x[ErrSiteReplicationIAMConfigMismatch-218] + _ = x[ErrAdminRebalanceAlreadyStarted-219] + _ = x[ErrAdminRebalanceNotStarted-220] + _ = x[ErrAdminBucketQuotaExceeded-221] + _ = x[ErrAdminNoSuchQuotaConfiguration-222] + _ = x[ErrHealNotImplemented-223] + _ = x[ErrHealNoSuchProcess-224] + _ = x[ErrHealInvalidClientToken-225] + _ = x[ErrHealMissingBucket-226] + _ = x[ErrHealAlreadyRunning-227] + _ = x[ErrHealOverlappingPaths-228] + _ = x[ErrIncorrectContinuationToken-229] + _ = x[ErrEmptyRequestBody-230] + _ = x[ErrUnsupportedFunction-231] + _ = x[ErrInvalidExpressionType-232] + _ = x[ErrBusy-233] + _ = x[ErrUnauthorizedAccess-234] + _ = x[ErrExpressionTooLong-235] + _ = x[ErrIllegalSQLFunctionArgument-236] + _ = x[ErrInvalidKeyPath-237] + _ = x[ErrInvalidCompressionFormat-238] + _ = x[ErrInvalidFileHeaderInfo-239] + _ = x[ErrInvalidJSONType-240] + _ = x[ErrInvalidQuoteFields-241] + _ = x[ErrInvalidRequestParameter-242] + _ = x[ErrInvalidDataType-243] + _ = x[ErrInvalidTextEncoding-244] + _ = x[ErrInvalidDataSource-245] + _ = x[ErrInvalidTableAlias-246] + _ = x[ErrMissingRequiredParameter-247] + _ = x[ErrObjectSerializationConflict-248] + _ = x[ErrUnsupportedSQLOperation-249] + _ = x[ErrUnsupportedSQLStructure-250] + _ = x[ErrUnsupportedSyntax-251] + _ = x[ErrUnsupportedRangeHeader-252] + _ = x[ErrLexerInvalidChar-253] + _ = x[ErrLexerInvalidOperator-254] + _ = x[ErrLexerInvalidLiteral-255] + _ = x[ErrLexerInvalidIONLiteral-256] + _ = x[ErrParseExpectedDatePart-257] + _ = x[ErrParseExpectedKeyword-258] + _ = x[ErrParseExpectedTokenType-259] + _ = x[ErrParseExpected2TokenTypes-260] + _ = x[ErrParseExpectedNumber-261] + _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-262] + _ = x[ErrParseExpectedTypeName-263] + _ = x[ErrParseExpectedWhenClause-264] + _ = x[ErrParseUnsupportedToken-265] + _ = x[ErrParseUnsupportedLiteralsGroupBy-266] + _ = x[ErrParseExpectedMember-267] + _ = x[ErrParseUnsupportedSelect-268] + _ = x[ErrParseUnsupportedCase-269] + _ = x[ErrParseUnsupportedCaseClause-270] + _ = x[ErrParseUnsupportedAlias-271] + _ = x[ErrParseUnsupportedSyntax-272] + _ = x[ErrParseUnknownOperator-273] + _ = x[ErrParseMissingIdentAfterAt-274] + _ = x[ErrParseUnexpectedOperator-275] + _ = x[ErrParseUnexpectedTerm-276] + _ = x[ErrParseUnexpectedToken-277] + _ = x[ErrParseUnexpectedKeyword-278] + _ = x[ErrParseExpectedExpression-279] + _ = x[ErrParseExpectedLeftParenAfterCast-280] + _ = x[ErrParseExpectedLeftParenValueConstructor-281] + _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-282] + _ = x[ErrParseExpectedArgumentDelimiter-283] + _ = x[ErrParseCastArity-284] + _ = x[ErrParseInvalidTypeParam-285] + _ = x[ErrParseEmptySelect-286] + _ = x[ErrParseSelectMissingFrom-287] + _ = x[ErrParseExpectedIdentForGroupName-288] + _ = x[ErrParseExpectedIdentForAlias-289] + _ = x[ErrParseUnsupportedCallWithStar-290] + _ = x[ErrParseNonUnaryAggregateFunctionCall-291] + _ = x[ErrParseMalformedJoin-292] + _ = x[ErrParseExpectedIdentForAt-293] + _ = x[ErrParseAsteriskIsNotAloneInSelectList-294] + _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-295] + _ = x[ErrParseInvalidContextForWildcardInSelectList-296] + _ = x[ErrIncorrectSQLFunctionArgumentType-297] + _ = x[ErrValueParseFailure-298] + _ = x[ErrEvaluatorInvalidArguments-299] + _ = x[ErrIntegerOverflow-300] + _ = x[ErrLikeInvalidInputs-301] + _ = x[ErrCastFailed-302] + _ = x[ErrInvalidCast-303] + _ = x[ErrEvaluatorInvalidTimestampFormatPattern-304] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-305] + _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-306] + _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-307] + _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-308] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-309] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-310] + _ = x[ErrEvaluatorBindingDoesNotExist-311] + _ = x[ErrMissingHeaders-312] + _ = x[ErrInvalidColumnIndex-313] + _ = x[ErrAdminConfigNotificationTargetsFailed-314] + _ = x[ErrAdminProfilerNotEnabled-315] + _ = x[ErrInvalidDecompressedSize-316] + _ = x[ErrAddUserInvalidArgument-317] + _ = x[ErrAddUserValidUTF-318] + _ = x[ErrAdminResourceInvalidArgument-319] + _ = x[ErrAdminAccountNotEligible-320] + _ = x[ErrAccountNotEligible-321] + _ = x[ErrAdminServiceAccountNotFound-322] + _ = x[ErrPostPolicyConditionInvalidFormat-323] + _ = x[ErrInvalidChecksum-324] + _ = x[ErrLambdaARNInvalid-325] + _ = x[ErrLambdaARNNotFound-326] + _ = x[ErrInvalidAttributeName-327] + _ = x[ErrAdminNoAccessKey-328] + _ = x[ErrAdminNoSecretKey-329] + _ = x[ErrIAMNotInitialized-330] + _ = x[apiErrCodeEnd-331] } -const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidArgumentInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorRemoteTargetDenyAddErrorReplicationNoExistingObjectsReplicationValidationErrorReplicationPermissionCheckErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderMissingPartAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledPolicyInvalidVersionMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataUnsupportedHostHeaderMaximumExpiresSlowDownReadSlowDownWriteMaxVersionsExceededInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectivePolicyAlreadyAttachedPolicyNotAttachedExcessDataPolicyInvalidNameNoTokenRevokeTypeInvalidEncryptionMethodInvalidEncryptionKeyIDInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidEncryptionParametersSSECInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionKMSDefaultKeyAlreadyConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchContentChecksumMismatchStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameInvalidLifecycleQueryParameterServerNotInitializedBucketMetadataNotInitializedRequestTimedoutClientDisconnectedTooManyRequestsInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchUserLDAPWarnAdminLDAPExpectedLoginNameAdminNoSuchGroupAdminGroupNotEmptyAdminGroupDisabledAdminInvalidGroupNameAdminNoSuchJobAdminNoSuchPolicyAdminPolicyChangeAlreadyAppliedAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminNoSuchConfigTargetAdminConfigEnvOverriddenAdminConfigDuplicateKeysAdminConfigInvalidIDPTypeAdminConfigLDAPNonDefaultConfigNameAdminConfigLDAPValidationAdminConfigIDPCfgNameAlreadyExistsAdminConfigIDPCfgNameDoesNotExistInsecureClientRequestObjectTamperedAdminLDAPNotEnabledSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingSiteReplicationIAMConfigMismatchAdminRebalanceAlreadyStartedAdminRebalanceNotStartedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAggregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAddUserValidUTFAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormatInvalidChecksumLambdaARNInvalidLambdaARNNotFoundInvalidAttributeNameAdminNoAccessKeyAdminNoSecretKeyIAMNotInitializedapiErrCodeEnd" +const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidArgumentInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorRemoteTargetDenyAddErrorReplicationNoExistingObjectsReplicationValidationErrorReplicationPermissionCheckErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderMissingPartAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledPolicyInvalidVersionMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataUnsupportedHostHeaderMaximumExpiresSlowDownReadSlowDownWriteMaxVersionsExceededInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectivePolicyAlreadyAttachedPolicyNotAttachedExcessDataPolicyInvalidNameNoTokenRevokeTypeAdminOpenIDNotEnabledAdminNoSuchAccessKeyInvalidEncryptionMethodInvalidEncryptionKeyIDInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidEncryptionParametersSSECInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionKMSDefaultKeyAlreadyConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchContentChecksumMismatchStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameInvalidLifecycleQueryParameterServerNotInitializedBucketMetadataNotInitializedRequestTimedoutClientDisconnectedTooManyRequestsInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchUserLDAPWarnAdminLDAPExpectedLoginNameAdminNoSuchGroupAdminGroupNotEmptyAdminGroupDisabledAdminInvalidGroupNameAdminNoSuchJobAdminNoSuchPolicyAdminPolicyChangeAlreadyAppliedAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminNoSuchConfigTargetAdminConfigEnvOverriddenAdminConfigDuplicateKeysAdminConfigInvalidIDPTypeAdminConfigLDAPNonDefaultConfigNameAdminConfigLDAPValidationAdminConfigIDPCfgNameAlreadyExistsAdminConfigIDPCfgNameDoesNotExistInsecureClientRequestObjectTamperedAdminLDAPNotEnabledSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingSiteReplicationIAMConfigMismatchAdminRebalanceAlreadyStartedAdminRebalanceNotStartedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAggregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAddUserValidUTFAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormatInvalidChecksumLambdaARNInvalidLambdaARNNotFoundInvalidAttributeNameAdminNoAccessKeyAdminNoSecretKeyIAMNotInitializedapiErrCodeEnd" -var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 144, 161, 174, 186, 208, 228, 254, 268, 289, 306, 321, 344, 361, 379, 396, 420, 435, 456, 474, 486, 506, 523, 546, 567, 579, 597, 618, 646, 676, 697, 720, 746, 783, 813, 846, 871, 903, 933, 962, 987, 1009, 1035, 1057, 1085, 1114, 1148, 1179, 1216, 1240, 1264, 1292, 1318, 1349, 1379, 1388, 1400, 1416, 1429, 1443, 1461, 1481, 1502, 1518, 1529, 1545, 1556, 1584, 1604, 1620, 1648, 1662, 1679, 1699, 1712, 1726, 1739, 1752, 1768, 1785, 1806, 1820, 1841, 1854, 1876, 1899, 1915, 1930, 1945, 1966, 1984, 1999, 2016, 2041, 2059, 2082, 2097, 2116, 2132, 2151, 2172, 2186, 2198, 2211, 2230, 2249, 2259, 2274, 2310, 2341, 2374, 2403, 2415, 2435, 2459, 2483, 2504, 2528, 2547, 2568, 2585, 2595, 2612, 2629, 2652, 2674, 2700, 2721, 2739, 2766, 2797, 2824, 2845, 2866, 2890, 2915, 2943, 2971, 2987, 3010, 3040, 3051, 3063, 3080, 3095, 3113, 3142, 3159, 3175, 3191, 3209, 3227, 3250, 3271, 3294, 3305, 3321, 3344, 3361, 3389, 3408, 3438, 3458, 3486, 3501, 3519, 3534, 3548, 3583, 3602, 3613, 3626, 3641, 3664, 3690, 3706, 3724, 3742, 3763, 3777, 3794, 3825, 3845, 3866, 3887, 3906, 3925, 3943, 3966, 3990, 4014, 4039, 4074, 4099, 4133, 4166, 4187, 4201, 4220, 4249, 4272, 4299, 4333, 4365, 4395, 4418, 4446, 4478, 4506, 4530, 4554, 4583, 4601, 4618, 4640, 4657, 4675, 4695, 4721, 4737, 4756, 4777, 4781, 4799, 4816, 4842, 4856, 4880, 4901, 4916, 4934, 4957, 4972, 4991, 5008, 5025, 5049, 5076, 5099, 5122, 5139, 5161, 5177, 5197, 5216, 5238, 5259, 5279, 5301, 5325, 5344, 5386, 5407, 5430, 5451, 5482, 5501, 5523, 5543, 5569, 5590, 5612, 5632, 5656, 5679, 5698, 5718, 5740, 5763, 5794, 5832, 5873, 5903, 5917, 5938, 5954, 5976, 6006, 6032, 6060, 6094, 6112, 6135, 6170, 6210, 6252, 6284, 6301, 6326, 6341, 6358, 6368, 6379, 6417, 6471, 6517, 6569, 6617, 6660, 6704, 6732, 6746, 6764, 6800, 6823, 6846, 6868, 6883, 6911, 6934, 6952, 6979, 7011, 7026, 7042, 7059, 7079, 7095, 7111, 7128, 7141} +var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 144, 161, 174, 186, 208, 228, 254, 268, 289, 306, 321, 344, 361, 379, 396, 420, 435, 456, 474, 486, 506, 523, 546, 567, 579, 597, 618, 646, 676, 697, 720, 746, 783, 813, 846, 871, 903, 933, 962, 987, 1009, 1035, 1057, 1085, 1114, 1148, 1179, 1216, 1240, 1264, 1292, 1318, 1349, 1379, 1388, 1400, 1416, 1429, 1443, 1461, 1481, 1502, 1518, 1529, 1545, 1556, 1584, 1604, 1620, 1648, 1662, 1679, 1699, 1712, 1726, 1739, 1752, 1768, 1785, 1806, 1820, 1841, 1854, 1876, 1899, 1915, 1930, 1945, 1966, 1984, 1999, 2016, 2041, 2059, 2082, 2097, 2116, 2132, 2151, 2172, 2186, 2198, 2211, 2230, 2249, 2259, 2274, 2310, 2341, 2374, 2403, 2415, 2435, 2459, 2483, 2504, 2528, 2547, 2568, 2585, 2595, 2612, 2629, 2650, 2670, 2693, 2715, 2741, 2762, 2780, 2807, 2838, 2865, 2886, 2907, 2931, 2956, 2984, 3012, 3028, 3051, 3081, 3092, 3104, 3121, 3136, 3154, 3183, 3200, 3216, 3232, 3250, 3268, 3291, 3312, 3335, 3346, 3362, 3385, 3402, 3430, 3449, 3479, 3499, 3527, 3542, 3560, 3575, 3589, 3624, 3643, 3654, 3667, 3682, 3705, 3731, 3747, 3765, 3783, 3804, 3818, 3835, 3866, 3886, 3907, 3928, 3947, 3966, 3984, 4007, 4031, 4055, 4080, 4115, 4140, 4174, 4207, 4228, 4242, 4261, 4290, 4313, 4340, 4374, 4406, 4436, 4459, 4487, 4519, 4547, 4571, 4595, 4624, 4642, 4659, 4681, 4698, 4716, 4736, 4762, 4778, 4797, 4818, 4822, 4840, 4857, 4883, 4897, 4921, 4942, 4957, 4975, 4998, 5013, 5032, 5049, 5066, 5090, 5117, 5140, 5163, 5180, 5202, 5218, 5238, 5257, 5279, 5300, 5320, 5342, 5366, 5385, 5427, 5448, 5471, 5492, 5523, 5542, 5564, 5584, 5610, 5631, 5653, 5673, 5697, 5720, 5739, 5759, 5781, 5804, 5835, 5873, 5914, 5944, 5958, 5979, 5995, 6017, 6047, 6073, 6101, 6135, 6153, 6176, 6211, 6251, 6293, 6325, 6342, 6367, 6382, 6399, 6409, 6420, 6458, 6512, 6558, 6610, 6658, 6701, 6745, 6773, 6787, 6805, 6841, 6864, 6887, 6909, 6924, 6952, 6975, 6993, 7020, 7052, 7067, 7083, 7100, 7120, 7136, 7152, 7169, 7182} func (i APIErrorCode) String() string { if i < 0 || i >= APIErrorCode(len(_APIErrorCode_index)-1) { diff --git a/cmd/iam-store.go b/cmd/iam-store.go index 5640a8b8f..90e615519 100644 --- a/cmd/iam-store.go +++ b/cmd/iam-store.go @@ -2777,6 +2777,31 @@ func (store *IAMStoreSys) ListSTSAccounts(ctx context.Context, accessKey string) return stsAccounts, nil } +// ListAccessKeys - lists all access keys (sts/service accounts) +func (store *IAMStoreSys) ListAccessKeys(ctx context.Context) ([]auth.Credentials, error) { + cache := store.rlock() + defer store.runlock() + + accessKeys := store.getSTSAndServiceAccounts(cache) + for i, accessKey := range accessKeys { + accessKeys[i].SecretKey = "" + if accessKey.IsTemp() { + secret, err := getTokenSigningKey() + if err != nil { + return nil, err + } + claims, err := getClaimsFromTokenWithSecret(accessKey.SessionToken, secret) + if err != nil { + continue // ignore invalid session tokens + } + accessKeys[i].Claims = claims.MapClaims + } + accessKeys[i].SessionToken = "" + } + + return accessKeys, nil +} + // AddUser - adds/updates long term user account to storage. func (store *IAMStoreSys) AddUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) (updatedAt time.Time, err error) { cache := store.lock() @@ -2839,6 +2864,10 @@ func (store *IAMStoreSys) GetSTSAndServiceAccounts() []auth.Credentials { cache := store.rlock() defer store.runlock() + return store.getSTSAndServiceAccounts(cache) +} + +func (store *IAMStoreSys) getSTSAndServiceAccounts(cache *iamCache) []auth.Credentials { var res []auth.Credentials for _, u := range cache.iamUsersMap { cred := u.Credentials diff --git a/cmd/iam.go b/cmd/iam.go index ba9715abf..39416a64f 100644 --- a/cmd/iam.go +++ b/cmd/iam.go @@ -1246,6 +1246,20 @@ func (sys *IAMSys) ListSTSAccounts(ctx context.Context, accessKey string) ([]aut } } +// ListAllAccessKeys - lists all access keys (sts/service accounts) +func (sys *IAMSys) ListAllAccessKeys(ctx context.Context) ([]auth.Credentials, error) { + if !sys.Initialized() { + return nil, errServerNotInitialized + } + + select { + case <-sys.configLoaded: + return sys.store.ListAccessKeys(ctx) + case <-ctx.Done(): + return nil, ctx.Err() + } +} + // GetServiceAccount - wrapper method to get information about a service account func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *policy.Policy, error) { sa, embeddedPolicy, err := sys.getServiceAccount(ctx, accessKey) diff --git a/cmd/typed-errors.go b/cmd/typed-errors.go index da25c674a..58f2590e4 100644 --- a/cmd/typed-errors.go +++ b/cmd/typed-errors.go @@ -75,6 +75,9 @@ var errNoSuchServiceAccount = errors.New("Specified service account does not exi // error returned when temporary account is not found var errNoSuchTempAccount = errors.New("Specified temporary account does not exist") +// error returned when access key is not found +var errNoSuchAccessKey = errors.New("Specified access key does not exist") + // error returned in IAM subsystem when an account doesn't exist. var errNoSuchAccount = errors.New("Specified account does not exist") diff --git a/cmd/user-provider-utils.go b/cmd/user-provider-utils.go index 5f5501350..8f2ad5358 100644 --- a/cmd/user-provider-utils.go +++ b/cmd/user-provider-utils.go @@ -19,8 +19,10 @@ package cmd import ( "context" + "strings" "github.com/minio/madmin-go/v3" + "github.com/minio/minio/internal/auth" ) // getUserWithProvider - returns the appropriate internal username based on the user provider. @@ -55,3 +57,85 @@ func getUserWithProvider(ctx context.Context, userProvider, user string, validat return "", errIAMActionNotAllowed } } + +// guessUserProvider - guesses the user provider based on the access key and claims. +func guessUserProvider(credentials auth.Credentials) string { + if !credentials.IsServiceAccount() && !credentials.IsTemp() { + return madmin.BuiltinProvider // regular users are always internal + } + + claims := credentials.Claims + if _, ok := claims[ldapUser]; ok { + return madmin.LDAPProvider // ldap users + } + + if _, ok := claims[subClaim]; ok { + providerPrefix, _, found := strings.Cut(credentials.ParentUser, getKeySeparator()) + if found { + return providerPrefix // this is true for certificate and custom providers + } + return madmin.OpenIDProvider // openid users are already hashed, so no separator + } + + return madmin.BuiltinProvider // default to internal +} + +// getProviderInfoFromClaims - returns the provider info from the claims. +func populateProviderInfoFromClaims(claims map[string]interface{}, provider string, resp *madmin.InfoAccessKeyResp) { + resp.UserProvider = provider + switch provider { + case madmin.LDAPProvider: + resp.LDAPSpecificInfo = getLDAPInfoFromClaims(claims) + case madmin.OpenIDProvider: + resp.OpenIDSpecificInfo = getOpenIDInfoFromClaims(claims) + } +} + +func getOpenIDCfgNameFromClaims(claims map[string]interface{}) (string, bool) { + roleArn := claims[roleArnClaim] + + s := globalServerConfig.Clone() + configs, err := globalIAMSys.OpenIDConfig.GetConfigList(s) + if err != nil { + return "", false + } + for _, cfg := range configs { + if cfg.RoleARN == roleArn { + return cfg.Name, true + } + } + return "", false +} + +func getOpenIDInfoFromClaims(claims map[string]interface{}) madmin.OpenIDSpecificAccessKeyInfo { + info := madmin.OpenIDSpecificAccessKeyInfo{} + + cfgName, ok := getOpenIDCfgNameFromClaims(claims) + if !ok { + return info + } + + info.ConfigName = cfgName + if displayNameClaim := globalIAMSys.OpenIDConfig.GetUserReadableClaim(cfgName); displayNameClaim != "" { + name, _ := claims[displayNameClaim].(string) + info.DisplayName = name + info.DisplayNameClaim = displayNameClaim + } + if idClaim := globalIAMSys.OpenIDConfig.GetUserIDClaim(cfgName); idClaim != "" { + id, _ := claims[idClaim].(string) + info.UserID = id + info.UserIDClaim = idClaim + } + + return info +} + +func getLDAPInfoFromClaims(claims map[string]interface{}) madmin.LDAPSpecificAccessKeyInfo { + info := madmin.LDAPSpecificAccessKeyInfo{} + + if name, ok := claims[ldapUser].(string); ok { + info.Username = name + } + + return info +} diff --git a/go.mod b/go.mod index 02d1e7bb1..5def36df8 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.24.0 toolchain go1.24.2 +replace github.com/minio/madmin-go/v3 => github.com/taran-p/madmin-go/v3 v3.0.55-0.20250325221636-f5498832320f + require ( cloud.google.com/go/storage v1.46.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 diff --git a/go.sum b/go.sum index 36d2bb401..96b86ae7a 100644 --- a/go.sum +++ b/go.sum @@ -436,8 +436,6 @@ github.com/minio/kms-go/kes v0.3.1 h1:K3sPFAvFbJx33XlCTUBnQo8JRmSZyDvT6T2/MQ2iC3 github.com/minio/kms-go/kes v0.3.1/go.mod h1:Q9Ct0KUAuN9dH0hSVa0eva45Jg99cahbZpPxeqR9rOQ= github.com/minio/kms-go/kms v0.4.0 h1:cLPZceEp+05xHotVBaeFJrgL7JcXM4lBy6PU0idkE7I= github.com/minio/kms-go/kms v0.4.0/go.mod h1:q12CehiIy2qgBnDKq6Q7wmPi2PHSyRVug5DKp0HAVeE= -github.com/minio/madmin-go/v3 v3.0.102 h1:bqy15D6d9uQOh/3B/sLfzRtWSJgZeuKnAI5VRDhvRQw= -github.com/minio/madmin-go/v3 v3.0.102/go.mod h1:pMLdj9OtN0CANNs5tdm6opvOlDFfj0WhbztboZAjRWE= github.com/minio/mc v0.0.0-20250312172924-c1d5d4cbb4ca h1:Zeu+Gbsw/yoqJofAFaU3zbIVr51j9LULUrQqKFLQnGA= github.com/minio/mc v0.0.0-20250312172924-c1d5d4cbb4ca/go.mod h1:h5UQZ+5Qfq6XV81E4iZSgStPZ6Hy+gMuHMkLkjq4Gys= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= @@ -612,6 +610,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/taran-p/madmin-go/v3 v3.0.55-0.20250325221636-f5498832320f h1:U8MMUkE2W8zVMMxpI6AwIf0PacwEYdBP1LR30FWNlhk= +github.com/taran-p/madmin-go/v3 v3.0.55-0.20250325221636-f5498832320f/go.mod h1:pMLdj9OtN0CANNs5tdm6opvOlDFfj0WhbztboZAjRWE= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= diff --git a/internal/config/identity/openid/openid.go b/internal/config/identity/openid/openid.go index c2f502a68..c90c60d3e 100644 --- a/internal/config/identity/openid/openid.go +++ b/internal/config/identity/openid/openid.go @@ -43,13 +43,15 @@ import ( // OpenID keys and envs. const ( - ClientID = "client_id" - ClientSecret = "client_secret" - ConfigURL = "config_url" - ClaimName = "claim_name" - ClaimUserinfo = "claim_userinfo" - RolePolicy = "role_policy" - DisplayName = "display_name" + ClientID = "client_id" + ClientSecret = "client_secret" + ConfigURL = "config_url" + ClaimName = "claim_name" + ClaimUserinfo = "claim_userinfo" + RolePolicy = "role_policy" + DisplayName = "display_name" + UserReadableClaim = "user_readable_claim" + UserIDClaim = "user_id_claim" Scopes = "scopes" RedirectURI = "redirect_uri" @@ -130,6 +132,14 @@ var ( Key: KeyCloakAdminURL, Value: "", }, + config.KV{ + Key: UserReadableClaim, + Value: "", + }, + config.KV{ + Key: UserIDClaim, + Value: "", + }, } ) @@ -628,3 +638,25 @@ func GetDefaultExpiration(dsecs string) (time.Duration, error) { return defaultExpiryDuration, nil } + +// GetUserReadableClaim returns the human readable claim name for the given +// configuration name. +func (r Config) GetUserReadableClaim(cfgName string) string { + pCfg, ok := r.ProviderCfgs[cfgName] + if ok { + return pCfg.UserReadableClaim + } + return "" +} + +// GetUserIDClaim returns the user ID claim for the given configuration name, or "sub" if not set. +func (r Config) GetUserIDClaim(cfgName string) string { + pCfg, ok := r.ProviderCfgs[cfgName] + if ok { + if pCfg.UserIDClaim != "" { + return pCfg.UserIDClaim + } + return "sub" + } + return "" // an incorrect config should be handled outside this function +} diff --git a/internal/config/identity/openid/providercfg.go b/internal/config/identity/openid/providercfg.go index 5621b83df..0c0a91534 100644 --- a/internal/config/identity/openid/providercfg.go +++ b/internal/config/identity/openid/providercfg.go @@ -48,6 +48,8 @@ type providerCfg struct { ClientID string ClientSecret string RolePolicy string + UserReadableClaim string + UserIDClaim string roleArn arn.ARN provider provider.Provider @@ -64,6 +66,8 @@ func newProviderCfgFromConfig(getCfgVal func(cfgName string) string) providerCfg ClientID: getCfgVal(ClientID), ClientSecret: getCfgVal(ClientSecret), RolePolicy: getCfgVal(RolePolicy), + UserReadableClaim: getCfgVal(UserReadableClaim), + UserIDClaim: getCfgVal(UserIDClaim), } }