From af9bc7ea7dc35a2aaf6e4dc56a38008d0c83b45d Mon Sep 17 00:00:00 2001 From: Aditya Manthramurthy Date: Tue, 5 Jul 2022 18:18:04 -0700 Subject: [PATCH] Add external IDP management Admin API for OpenID (#15152) --- cmd/admin-handlers-idp-config.go | 321 ++++++++++++++++++++++ cmd/admin-router.go | 7 + cmd/api-errors.go | 12 + cmd/apierrorcode_string.go | 234 ++++++++-------- internal/config/config.go | 55 ++++ internal/config/identity/openid/help.go | 1 + internal/config/identity/openid/openid.go | 102 +++++++ 7 files changed, 616 insertions(+), 116 deletions(-) create mode 100644 cmd/admin-handlers-idp-config.go diff --git a/cmd/admin-handlers-idp-config.go b/cmd/admin-handlers-idp-config.go new file mode 100644 index 000000000..52444da90 --- /dev/null +++ b/cmd/admin-handlers-idp-config.go @@ -0,0 +1,321 @@ +// 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 . + +package cmd + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + "github.com/gorilla/mux" + "github.com/minio/madmin-go" + "github.com/minio/minio-go/v7/pkg/set" + "github.com/minio/minio/internal/config" + "github.com/minio/minio/internal/config/identity/openid" + "github.com/minio/minio/internal/logger" + iampolicy "github.com/minio/pkg/iam/policy" +) + +// List of implemented ID config types. +var idCfgTypes = set.CreateStringSet("openid") + +// SetIdentityProviderCfg: +// +// PUT /id-cfg?type=openid&name=dex1 +func (a adminAPIHandlers) SetIdentityProviderCfg(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "SetIdentityCfg") + + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, cred := validateAdminReq(ctx, w, r, iampolicy.ConfigUpdateAdminAction) + if objectAPI == nil { + return + } + + if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { + // More than maxConfigSize bytes were available + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) + return + } + + password := cred.SecretKey + reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) + if err != nil { + logger.LogIf(ctx, err, logger.Application) + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) + return + } + + cfgType := mux.Vars(r)["type"] + if !idCfgTypes.Contains(cfgType) { + // TODO: change this to invalid type error when implementation + // is complete. + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + var cfgDataBuilder strings.Builder + switch cfgType { + case "openid": + fmt.Fprintf(&cfgDataBuilder, "identity_openid") + } + + // Ensure body content type is opaque. + contentType := r.Header.Get("Content-Type") + if contentType != "application/octet-stream" { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrBadRequest), r.URL) + return + } + + // Subsystem configuration name could be empty. + cfgName := mux.Vars(r)["name"] + if cfgName != "" { + fmt.Fprintf(&cfgDataBuilder, "%s%s", config.SubSystemSeparator, cfgName) + } + + fmt.Fprintf(&cfgDataBuilder, "%s%s", config.KvSpaceSeparator, string(reqBytes)) + + cfgData := cfgDataBuilder.String() + subSys, _, _, err := config.GetSubSys(cfgData) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + cfg, err := readServerConfig(ctx, objectAPI) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + dynamic, err := cfg.ReadConfig(strings.NewReader(cfgData)) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + // IDP config is not dynamic. Sanity check. + if dynamic { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL) + return + } + + if err = validateConfig(cfg, subSys); err != nil { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) + return + } + + // Update the actual server config on disk. + if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + // Write to the config input KV to history. + if err = saveServerConfigHistory(ctx, objectAPI, []byte(cfgData)); err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + writeSuccessResponseHeadersOnly(w) +} + +// GetIdentityProviderCfg: +// +// GET /id-cfg?type=openid&name=dex_test +// +// GetIdentityProviderCfg returns a list of configured IDPs on the server if +// name is empty. If name is non-empty, returns the configuration details for +// the IDP of the given type and configuration name. The configuration name for +// the default ("un-named") configuration target is `_`. +func (a adminAPIHandlers) GetIdentityProviderCfg(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "GetIdentityProviderCfg") + + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, cred := validateAdminReq(ctx, w, r, iampolicy.ConfigUpdateAdminAction) + if objectAPI == nil { + return + } + + cfgType := mux.Vars(r)["type"] + cfgName := r.Form.Get("name") + password := cred.SecretKey + + if !idCfgTypes.Contains(cfgType) { + // TODO: change this to invalid type error when implementation + // is complete. + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + // If no cfgName is provided, we list. + if cfgName == "" { + a.listIdentityProviders(ctx, w, r, cfgType, password) + return + } + + cfg := globalServerConfig.Clone() + + cfgInfos, err := globalOpenIDConfig.GetConfigInfo(cfg, cfgName) + if err != nil { + if err == openid.ErrProviderConfigNotFound { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminNoSuchConfigTarget), r.URL) + return + } + + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + res := madmin.IDPConfig{ + Type: cfgType, + Name: cfgName, + Info: cfgInfos, + } + data, err := json.Marshal(res) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + econfigData, err := madmin.EncryptData(password, data) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + writeSuccessResponseJSON(w, econfigData) +} + +func (a adminAPIHandlers) listIdentityProviders(ctx context.Context, w http.ResponseWriter, r *http.Request, cfgType, password string) { + // var subSys string + switch cfgType { + case "openid": + // subSys = config.IdentityOpenIDSubSys + default: + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + cfg := globalServerConfig.Clone() + cfgList, err := globalOpenIDConfig.GetConfigList(cfg) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + data, err := json.Marshal(cfgList) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + econfigData, err := madmin.EncryptData(password, data) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + writeSuccessResponseJSON(w, econfigData) +} + +// DeleteIdentityProviderCfg: +// +// DELETE /id-cfg?type=openid&name=dex_test +func (a adminAPIHandlers) DeleteIdentityProviderCfg(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "DeleteIdentityProviderCfg") + + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.ConfigUpdateAdminAction) + if objectAPI == nil { + return + } + + cfgType := mux.Vars(r)["type"] + cfgName := mux.Vars(r)["name"] + if !idCfgTypes.Contains(cfgType) { + // TODO: change this to invalid type error when implementation + // is complete. + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + cfg := globalServerConfig.Clone() + + cfgInfos, err := globalOpenIDConfig.GetConfigInfo(cfg, cfgName) + if err != nil { + if err == openid.ErrProviderConfigNotFound { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminNoSuchConfigTarget), r.URL) + return + } + + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + hasEnv := false + for _, ci := range cfgInfos { + if ci.IsCfg && ci.IsEnv { + hasEnv = true + break + } + } + + if hasEnv { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigEnvOverridden), r.URL) + return + } + + var subSys string + switch cfgType { + case "openid": + subSys = config.IdentityOpenIDSubSys + default: + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + cfg, err = readServerConfig(ctx, objectAPI) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + if err = cfg.DelKVS(fmt.Sprintf("%s:%s", subSys, cfgName)); err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + if err = validateConfig(cfg, subSys); err != nil { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) + return + } + if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + dynamic := config.SubSystemsDynamic.Contains(subSys) + if dynamic { + applyDynamic(ctx, objectAPI, cfg, subSys, r, w) + } +} diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 2e9a96897..d1a633e1c 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -178,6 +178,13 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) { // Import IAM info adminRouter.Methods(http.MethodPut).Path(adminVersion + "/import-iam").HandlerFunc(httpTraceHdrs(adminAPI.ImportIAM)) + // IDentity Provider configuration APIs + adminRouter.Methods(http.MethodPut).Path(adminVersion+"/idp-config").HandlerFunc(gz(httpTraceHdrs(adminAPI.SetIdentityProviderCfg))).Queries("type", "{type:.*}").Queries("name", "{name:.*}") + adminRouter.Methods(http.MethodGet).Path(adminVersion+"/idp-config").HandlerFunc(gz(httpTraceHdrs(adminAPI.GetIdentityProviderCfg))).Queries("type", "{type:.*}") + adminRouter.Methods(http.MethodDelete).Path(adminVersion+"/idp-config").HandlerFunc(gz(httpTraceHdrs(adminAPI.DeleteIdentityProviderCfg))).Queries("type", "{type:.*}").Queries("name", "{name:.*}") + + // -- END IAM APIs -- + // GetBucketQuotaConfig adminRouter.Methods(http.MethodGet).Path(adminVersion+"/get-bucket-quota").HandlerFunc( gz(httpTraceHdrs(adminAPI.GetBucketQuotaConfigHandler))).Queries("bucket", "{bucket:.*}") diff --git a/cmd/api-errors.go b/cmd/api-errors.go index b02fa0b73..ae4dacf51 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -267,6 +267,8 @@ const ( ErrAdminConfigNoQuorum ErrAdminConfigTooLarge ErrAdminConfigBadJSON + ErrAdminNoSuchConfigTarget + ErrAdminConfigEnvOverridden ErrAdminConfigDuplicateKeys ErrAdminCredentialsMismatch ErrInsecureClientRequest @@ -1240,11 +1242,21 @@ var errorCodes = errorCodeMap{ maxEConfigJSONSize), HTTPStatusCode: http.StatusBadRequest, }, + ErrAdminNoSuchConfigTarget: { + Code: "XMinioAdminNoSuchConfigTarget", + Description: "No such named configuration target exists", + HTTPStatusCode: http.StatusBadRequest, + }, ErrAdminConfigBadJSON: { Code: "XMinioAdminConfigBadJSON", Description: "JSON configuration provided is of incorrect format", HTTPStatusCode: http.StatusBadRequest, }, + ErrAdminConfigEnvOverridden: { + Code: "XMinioAdminConfigEnvOverridden", + Description: "Unable to update config via Admin API due to environment variable override", + HTTPStatusCode: http.StatusBadRequest, + }, ErrAdminConfigDuplicateKeys: { Code: "XMinioAdminConfigDuplicateKeys", Description: "JSON configuration provided has objects with duplicate keys", diff --git a/cmd/apierrorcode_string.go b/cmd/apierrorcode_string.go index f5cfefd2c..4552d751f 100644 --- a/cmd/apierrorcode_string.go +++ b/cmd/apierrorcode_string.go @@ -183,125 +183,127 @@ func _() { _ = x[ErrAdminConfigNoQuorum-172] _ = x[ErrAdminConfigTooLarge-173] _ = x[ErrAdminConfigBadJSON-174] - _ = x[ErrAdminConfigDuplicateKeys-175] - _ = x[ErrAdminCredentialsMismatch-176] - _ = x[ErrInsecureClientRequest-177] - _ = x[ErrObjectTampered-178] - _ = x[ErrSiteReplicationInvalidRequest-179] - _ = x[ErrSiteReplicationPeerResp-180] - _ = x[ErrSiteReplicationBackendIssue-181] - _ = x[ErrSiteReplicationServiceAccountError-182] - _ = x[ErrSiteReplicationBucketConfigError-183] - _ = x[ErrSiteReplicationBucketMetaError-184] - _ = x[ErrSiteReplicationIAMError-185] - _ = x[ErrSiteReplicationConfigMissing-186] - _ = x[ErrAdminBucketQuotaExceeded-187] - _ = x[ErrAdminNoSuchQuotaConfiguration-188] - _ = x[ErrHealNotImplemented-189] - _ = x[ErrHealNoSuchProcess-190] - _ = x[ErrHealInvalidClientToken-191] - _ = x[ErrHealMissingBucket-192] - _ = x[ErrHealAlreadyRunning-193] - _ = x[ErrHealOverlappingPaths-194] - _ = x[ErrIncorrectContinuationToken-195] - _ = x[ErrEmptyRequestBody-196] - _ = x[ErrUnsupportedFunction-197] - _ = x[ErrInvalidExpressionType-198] - _ = x[ErrBusy-199] - _ = x[ErrUnauthorizedAccess-200] - _ = x[ErrExpressionTooLong-201] - _ = x[ErrIllegalSQLFunctionArgument-202] - _ = x[ErrInvalidKeyPath-203] - _ = x[ErrInvalidCompressionFormat-204] - _ = x[ErrInvalidFileHeaderInfo-205] - _ = x[ErrInvalidJSONType-206] - _ = x[ErrInvalidQuoteFields-207] - _ = x[ErrInvalidRequestParameter-208] - _ = x[ErrInvalidDataType-209] - _ = x[ErrInvalidTextEncoding-210] - _ = x[ErrInvalidDataSource-211] - _ = x[ErrInvalidTableAlias-212] - _ = x[ErrMissingRequiredParameter-213] - _ = x[ErrObjectSerializationConflict-214] - _ = x[ErrUnsupportedSQLOperation-215] - _ = x[ErrUnsupportedSQLStructure-216] - _ = x[ErrUnsupportedSyntax-217] - _ = x[ErrUnsupportedRangeHeader-218] - _ = x[ErrLexerInvalidChar-219] - _ = x[ErrLexerInvalidOperator-220] - _ = x[ErrLexerInvalidLiteral-221] - _ = x[ErrLexerInvalidIONLiteral-222] - _ = x[ErrParseExpectedDatePart-223] - _ = x[ErrParseExpectedKeyword-224] - _ = x[ErrParseExpectedTokenType-225] - _ = x[ErrParseExpected2TokenTypes-226] - _ = x[ErrParseExpectedNumber-227] - _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-228] - _ = x[ErrParseExpectedTypeName-229] - _ = x[ErrParseExpectedWhenClause-230] - _ = x[ErrParseUnsupportedToken-231] - _ = x[ErrParseUnsupportedLiteralsGroupBy-232] - _ = x[ErrParseExpectedMember-233] - _ = x[ErrParseUnsupportedSelect-234] - _ = x[ErrParseUnsupportedCase-235] - _ = x[ErrParseUnsupportedCaseClause-236] - _ = x[ErrParseUnsupportedAlias-237] - _ = x[ErrParseUnsupportedSyntax-238] - _ = x[ErrParseUnknownOperator-239] - _ = x[ErrParseMissingIdentAfterAt-240] - _ = x[ErrParseUnexpectedOperator-241] - _ = x[ErrParseUnexpectedTerm-242] - _ = x[ErrParseUnexpectedToken-243] - _ = x[ErrParseUnexpectedKeyword-244] - _ = x[ErrParseExpectedExpression-245] - _ = x[ErrParseExpectedLeftParenAfterCast-246] - _ = x[ErrParseExpectedLeftParenValueConstructor-247] - _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-248] - _ = x[ErrParseExpectedArgumentDelimiter-249] - _ = x[ErrParseCastArity-250] - _ = x[ErrParseInvalidTypeParam-251] - _ = x[ErrParseEmptySelect-252] - _ = x[ErrParseSelectMissingFrom-253] - _ = x[ErrParseExpectedIdentForGroupName-254] - _ = x[ErrParseExpectedIdentForAlias-255] - _ = x[ErrParseUnsupportedCallWithStar-256] - _ = x[ErrParseNonUnaryAgregateFunctionCall-257] - _ = x[ErrParseMalformedJoin-258] - _ = x[ErrParseExpectedIdentForAt-259] - _ = x[ErrParseAsteriskIsNotAloneInSelectList-260] - _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-261] - _ = x[ErrParseInvalidContextForWildcardInSelectList-262] - _ = x[ErrIncorrectSQLFunctionArgumentType-263] - _ = x[ErrValueParseFailure-264] - _ = x[ErrEvaluatorInvalidArguments-265] - _ = x[ErrIntegerOverflow-266] - _ = x[ErrLikeInvalidInputs-267] - _ = x[ErrCastFailed-268] - _ = x[ErrInvalidCast-269] - _ = x[ErrEvaluatorInvalidTimestampFormatPattern-270] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-271] - _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-272] - _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-273] - _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-274] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-275] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-276] - _ = x[ErrEvaluatorBindingDoesNotExist-277] - _ = x[ErrMissingHeaders-278] - _ = x[ErrInvalidColumnIndex-279] - _ = x[ErrAdminConfigNotificationTargetsFailed-280] - _ = x[ErrAdminProfilerNotEnabled-281] - _ = x[ErrInvalidDecompressedSize-282] - _ = x[ErrAddUserInvalidArgument-283] - _ = x[ErrAdminResourceInvalidArgument-284] - _ = x[ErrAdminAccountNotEligible-285] - _ = x[ErrAccountNotEligible-286] - _ = x[ErrAdminServiceAccountNotFound-287] - _ = x[ErrPostPolicyConditionInvalidFormat-288] + _ = x[ErrAdminNoSuchConfigTarget-175] + _ = x[ErrAdminConfigEnvOverridden-176] + _ = x[ErrAdminConfigDuplicateKeys-177] + _ = x[ErrAdminCredentialsMismatch-178] + _ = x[ErrInsecureClientRequest-179] + _ = x[ErrObjectTampered-180] + _ = x[ErrSiteReplicationInvalidRequest-181] + _ = x[ErrSiteReplicationPeerResp-182] + _ = x[ErrSiteReplicationBackendIssue-183] + _ = x[ErrSiteReplicationServiceAccountError-184] + _ = x[ErrSiteReplicationBucketConfigError-185] + _ = x[ErrSiteReplicationBucketMetaError-186] + _ = x[ErrSiteReplicationIAMError-187] + _ = x[ErrSiteReplicationConfigMissing-188] + _ = x[ErrAdminBucketQuotaExceeded-189] + _ = x[ErrAdminNoSuchQuotaConfiguration-190] + _ = x[ErrHealNotImplemented-191] + _ = x[ErrHealNoSuchProcess-192] + _ = x[ErrHealInvalidClientToken-193] + _ = x[ErrHealMissingBucket-194] + _ = x[ErrHealAlreadyRunning-195] + _ = x[ErrHealOverlappingPaths-196] + _ = x[ErrIncorrectContinuationToken-197] + _ = x[ErrEmptyRequestBody-198] + _ = x[ErrUnsupportedFunction-199] + _ = x[ErrInvalidExpressionType-200] + _ = x[ErrBusy-201] + _ = x[ErrUnauthorizedAccess-202] + _ = x[ErrExpressionTooLong-203] + _ = x[ErrIllegalSQLFunctionArgument-204] + _ = x[ErrInvalidKeyPath-205] + _ = x[ErrInvalidCompressionFormat-206] + _ = x[ErrInvalidFileHeaderInfo-207] + _ = x[ErrInvalidJSONType-208] + _ = x[ErrInvalidQuoteFields-209] + _ = x[ErrInvalidRequestParameter-210] + _ = x[ErrInvalidDataType-211] + _ = x[ErrInvalidTextEncoding-212] + _ = x[ErrInvalidDataSource-213] + _ = x[ErrInvalidTableAlias-214] + _ = x[ErrMissingRequiredParameter-215] + _ = x[ErrObjectSerializationConflict-216] + _ = x[ErrUnsupportedSQLOperation-217] + _ = x[ErrUnsupportedSQLStructure-218] + _ = x[ErrUnsupportedSyntax-219] + _ = x[ErrUnsupportedRangeHeader-220] + _ = x[ErrLexerInvalidChar-221] + _ = x[ErrLexerInvalidOperator-222] + _ = x[ErrLexerInvalidLiteral-223] + _ = x[ErrLexerInvalidIONLiteral-224] + _ = x[ErrParseExpectedDatePart-225] + _ = x[ErrParseExpectedKeyword-226] + _ = x[ErrParseExpectedTokenType-227] + _ = x[ErrParseExpected2TokenTypes-228] + _ = x[ErrParseExpectedNumber-229] + _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-230] + _ = x[ErrParseExpectedTypeName-231] + _ = x[ErrParseExpectedWhenClause-232] + _ = x[ErrParseUnsupportedToken-233] + _ = x[ErrParseUnsupportedLiteralsGroupBy-234] + _ = x[ErrParseExpectedMember-235] + _ = x[ErrParseUnsupportedSelect-236] + _ = x[ErrParseUnsupportedCase-237] + _ = x[ErrParseUnsupportedCaseClause-238] + _ = x[ErrParseUnsupportedAlias-239] + _ = x[ErrParseUnsupportedSyntax-240] + _ = x[ErrParseUnknownOperator-241] + _ = x[ErrParseMissingIdentAfterAt-242] + _ = x[ErrParseUnexpectedOperator-243] + _ = x[ErrParseUnexpectedTerm-244] + _ = x[ErrParseUnexpectedToken-245] + _ = x[ErrParseUnexpectedKeyword-246] + _ = x[ErrParseExpectedExpression-247] + _ = x[ErrParseExpectedLeftParenAfterCast-248] + _ = x[ErrParseExpectedLeftParenValueConstructor-249] + _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-250] + _ = x[ErrParseExpectedArgumentDelimiter-251] + _ = x[ErrParseCastArity-252] + _ = x[ErrParseInvalidTypeParam-253] + _ = x[ErrParseEmptySelect-254] + _ = x[ErrParseSelectMissingFrom-255] + _ = x[ErrParseExpectedIdentForGroupName-256] + _ = x[ErrParseExpectedIdentForAlias-257] + _ = x[ErrParseUnsupportedCallWithStar-258] + _ = x[ErrParseNonUnaryAgregateFunctionCall-259] + _ = x[ErrParseMalformedJoin-260] + _ = x[ErrParseExpectedIdentForAt-261] + _ = x[ErrParseAsteriskIsNotAloneInSelectList-262] + _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-263] + _ = x[ErrParseInvalidContextForWildcardInSelectList-264] + _ = x[ErrIncorrectSQLFunctionArgumentType-265] + _ = x[ErrValueParseFailure-266] + _ = x[ErrEvaluatorInvalidArguments-267] + _ = x[ErrIntegerOverflow-268] + _ = x[ErrLikeInvalidInputs-269] + _ = x[ErrCastFailed-270] + _ = x[ErrInvalidCast-271] + _ = x[ErrEvaluatorInvalidTimestampFormatPattern-272] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-273] + _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-274] + _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-275] + _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-276] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-277] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-278] + _ = x[ErrEvaluatorBindingDoesNotExist-279] + _ = x[ErrMissingHeaders-280] + _ = x[ErrInvalidColumnIndex-281] + _ = x[ErrAdminConfigNotificationTargetsFailed-282] + _ = x[ErrAdminProfilerNotEnabled-283] + _ = x[ErrInvalidDecompressedSize-284] + _ = x[ErrAddUserInvalidArgument-285] + _ = x[ErrAdminResourceInvalidArgument-286] + _ = x[ErrAdminAccountNotEligible-287] + _ = x[ErrAccountNotEligible-288] + _ = x[ErrAdminServiceAccountNotFound-289] + _ = x[ErrPostPolicyConditionInvalidFormat-290] } -const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorReplicationNoExistingObjectsObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" +const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorReplicationNoExistingObjectsObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminNoSuchConfigTargetAdminConfigEnvOverriddenAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" -var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 146, 159, 171, 193, 213, 239, 253, 274, 291, 306, 329, 346, 364, 381, 405, 420, 441, 459, 471, 491, 508, 531, 552, 564, 582, 603, 631, 661, 682, 705, 731, 768, 798, 831, 856, 888, 918, 947, 972, 994, 1020, 1042, 1070, 1099, 1133, 1164, 1201, 1225, 1253, 1283, 1292, 1304, 1320, 1333, 1347, 1365, 1385, 1406, 1422, 1433, 1449, 1477, 1497, 1513, 1541, 1555, 1572, 1587, 1600, 1614, 1627, 1640, 1656, 1673, 1694, 1708, 1729, 1742, 1764, 1787, 1812, 1828, 1843, 1858, 1879, 1897, 1912, 1929, 1954, 1972, 1995, 2010, 2029, 2045, 2064, 2078, 2086, 2105, 2115, 2130, 2166, 2197, 2230, 2259, 2271, 2291, 2315, 2339, 2360, 2384, 2403, 2426, 2452, 2473, 2491, 2518, 2545, 2566, 2587, 2611, 2636, 2664, 2692, 2708, 2731, 2742, 2754, 2771, 2786, 2804, 2833, 2850, 2866, 2882, 2900, 2918, 2941, 2962, 2972, 2983, 2994, 3010, 3033, 3050, 3078, 3097, 3117, 3134, 3152, 3169, 3183, 3218, 3237, 3248, 3261, 3276, 3292, 3310, 3327, 3347, 3368, 3389, 3408, 3427, 3445, 3469, 3493, 3514, 3528, 3557, 3580, 3607, 3641, 3673, 3703, 3726, 3754, 3778, 3807, 3825, 3842, 3864, 3881, 3899, 3919, 3945, 3961, 3980, 4001, 4005, 4023, 4040, 4066, 4080, 4104, 4125, 4140, 4158, 4181, 4196, 4215, 4232, 4249, 4273, 4300, 4323, 4346, 4363, 4385, 4401, 4421, 4440, 4462, 4483, 4503, 4525, 4549, 4568, 4610, 4631, 4654, 4675, 4706, 4725, 4747, 4767, 4793, 4814, 4836, 4856, 4880, 4903, 4922, 4942, 4964, 4987, 5018, 5056, 5097, 5127, 5141, 5162, 5178, 5200, 5230, 5256, 5284, 5317, 5335, 5358, 5393, 5433, 5475, 5507, 5524, 5549, 5564, 5581, 5591, 5602, 5640, 5694, 5740, 5792, 5840, 5883, 5927, 5955, 5969, 5987, 6023, 6046, 6069, 6091, 6119, 6142, 6160, 6187, 6219} +var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 146, 159, 171, 193, 213, 239, 253, 274, 291, 306, 329, 346, 364, 381, 405, 420, 441, 459, 471, 491, 508, 531, 552, 564, 582, 603, 631, 661, 682, 705, 731, 768, 798, 831, 856, 888, 918, 947, 972, 994, 1020, 1042, 1070, 1099, 1133, 1164, 1201, 1225, 1253, 1283, 1292, 1304, 1320, 1333, 1347, 1365, 1385, 1406, 1422, 1433, 1449, 1477, 1497, 1513, 1541, 1555, 1572, 1587, 1600, 1614, 1627, 1640, 1656, 1673, 1694, 1708, 1729, 1742, 1764, 1787, 1812, 1828, 1843, 1858, 1879, 1897, 1912, 1929, 1954, 1972, 1995, 2010, 2029, 2045, 2064, 2078, 2086, 2105, 2115, 2130, 2166, 2197, 2230, 2259, 2271, 2291, 2315, 2339, 2360, 2384, 2403, 2426, 2452, 2473, 2491, 2518, 2545, 2566, 2587, 2611, 2636, 2664, 2692, 2708, 2731, 2742, 2754, 2771, 2786, 2804, 2833, 2850, 2866, 2882, 2900, 2918, 2941, 2962, 2972, 2983, 2994, 3010, 3033, 3050, 3078, 3097, 3117, 3134, 3152, 3169, 3183, 3218, 3237, 3248, 3261, 3276, 3292, 3310, 3327, 3347, 3368, 3389, 3408, 3427, 3445, 3468, 3492, 3516, 3540, 3561, 3575, 3604, 3627, 3654, 3688, 3720, 3750, 3773, 3801, 3825, 3854, 3872, 3889, 3911, 3928, 3946, 3966, 3992, 4008, 4027, 4048, 4052, 4070, 4087, 4113, 4127, 4151, 4172, 4187, 4205, 4228, 4243, 4262, 4279, 4296, 4320, 4347, 4370, 4393, 4410, 4432, 4448, 4468, 4487, 4509, 4530, 4550, 4572, 4596, 4615, 4657, 4678, 4701, 4722, 4753, 4772, 4794, 4814, 4840, 4861, 4883, 4903, 4927, 4950, 4969, 4989, 5011, 5034, 5065, 5103, 5144, 5174, 5188, 5209, 5225, 5247, 5277, 5303, 5331, 5364, 5382, 5405, 5440, 5480, 5522, 5554, 5571, 5596, 5611, 5628, 5638, 5649, 5687, 5741, 5787, 5839, 5887, 5930, 5974, 6002, 6016, 6034, 6070, 6093, 6116, 6138, 6166, 6189, 6207, 6234, 6266} func (i APIErrorCode) String() string { if i < 0 || i >= APIErrorCode(len(_APIErrorCode_index)-1) { diff --git a/internal/config/config.go b/internal/config/config.go index 4be94ee51..52052cc34 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1100,6 +1100,10 @@ func (c Config) ResolveConfigParam(subSys, target, cfgParam string) (value strin } defValue, isFound := defKVS.Lookup(cfgParam) + // Comments usually are absent from `defKVS`, so we handle it specially. + if cfgParam == Comment { + defValue, isFound = "", true + } if !isFound { return } @@ -1134,3 +1138,54 @@ func (c Config) ResolveConfigParam(subSys, target, cfgParam string) (value strin cs = ValueSourceDef return } + +// KVSrc represents a configuration parameter key and value along with the +// source of the value. +type KVSrc struct { + Key string + Value string + Src ValueSource +} + +// GetResolvedConfigParams returns all applicable config parameters with their +// value sources. +func (c Config) GetResolvedConfigParams(subSys, target string) ([]KVSrc, error) { + // Initially only support OpenID + if !resolvableSubsystems.Contains(subSys) { + return nil, fmt.Errorf("unsupported subsystem: %s", subSys) + } + + // Check if config param requested is valid. + defKVS, ok := DefaultKVS[subSys] + if !ok { + return nil, fmt.Errorf("unknown subsystem: %s", subSys) + } + + r := make([]KVSrc, 0, len(defKVS)+1) + for _, kv := range defKVS { + v, vs := c.ResolveConfigParam(subSys, target, kv.Key) + + // Fix `vs` when default. + if v == kv.Value { + vs = ValueSourceDef + } + + r = append(r, KVSrc{ + Key: kv.Key, + Value: v, + Src: vs, + }) + } + + // Add the comment key as well if non-empty. + v, vs := c.ResolveConfigParam(subSys, target, Comment) + if vs != ValueSourceDef { + r = append(r, KVSrc{ + Key: Comment, + Value: v, + Src: vs, + }) + } + + return r, nil +} diff --git a/internal/config/identity/openid/help.go b/internal/config/identity/openid/help.go index 6ad718540..57d1b2f51 100644 --- a/internal/config/identity/openid/help.go +++ b/internal/config/identity/openid/help.go @@ -52,6 +52,7 @@ var ( config.HelpKV{ Key: ClientSecret, Description: `secret for the unique public identifier for apps` + defaultHelpPostfix(ClientSecret), + Sensitive: true, Type: "string", }, config.HelpKV{ diff --git a/internal/config/identity/openid/openid.go b/internal/config/identity/openid/openid.go index 752e5cd0b..fd77b0510 100644 --- a/internal/config/identity/openid/openid.go +++ b/internal/config/identity/openid/openid.go @@ -24,6 +24,7 @@ import ( "errors" "io" "net/http" + "sort" "strconv" "strings" "sync" @@ -391,6 +392,107 @@ func LookupConfig(s config.Config, transport http.RoundTripper, closeRespFn func return c, nil } +// ErrProviderConfigNotFound - represents a non-existing provider error. +var ErrProviderConfigNotFound = errors.New("provider configuration not found") + +// GetConfigInfo - returns configuration and related info for the given IDP +// provider. +func (r *Config) GetConfigInfo(s config.Config, cfgName string) ([]madmin.IDPCfgInfo, error) { + openIDConfigs, err := s.GetAvailableTargets(config.IdentityOpenIDSubSys) + if err != nil { + return nil, err + } + + present := false + for _, cfg := range openIDConfigs { + if cfg == cfgName { + present = true + break + } + } + + if !present { + return nil, ErrProviderConfigNotFound + } + + kvsrcs, err := s.GetResolvedConfigParams(config.IdentityOpenIDSubSys, cfgName) + if err != nil { + return nil, err + } + + res := make([]madmin.IDPCfgInfo, 0, len(kvsrcs)+1) + for _, kvsrc := range kvsrcs { + // skip default values. + if kvsrc.Src == config.ValueSourceDef { + if kvsrc.Key != madmin.EnableKey { + continue + } + // set an explicit on/off from live configuration. + kvsrc.Value = "off" + if _, ok := r.ProviderCfgs[cfgName]; ok { + if r.Enabled { + kvsrc.Value = "on" + } + } + } + res = append(res, madmin.IDPCfgInfo{ + Key: kvsrc.Key, + Value: kvsrc.Value, + IsCfg: true, + IsEnv: kvsrc.Src == config.ValueSourceEnv, + }) + } + + if provCfg, exists := r.ProviderCfgs[cfgName]; exists && provCfg.RolePolicy != "" { + // Append roleARN + res = append(res, madmin.IDPCfgInfo{ + Key: "roleARN", + Value: provCfg.roleArn.String(), + IsCfg: false, + }) + } + + // sort the structs by the key + sort.Slice(res, func(i, j int) bool { + return res[i].Key < res[j].Key + }) + + return res, nil +} + +// GetConfigList - list openID configurations +func (r *Config) GetConfigList(s config.Config) ([]madmin.IDPListItem, error) { + openIDConfigs, err := s.GetAvailableTargets(config.IdentityOpenIDSubSys) + if err != nil { + return nil, err + } + + var res []madmin.IDPListItem + for _, cfg := range openIDConfigs { + pcfg, ok := r.ProviderCfgs[cfg] + if !ok { + res = append(res, madmin.IDPListItem{ + Type: "openid", + Name: cfg, + Enabled: false, + }) + } else { + var roleARN string + if pcfg.RolePolicy != "" { + roleARN = pcfg.roleArn.String() + } + res = append(res, madmin.IDPListItem{ + Type: "openid", + Name: cfg, + Enabled: r.Enabled, + RoleARN: roleARN, + }) + } + } + + return res, nil +} + // Enabled returns if configURL is enabled. func Enabled(kvs config.KVS) bool { return kvs.Get(ConfigURL) != ""