assumeRole return the correct http code for auth errors (#16967)

This commit is contained in:
Anis Eleuch 2023-04-06 06:19:31 +01:00 committed by GitHub
parent 62c3df0ca3
commit 111c7d4026
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 85 deletions

View file

@ -371,7 +371,7 @@ func deleteObjectVersions(ctx context.Context, o ObjectLayer, bucket string, toD
auditLogLifecycle( auditLogLifecycle(
ctx, ctx,
ObjectInfo{ ObjectInfo{
Bucket: bucket, Bucket: bucket,
Name: dobj.ObjectName, Name: dobj.ObjectName,
VersionID: dobj.VersionID, VersionID: dobj.VersionID,
}, },

View file

@ -27,19 +27,9 @@ import (
) )
// writeSTSErrorRespone writes error headers // writeSTSErrorRespone writes error headers
func writeSTSErrorResponse(ctx context.Context, w http.ResponseWriter, isErrCodeSTS bool, errCode STSErrorCode, errCtxt error) { func writeSTSErrorResponse(ctx context.Context, w http.ResponseWriter, errCode STSErrorCode, errCtxt error) {
var err STSError err := stsErrCodes.ToSTSErr(errCode)
if isErrCodeSTS {
err = stsErrCodes.ToSTSErr(errCode)
}
if err.Code == "InternalError" || !isErrCodeSTS {
aerr := errorCodes.ToAPIErr(toAPIErrorCode(ctx, errCtxt))
if aerr.Code != "InternalError" {
err.Code = aerr.Code
err.Description = aerr.Description
err.HTTPStatusCode = aerr.HTTPStatusCode
}
}
// Generate error response. // Generate error response.
stsErrorResponse := STSErrorResponse{} stsErrorResponse := STSErrorResponse{}
stsErrorResponse.Error.Code = err.Code stsErrorResponse.Error.Code = err.Code

View file

@ -137,32 +137,45 @@ func registerSTSRouter(router *mux.Router) {
Queries(stsVersion, stsAPIVersion) Queries(stsVersion, stsAPIVersion)
} }
func checkAssumeRoleAuth(ctx context.Context, r *http.Request) (user auth.Credentials, isErrCodeSTS bool, stsErr STSErrorCode) { func apiToSTSError(authErr APIErrorCode) (stsErrCode STSErrorCode) {
switch authErr {
case ErrSignatureDoesNotMatch, ErrInvalidAccessKeyID, ErrAccessKeyDisabled:
return ErrSTSAccessDenied
case ErrServerNotInitialized:
return ErrSTSNotInitialized
case ErrInternalError:
return ErrSTSInternalError
default:
return ErrSTSAccessDenied
}
}
func checkAssumeRoleAuth(ctx context.Context, r *http.Request) (auth.Credentials, APIErrorCode) {
if !isRequestSignatureV4(r) { if !isRequestSignatureV4(r) {
return user, true, ErrSTSAccessDenied return auth.Credentials{}, ErrAccessDenied
} }
s3Err := isReqAuthenticated(ctx, r, globalSite.Region, serviceSTS) s3Err := isReqAuthenticated(ctx, r, globalSite.Region, serviceSTS)
if s3Err != ErrNone { if s3Err != ErrNone {
return user, false, STSErrorCode(s3Err) return auth.Credentials{}, s3Err
} }
user, _, s3Err = getReqAccessKeyV4(r, globalSite.Region, serviceSTS) user, _, s3Err := getReqAccessKeyV4(r, globalSite.Region, serviceSTS)
if s3Err != ErrNone { if s3Err != ErrNone {
return user, false, STSErrorCode(s3Err) return auth.Credentials{}, s3Err
} }
// Temporary credentials or Service accounts cannot generate further temporary credentials. // Temporary credentials or Service accounts cannot generate further temporary credentials.
if user.IsTemp() || user.IsServiceAccount() { if user.IsTemp() || user.IsServiceAccount() {
return user, true, ErrSTSAccessDenied return auth.Credentials{}, ErrAccessDenied
} }
// Session tokens are not allowed in STS AssumeRole requests. // Session tokens are not allowed in STS AssumeRole requests.
if getSessionToken(r) != "" { if getSessionToken(r) != "" {
return user, true, ErrSTSAccessDenied return auth.Credentials{}, ErrAccessDenied
} }
return user, true, ErrSTSNone return user, ErrNone
} }
func parseForm(r *http.Request) error { func parseForm(r *http.Request) error {
@ -190,15 +203,15 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
// the call to `parseForm` below), but return failure only after we are // the call to `parseForm` below), but return failure only after we are
// able to validate that it is a valid STS request, so that we are able // able to validate that it is a valid STS request, so that we are able
// to send an appropriate audit log. // to send an appropriate audit log.
user, isErrCodeSTS, stsErr := checkAssumeRoleAuth(ctx, r) user, apiErrCode := checkAssumeRoleAuth(ctx, r)
if err := parseForm(r); err != nil { if err := parseForm(r); err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
if r.Form.Get(stsVersion) != stsAPIVersion { if r.Form.Get(stsVersion) != stsAPIVersion {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get(stsVersion), stsAPIVersion)) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get(stsVersion), stsAPIVersion))
return return
} }
@ -206,16 +219,17 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
switch action { switch action {
case assumeRole: case assumeRole:
default: default:
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action)) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
return return
} }
ctx = newContext(r, w, action) ctx = newContext(r, w, action)
// Validate the authentication result here so that failures will be // Validate the authentication result here so that failures will be audit-logged.
// audit-logged. if apiErrCode != ErrNone {
if stsErr != ErrSTSNone { stsErr := apiToSTSError(apiErrCode)
writeSTSErrorResponse(ctx, w, isErrCodeSTS, stsErr, nil) // Borrow the description error from the API error code
writeSTSErrorResponse(ctx, w, stsErr, fmt.Errorf(errorCodes[apiErrCode].Description))
return return
} }
@ -224,27 +238,27 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
// The plain text that you use for both inline and managed session // The plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. // policies shouldn't exceed 2048 characters.
if len(sessionPolicyStr) > 2048 { if len(sessionPolicyStr) > 2048 {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy shouldn't exceed 2048 characters")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy shouldn't exceed 2048 characters"))
return return
} }
if len(sessionPolicyStr) > 0 { if len(sessionPolicyStr) > 0 {
sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr))) sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
// Version in policy must not be empty // Version in policy must not be empty
if sessionPolicy.Version == "" { if sessionPolicy.Version == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Version cannot be empty expecting '2012-10-17'")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Version cannot be empty expecting '2012-10-17'"))
return return
} }
} }
duration, err := openid.GetDefaultExpiration(r.Form.Get(stsDurationSeconds)) duration, err := openid.GetDefaultExpiration(r.Form.Get(stsDurationSeconds))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
@ -254,7 +268,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
// Validate that user.AccessKey's policies can be retrieved - it may not // Validate that user.AccessKey's policies can be retrieved - it may not
// be in case the user is disabled. // be in case the user is disabled.
if _, err = globalIAMSys.PolicyDBGet(user.AccessKey, false); err != nil { if _, err = globalIAMSys.PolicyDBGet(user.AccessKey, false); err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
@ -265,7 +279,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
secret := globalActiveCred.SecretKey secret := globalActiveCred.SecretKey
cred, err := auth.GetNewCredentialsWithMetadata(claims, secret) cred, err := auth.GetNewCredentialsWithMetadata(claims, secret)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -276,7 +290,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
// Set the newly generated credentials. // Set the newly generated credentials.
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "") updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "")
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -312,12 +326,12 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
// Parse the incoming form data. // Parse the incoming form data.
if err := parseForm(r); err != nil { if err := parseForm(r); err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
if r.Form.Get(stsVersion) != stsAPIVersion { if r.Form.Get(stsVersion) != stsAPIVersion {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion)) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion))
return return
} }
@ -328,7 +342,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
return return
case clientGrants, webIdentity: case clientGrants, webIdentity:
default: default:
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action)) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
return return
} }
@ -354,7 +368,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
var err error var err error
roleArn, _, err = globalIAMSys.GetRolePolicy(roleArnStr) roleArn, _, err = globalIAMSys.GetRolePolicy(roleArnStr)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
fmt.Errorf("Error processing %s parameter: %v", stsRoleArn, err)) fmt.Errorf("Error processing %s parameter: %v", stsRoleArn, err))
return return
} }
@ -366,16 +380,16 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
case openid.ErrTokenExpired: case openid.ErrTokenExpired:
switch action { switch action {
case clientGrants: case clientGrants:
writeSTSErrorResponse(ctx, w, true, ErrSTSClientGrantsExpiredToken, err) writeSTSErrorResponse(ctx, w, ErrSTSClientGrantsExpiredToken, err)
case webIdentity: case webIdentity:
writeSTSErrorResponse(ctx, w, true, ErrSTSWebIdentityExpiredToken, err) writeSTSErrorResponse(ctx, w, ErrSTSWebIdentityExpiredToken, err)
} }
return return
case auth.ErrInvalidDuration: case auth.ErrInvalidDuration:
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
@ -397,11 +411,11 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
if newGlobalAuthZPluginFn() == nil { if newGlobalAuthZPluginFn() == nil {
if !ok { if !ok {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID())) fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID()))
return return
} else if policyName == "" { } else if policyName == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
fmt.Errorf("None of the given policies (`%s`) are defined, credentials will not be generated", policies)) fmt.Errorf("None of the given policies (`%s`) are defined, credentials will not be generated", policies))
return return
} }
@ -414,20 +428,20 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
// The plain text that you use for both inline and managed session // The plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. // policies shouldn't exceed 2048 characters.
if len(sessionPolicyStr) > 2048 { if len(sessionPolicyStr) > 2048 {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters"))
return return
} }
if len(sessionPolicyStr) > 0 { if len(sessionPolicyStr) > 0 {
sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr))) sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
// Version in policy must not be empty // Version in policy must not be empty
if sessionPolicy.Version == "" { if sessionPolicy.Version == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid session policy version")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid session policy version"))
return return
} }
@ -437,7 +451,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
secret := globalActiveCred.SecretKey secret := globalActiveCred.SecretKey
cred, err := auth.GetNewCredentialsWithMetadata(claims, secret) cred, err := auth.GetNewCredentialsWithMetadata(claims, secret)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -452,7 +466,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
} }
if subFromToken == "" { if subFromToken == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
errors.New("STS JWT Token has `sub` claim missing, `sub` claim is mandatory")) errors.New("STS JWT Token has `sub` claim missing, `sub` claim is mandatory"))
return return
} }
@ -477,7 +491,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
// Set the newly generated credentials. // Set the newly generated credentials.
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, policyName) updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, policyName)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -549,12 +563,12 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
// Parse the incoming form data. // Parse the incoming form data.
if err := parseForm(r); err != nil { if err := parseForm(r); err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
if r.Form.Get(stsVersion) != stsAPIVersion { if r.Form.Get(stsVersion) != stsAPIVersion {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter,
fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion)) fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion))
return return
} }
@ -563,7 +577,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
ldapPassword := r.Form.Get(stsLDAPPassword) ldapPassword := r.Form.Get(stsLDAPPassword)
if ldapUsername == "" || ldapPassword == "" { if ldapUsername == "" || ldapPassword == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("LDAPUsername and LDAPPassword cannot be empty")) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, fmt.Errorf("LDAPUsername and LDAPPassword cannot be empty"))
return return
} }
@ -571,7 +585,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
switch action { switch action {
case ldapIdentity: case ldapIdentity:
default: default:
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action)) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
return return
} }
@ -580,20 +594,20 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
// The plain text that you use for both inline and managed session // The plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. // policies shouldn't exceed 2048 characters.
if len(sessionPolicyStr) > 2048 { if len(sessionPolicyStr) > 2048 {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters"))
return return
} }
if len(sessionPolicyStr) > 0 { if len(sessionPolicyStr) > 0 {
sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr))) sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
// Version in policy must not be empty // Version in policy must not be empty
if sessionPolicy.Version == "" { if sessionPolicy.Version == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Version needs to be specified in session policy")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Version needs to be specified in session policy"))
return return
} }
} }
@ -601,14 +615,14 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
ldapUserDN, groupDistNames, err := globalIAMSys.LDAPConfig.Bind(ldapUsername, ldapPassword) ldapUserDN, groupDistNames, err := globalIAMSys.LDAPConfig.Bind(ldapUsername, ldapPassword)
if err != nil { if err != nil {
err = fmt.Errorf("LDAP server error: %w", err) err = fmt.Errorf("LDAP server error: %w", err)
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
// Check if this user or their groups have a policy applied. // Check if this user or their groups have a policy applied.
ldapPolicies, _ := globalIAMSys.PolicyDBGet(ldapUserDN, false, groupDistNames...) ldapPolicies, _ := globalIAMSys.PolicyDBGet(ldapUserDN, false, groupDistNames...)
if len(ldapPolicies) == 0 && newGlobalAuthZPluginFn() == nil { if len(ldapPolicies) == 0 && newGlobalAuthZPluginFn() == nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
fmt.Errorf("expecting a policy to be set for user `%s` or one of their groups: `%s` - rejecting this request", fmt.Errorf("expecting a policy to be set for user `%s` or one of their groups: `%s` - rejecting this request",
ldapUserDN, strings.Join(groupDistNames, "`,`"))) ldapUserDN, strings.Join(groupDistNames, "`,`")))
return return
@ -616,7 +630,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
expiryDur, err := globalIAMSys.LDAPConfig.GetExpiryDuration(r.Form.Get(stsDurationSeconds)) expiryDur, err := globalIAMSys.LDAPConfig.GetExpiryDuration(r.Form.Get(stsDurationSeconds))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
@ -631,7 +645,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
secret := globalActiveCred.SecretKey secret := globalActiveCred.SecretKey
cred, err := auth.GetNewCredentialsWithMetadata(claims, secret) cred, err := auth.GetNewCredentialsWithMetadata(claims, secret)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -648,7 +662,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
// mapping. // mapping.
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "") updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "")
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -687,7 +701,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
defer logger.AuditLog(ctx, w, r, claims) defer logger.AuditLog(ctx, w, r, claims)
if !globalIAMSys.STSTLSConfig.Enabled { if !globalIAMSys.STSTLSConfig.Enabled {
writeSTSErrorResponse(ctx, w, true, ErrSTSNotInitialized, errors.New("STS API 'AssumeRoleWithCertificate' is disabled")) writeSTSErrorResponse(ctx, w, ErrSTSNotInitialized, errors.New("STS API 'AssumeRoleWithCertificate' is disabled"))
return return
} }
@ -696,7 +710,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
// Otherwise, we don't have a certificate to verify or // Otherwise, we don't have a certificate to verify or
// the policy lookup would ambigious. // the policy lookup would ambigious.
if r.TLS == nil { if r.TLS == nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInsecureConnection, errors.New("No TLS connection attempt")) writeSTSErrorResponse(ctx, w, ErrSTSInsecureConnection, errors.New("No TLS connection attempt"))
return return
} }
@ -718,11 +732,11 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
// Now, we have to check that the client has provided exactly one leaf // Now, we have to check that the client has provided exactly one leaf
// certificate that we can map to a policy. // certificate that we can map to a policy.
if len(r.TLS.PeerCertificates) == 0 { if len(r.TLS.PeerCertificates) == 0 {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, errors.New("No client certificate provided")) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, errors.New("No client certificate provided"))
return return
} }
if len(r.TLS.PeerCertificates) > 1 { if len(r.TLS.PeerCertificates) > 1 {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, errors.New("More than one client certificate provided")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, errors.New("More than one client certificate provided"))
return return
} }
@ -735,7 +749,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
Roots: globalRootCAs, Roots: globalRootCAs,
}) })
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidClientCertificate, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidClientCertificate, err)
return return
} }
} else { } else {
@ -760,7 +774,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
} }
} }
if !validKeyUsage { if !validKeyUsage {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, errors.New("certificate is not valid for client authentication")) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, errors.New("certificate is not valid for client authentication"))
return return
} }
} }
@ -772,13 +786,13 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
// //
// Group mapping is not possible with standard X.509 certificates. // Group mapping is not possible with standard X.509 certificates.
if certificate.Subject.CommonName == "" { if certificate.Subject.CommonName == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, errors.New("certificate subject CN cannot be empty")) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, errors.New("certificate subject CN cannot be empty"))
return return
} }
expiry, err := globalIAMSys.STSTLSConfig.GetExpiryDuration(r.Form.Get(stsDurationSeconds)) expiry, err := globalIAMSys.STSTLSConfig.GetExpiryDuration(r.Form.Get(stsDurationSeconds))
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, err) writeSTSErrorResponse(ctx, w, ErrSTSMissingParameter, err)
return return
} }
@ -801,7 +815,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
tmpCredentials, err := auth.GetNewCredentialsWithMetadata(claims, globalActiveCred.SecretKey) tmpCredentials, err := auth.GetNewCredentialsWithMetadata(claims, globalActiveCred.SecretKey)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -809,7 +823,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
policyName := certificate.Subject.CommonName policyName := certificate.Subject.CommonName
updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, policyName) updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, policyName)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
@ -845,19 +859,19 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
authn := newGlobalAuthNPluginFn() authn := newGlobalAuthNPluginFn()
if authn == nil { if authn == nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSNotInitialized, errors.New("STS API 'AssumeRoleWithCustomToken' is disabled")) writeSTSErrorResponse(ctx, w, ErrSTSNotInitialized, errors.New("STS API 'AssumeRoleWithCustomToken' is disabled"))
return return
} }
action := r.Form.Get(stsAction) action := r.Form.Get(stsAction)
if action != customTokenIdentity { if action != customTokenIdentity {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action)) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
return return
} }
token := r.Form.Get(stsToken) token := r.Form.Get(stsToken)
if token == "" { if token == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid empty `Token` parameter provided")) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid empty `Token` parameter provided"))
return return
} }
@ -867,7 +881,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
var err error var err error
requestedDuration, err = strconv.Atoi(durationParam) requestedDuration, err = strconv.Atoi(durationParam)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid requested duration: %s", durationParam)) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid requested duration: %s", durationParam))
return return
} }
} }
@ -875,26 +889,26 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
roleArnStr := r.Form.Get(stsRoleArn) roleArnStr := r.Form.Get(stsRoleArn)
roleArn, _, err := globalIAMSys.GetRolePolicy(roleArnStr) roleArn, _, err := globalIAMSys.GetRolePolicy(roleArnStr)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue,
fmt.Errorf("Error processing parameter %s: %v", stsRoleArn, err)) fmt.Errorf("Error processing parameter %s: %v", stsRoleArn, err))
return return
} }
res, err := authn.Authenticate(roleArn, token) res, err := authn.Authenticate(roleArn, token)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
return return
} }
// If authentication failed, return the error message to the user. // If authentication failed, return the error message to the user.
if res.Failure != nil { if res.Failure != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSUpstreamError, errors.New(res.Failure.Reason)) writeSTSErrorResponse(ctx, w, ErrSTSUpstreamError, errors.New(res.Failure.Reason))
return return
} }
// It is required that parent user be set. // It is required that parent user be set.
if res.Success.User == "" { if res.Success.User == "" {
writeSTSErrorResponse(ctx, w, true, ErrSTSUpstreamError, errors.New("A valid user was not returned by the authenticator.")) writeSTSErrorResponse(ctx, w, ErrSTSUpstreamError, errors.New("A valid user was not returned by the authenticator."))
return return
} }
@ -923,14 +937,14 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
tmpCredentials, err := auth.GetNewCredentialsWithMetadata(claims, globalActiveCred.SecretKey) tmpCredentials, err := auth.GetNewCredentialsWithMetadata(claims, globalActiveCred.SecretKey)
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }
tmpCredentials.ParentUser = parentUser tmpCredentials.ParentUser = parentUser
updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, "") updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, "")
if err != nil { if err != nil {
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err) writeSTSErrorResponse(ctx, w, ErrSTSInternalError, err)
return return
} }