mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
Allow region errors to be dynamic (#10323)
remove other FIXMEs as we are not planning to fix these, instead we will add dynamism case by case basis. fixes #10250
This commit is contained in:
parent
d0c910a6f3
commit
11aa393ba7
@ -663,20 +663,9 @@ var errorCodes = errorCodeMap{
|
|||||||
Description: "X-Amz-Date must be in the ISO8601 Long Format \"yyyyMMdd'T'HHmmss'Z'\"",
|
Description: "X-Amz-Date must be in the ISO8601 Long Format \"yyyyMMdd'T'HHmmss'Z'\"",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// FIXME: Should contain the invalid param set as seen in https://github.com/minio/minio/issues/2385.
|
|
||||||
// right Description: "Error parsing the X-Amz-Credential parameter; incorrect date format \"%s\". This date in the credential must be in the format \"yyyyMMdd\".",
|
|
||||||
// Need changes to make sure variable messages can be constructed.
|
|
||||||
ErrMalformedCredentialDate: {
|
ErrMalformedCredentialDate: {
|
||||||
Code: "AuthorizationQueryParametersError",
|
Code: "AuthorizationQueryParametersError",
|
||||||
Description: "Error parsing the X-Amz-Credential parameter; incorrect date format \"%s\". This date in the credential must be in the format \"yyyyMMdd\".",
|
Description: "Error parsing the X-Amz-Credential parameter; incorrect date format. This date in the credential must be in the format \"yyyyMMdd\".",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
|
||||||
},
|
|
||||||
// FIXME: Should contain the invalid param set as seen in https://github.com/minio/minio/issues/2385.
|
|
||||||
// right Description: "Error parsing the X-Amz-Credential parameter; the region 'us-east-' is wrong; expecting 'us-east-1'".
|
|
||||||
// Need changes to make sure variable messages can be constructed.
|
|
||||||
ErrMalformedCredentialRegion: {
|
|
||||||
Code: "AuthorizationQueryParametersError",
|
|
||||||
Description: "Error parsing the X-Amz-Credential parameter; the region is wrong;",
|
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
ErrInvalidRegion: {
|
ErrInvalidRegion: {
|
||||||
@ -684,9 +673,6 @@ var errorCodes = errorCodeMap{
|
|||||||
Description: "Region does not match.",
|
Description: "Region does not match.",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// FIXME: Should contain the invalid param set as seen in https://github.com/minio/minio/issues/2385.
|
|
||||||
// right Description: "Error parsing the X-Amz-Credential parameter; incorrect service \"s4\". This endpoint belongs to \"s3\".".
|
|
||||||
// Need changes to make sure variable messages can be constructed.
|
|
||||||
ErrInvalidServiceS3: {
|
ErrInvalidServiceS3: {
|
||||||
Code: "AuthorizationParametersError",
|
Code: "AuthorizationParametersError",
|
||||||
Description: "Error parsing the Credential/X-Amz-Credential parameter; incorrect service. This endpoint belongs to \"s3\".",
|
Description: "Error parsing the Credential/X-Amz-Credential parameter; incorrect service. This endpoint belongs to \"s3\".",
|
||||||
@ -697,9 +683,6 @@ var errorCodes = errorCodeMap{
|
|||||||
Description: "Error parsing the Credential parameter; incorrect service. This endpoint belongs to \"sts\".",
|
Description: "Error parsing the Credential parameter; incorrect service. This endpoint belongs to \"sts\".",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// FIXME: Should contain the invalid param set as seen in https://github.com/minio/minio/issues/2385.
|
|
||||||
// Description: "Error parsing the X-Amz-Credential parameter; incorrect terminal "aws4_reque". This endpoint uses "aws4_request".
|
|
||||||
// Need changes to make sure variable messages can be constructed.
|
|
||||||
ErrInvalidRequestVersion: {
|
ErrInvalidRequestVersion: {
|
||||||
Code: "AuthorizationQueryParametersError",
|
Code: "AuthorizationQueryParametersError",
|
||||||
Description: "Error parsing the X-Amz-Credential parameter; incorrect terminal. This endpoint uses \"aws4_request\".",
|
Description: "Error parsing the X-Amz-Credential parameter; incorrect terminal. This endpoint uses \"aws4_request\".",
|
||||||
@ -770,8 +753,6 @@ var errorCodes = errorCodeMap{
|
|||||||
Description: "Your key is too long",
|
Description: "Your key is too long",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
|
|
||||||
// FIXME: Actual XML error response also contains the header which missed in list of signed header parameters.
|
|
||||||
ErrUnsignedHeaders: {
|
ErrUnsignedHeaders: {
|
||||||
Code: "AccessDenied",
|
Code: "AccessDenied",
|
||||||
Description: "There were headers present in the request which were not signed",
|
Description: "There were headers present in the request which were not signed",
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@ -763,6 +764,10 @@ func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError
|
|||||||
// Set retry-after header to indicate user-agents to retry request after 120secs.
|
// Set retry-after header to indicate user-agents to retry request after 120secs.
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
||||||
w.Header().Set(xhttp.RetryAfter, "120")
|
w.Header().Set(xhttp.RetryAfter, "120")
|
||||||
|
case "InvalidRegion":
|
||||||
|
err.Description = fmt.Sprintf("Region does not match; expecting '%s'.", globalServerRegion)
|
||||||
|
case "AuthorizationHeaderMalformed":
|
||||||
|
err.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalServerRegion)
|
||||||
case "AccessDenied":
|
case "AccessDenied":
|
||||||
// The request is from browser and also if browser
|
// The request is from browser and also if browser
|
||||||
// is enabled we need to redirect.
|
// is enabled we need to redirect.
|
||||||
@ -821,38 +826,3 @@ func writeCustomErrorResponseJSON(ctx context.Context, w http.ResponseWriter, er
|
|||||||
encodedErrorResponse := encodeResponseJSON(errorResponse)
|
encodedErrorResponse := encodeResponseJSON(errorResponse)
|
||||||
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON)
|
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeCustomErrorResponseXML - similar to writeErrorResponse,
|
|
||||||
// but accepts the error message directly (this allows messages to be
|
|
||||||
// dynamically generated.)
|
|
||||||
func writeCustomErrorResponseXML(ctx context.Context, w http.ResponseWriter, err APIError, errBody string, reqURL *url.URL, browser bool) {
|
|
||||||
|
|
||||||
switch err.Code {
|
|
||||||
case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum":
|
|
||||||
// Set retry-after header to indicate user-agents to retry request after 120secs.
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
|
||||||
w.Header().Set(xhttp.RetryAfter, "120")
|
|
||||||
case "AccessDenied":
|
|
||||||
// The request is from browser and also if browser
|
|
||||||
// is enabled we need to redirect.
|
|
||||||
if browser && globalBrowserEnabled {
|
|
||||||
w.Header().Set(xhttp.Location, minioReservedBucketPath+reqURL.Path)
|
|
||||||
w.WriteHeader(http.StatusTemporaryRedirect)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reqInfo := logger.GetReqInfo(ctx)
|
|
||||||
errorResponse := APIErrorResponse{
|
|
||||||
Code: err.Code,
|
|
||||||
Message: errBody,
|
|
||||||
Resource: reqURL.Path,
|
|
||||||
BucketName: reqInfo.BucketName,
|
|
||||||
Key: reqInfo.ObjectName,
|
|
||||||
RequestID: w.Header().Get(xhttp.AmzRequestID),
|
|
||||||
HostID: globalDeploymentID,
|
|
||||||
}
|
|
||||||
|
|
||||||
encodedErrorResponse := encodeResponse(errorResponse)
|
|
||||||
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML)
|
|
||||||
}
|
|
||||||
|
@ -762,7 +762,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
|
|
||||||
// Make sure formValues adhere to policy restrictions.
|
// Make sure formValues adhere to policy restrictions.
|
||||||
if err = checkPostPolicy(formValues, postPolicyForm); err != nil {
|
if err = checkPostPolicy(formValues, postPolicyForm); err != nil {
|
||||||
writeCustomErrorResponseXML(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), err.Error(), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErrWithErr(ErrAccessDenied, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
|||||||
{
|
{
|
||||||
objectName: "test",
|
objectName: "test",
|
||||||
data: []byte("Hello, World"),
|
data: []byte("Hello, World"),
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
expectedRespStatus: http.StatusForbidden,
|
||||||
accessKey: "",
|
accessKey: "",
|
||||||
secretKey: "",
|
secretKey: "",
|
||||||
malformedBody: false,
|
malformedBody: false,
|
||||||
@ -293,7 +293,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
|||||||
{
|
{
|
||||||
objectName: "test",
|
objectName: "test",
|
||||||
data: []byte("Hello, World"),
|
data: []byte("Hello, World"),
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
expectedRespStatus: http.StatusForbidden,
|
||||||
accessKey: "",
|
accessKey: "",
|
||||||
secretKey: "",
|
secretKey: "",
|
||||||
dates: []interface{}{},
|
dates: []interface{}{},
|
||||||
|
@ -49,17 +49,17 @@ func (c credentialHeader) getScope() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getReqAccessKeyV4(r *http.Request, region string, stype serviceType) (auth.Credentials, bool, APIErrorCode) {
|
func getReqAccessKeyV4(r *http.Request, region string, stype serviceType) (auth.Credentials, bool, APIErrorCode) {
|
||||||
ch, err := parseCredentialHeader("Credential="+r.URL.Query().Get(xhttp.AmzCredential), region, stype)
|
ch, s3Err := parseCredentialHeader("Credential="+r.URL.Query().Get(xhttp.AmzCredential), region, stype)
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
// Strip off the Algorithm prefix.
|
// Strip off the Algorithm prefix.
|
||||||
v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm)
|
v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm)
|
||||||
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
|
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
|
||||||
if len(authFields) != 3 {
|
if len(authFields) != 3 {
|
||||||
return auth.Credentials{}, false, ErrMissingFields
|
return auth.Credentials{}, false, ErrMissingFields
|
||||||
}
|
}
|
||||||
ch, err = parseCredentialHeader(authFields[0], region, stype)
|
ch, s3Err = parseCredentialHeader(authFields[0], region, stype)
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return auth.Credentials{}, false, err
|
return auth.Credentials{}, false, s3Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return checkKeyValid(ch.accessKey)
|
return checkKeyValid(ch.accessKey)
|
||||||
@ -192,9 +192,9 @@ func doesV4PresignParamsExist(query url.Values) APIErrorCode {
|
|||||||
// Parses all the presigned signature values into separate elements.
|
// Parses all the presigned signature values into separate elements.
|
||||||
func parsePreSignV4(query url.Values, region string, stype serviceType) (psv preSignValues, aec APIErrorCode) {
|
func parsePreSignV4(query url.Values, region string, stype serviceType) (psv preSignValues, aec APIErrorCode) {
|
||||||
// verify whether the required query params exist.
|
// verify whether the required query params exist.
|
||||||
err := doesV4PresignParamsExist(query)
|
aec = doesV4PresignParamsExist(query)
|
||||||
if err != ErrNone {
|
if aec != ErrNone {
|
||||||
return psv, err
|
return psv, aec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the query algorithm is supported or not.
|
// Verify if the query algorithm is supported or not.
|
||||||
@ -206,9 +206,9 @@ func parsePreSignV4(query url.Values, region string, stype serviceType) (psv pre
|
|||||||
preSignV4Values := preSignValues{}
|
preSignV4Values := preSignValues{}
|
||||||
|
|
||||||
// Save credential.
|
// Save credential.
|
||||||
preSignV4Values.Credential, err = parseCredentialHeader("Credential="+query.Get(xhttp.AmzCredential), region, stype)
|
preSignV4Values.Credential, aec = parseCredentialHeader("Credential="+query.Get(xhttp.AmzCredential), region, stype)
|
||||||
if err != ErrNone {
|
if aec != ErrNone {
|
||||||
return psv, err
|
return psv, aec
|
||||||
}
|
}
|
||||||
|
|
||||||
var e error
|
var e error
|
||||||
@ -234,15 +234,15 @@ func parsePreSignV4(query url.Values, region string, stype serviceType) (psv pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save signed headers.
|
// Save signed headers.
|
||||||
preSignV4Values.SignedHeaders, err = parseSignedHeader("SignedHeaders=" + query.Get(xhttp.AmzSignedHeaders))
|
preSignV4Values.SignedHeaders, aec = parseSignedHeader("SignedHeaders=" + query.Get(xhttp.AmzSignedHeaders))
|
||||||
if err != ErrNone {
|
if aec != ErrNone {
|
||||||
return psv, err
|
return psv, aec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save signature.
|
// Save signature.
|
||||||
preSignV4Values.Signature, err = parseSignature("Signature=" + query.Get(xhttp.AmzSignature))
|
preSignV4Values.Signature, aec = parseSignature("Signature=" + query.Get(xhttp.AmzSignature))
|
||||||
if err != ErrNone {
|
if aec != ErrNone {
|
||||||
return psv, err
|
return psv, aec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return structed form of signature query string.
|
// Return structed form of signature query string.
|
||||||
@ -280,23 +280,23 @@ func parseSignV4(v4Auth string, region string, stype serviceType) (sv signValues
|
|||||||
// Initialize signature version '4' structured header.
|
// Initialize signature version '4' structured header.
|
||||||
signV4Values := signValues{}
|
signV4Values := signValues{}
|
||||||
|
|
||||||
var err APIErrorCode
|
var s3Err APIErrorCode
|
||||||
// Save credentail values.
|
// Save credentail values.
|
||||||
signV4Values.Credential, err = parseCredentialHeader(strings.TrimSpace(credElement), region, stype)
|
signV4Values.Credential, s3Err = parseCredentialHeader(strings.TrimSpace(credElement), region, stype)
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return sv, err
|
return sv, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save signed headers.
|
// Save signed headers.
|
||||||
signV4Values.SignedHeaders, err = parseSignedHeader(authFields[1])
|
signV4Values.SignedHeaders, s3Err = parseSignedHeader(authFields[1])
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return sv, err
|
return sv, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save signature.
|
// Save signature.
|
||||||
signV4Values.Signature, err = parseSignature(authFields[2])
|
signV4Values.Signature, s3Err = parseSignature(authFields[2])
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return sv, err
|
return sv, s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the structure here.
|
// Return the structure here.
|
||||||
|
@ -173,9 +173,9 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
|
|||||||
region := globalServerRegion
|
region := globalServerRegion
|
||||||
|
|
||||||
// Parse credential tag.
|
// Parse credential tag.
|
||||||
credHeader, err := parseCredentialHeader("Credential="+formValues.Get(xhttp.AmzCredential), region, serviceS3)
|
credHeader, s3Err := parseCredentialHeader("Credential="+formValues.Get(xhttp.AmzCredential), region, serviceS3)
|
||||||
if err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return ErrMissingFields
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, _, s3Err := checkKeyValid(credHeader.accessKey)
|
cred, _, s3Err := checkKeyValid(credHeader.accessKey)
|
||||||
|
@ -46,7 +46,7 @@ func TestDoesPolicySignatureMatch(t *testing.T) {
|
|||||||
// (0) It should fail if 'X-Amz-Credential' is missing.
|
// (0) It should fail if 'X-Amz-Credential' is missing.
|
||||||
{
|
{
|
||||||
form: http.Header{},
|
form: http.Header{},
|
||||||
expected: ErrMissingFields,
|
expected: ErrCredMalformed,
|
||||||
},
|
},
|
||||||
// (1) It should fail if the access key is incorrect.
|
// (1) It should fail if the access key is incorrect.
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user