fix: return IllegalLocationConstraintException for a mismatched LocationConstraint
A region specific endpoint requires CreateBucket to name that same region in `LocationConstraint`. The gateway reported a mismatch as `InvalidLocationConstraint`, which AWS reserves for a constraint that is not a valid location at all, and accepted a request that omitted the constraint entirely. Keep `InvalidLocationConstraint` for the global `us-east-1` endpoint, which takes no constraint, and return `IllegalLocationConstraintException` when a region specific endpoint gets a constraint naming another region, or none. Fixes #2246
This commit is contained in:
1 parent
2a5705ab02
commit
2742fc2216
3 files changed
+110
-11
No files matched your search
@@ -546,6 +546,32 @@ func (c S3ApiController) PutBucketAcl(ctx fiber.Ctx) (*Response, error) {
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateLocationConstraint checks a CreateBucket location constraint. The
|
||||||
|
// global endpoint serves defaultRegion and takes no constraint; any other
|
||||||
|
// region is a region specific endpoint and requires the constraint to name it.
|
||||||
|
func validateLocationConstraint(constraint *string, region string) error {
|
||||||
|
if region == defaultRegion {
|
||||||
|
if constraint != nil {
|
||||||
|
debuglogger.Logf("invalid location constraint: %s", *constraint)
|
||||||
|
return s3err.GetInvalidLocationConstraintErr(*constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if constraint == nil {
|
||||||
|
debuglogger.Logf("missing location constraint for region %s", region)
|
||||||
|
return s3err.GetIllegalLocationConstraintErr("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *constraint != region {
|
||||||
|
debuglogger.Logf("illegal location constraint %s for region %s", *constraint, region)
|
||||||
|
return s3err.GetIllegalLocationConstraintErr(*constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c S3ApiController) CreateBucket(ctx fiber.Ctx) (*Response, error) {
|
func (c S3ApiController) CreateBucket(ctx fiber.Ctx) (*Response, error) {
|
||||||
bucket := ctx.Params("bucket")
|
bucket := ctx.Params("bucket")
|
||||||
acl := types.BucketCannedACL(c.getAclHeaderValue(ctx, "X-Amz-Acl"))
|
acl := types.BucketCannedACL(c.getAclHeaderValue(ctx, "X-Amz-Acl"))
|
||||||
@@ -658,18 +684,19 @@ func (c S3ApiController) CreateBucket(ctx fiber.Ctx) (*Response, error) {
|
|||||||
},
|
},
|
||||||
}, s3err.GetAPIError(s3err.ErrMalformedXML)
|
}, s3err.GetAPIError(s3err.ErrMalformedXML)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if body.LocationConstraint != nil {
|
region, ok := utils.ContextKeyRegion.Get(ctx).(string)
|
||||||
region := utils.ContextKeyRegion.Get(ctx).(string)
|
if !ok {
|
||||||
if *body.LocationConstraint != region || *body.LocationConstraint == "us-east-1" {
|
region = defaultRegion
|
||||||
debuglogger.Logf("invalid location constraint: %s", *body.LocationConstraint)
|
}
|
||||||
return &Response{
|
|
||||||
MetaOpts: &MetaOptions{
|
if err := validateLocationConstraint(body.LocationConstraint, region); err != nil {
|
||||||
BucketOwner: bucketOwner.Access,
|
return &Response{
|
||||||
},
|
MetaOpts: &MetaOptions{
|
||||||
}, s3err.GetInvalidLocationConstraintErr(*body.LocationConstraint)
|
BucketOwner: bucketOwner.Access,
|
||||||
}
|
},
|
||||||
}
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defACL := auth.ACL{
|
defACL := auth.ACL{
|
||||||
|
|||||||
@@ -726,6 +726,11 @@ func TestS3ApiController_CreateBucket(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
euLocConstBody, err := xml.Marshal(s3response.CreateBucketConfiguration{
|
||||||
|
LocationConstraint: utils.GetStringPtr("eu-central-1"),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input testInput
|
input testInput
|
||||||
@@ -812,6 +817,59 @@ func TestS3ApiController_CreateBucket(t *testing.T) {
|
|||||||
err: s3err.GetInvalidLocationConstraintErr("us-west-1"),
|
err: s3err.GetInvalidLocationConstraintErr("us-west-1"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "illegal location constraint",
|
||||||
|
input: testInput{
|
||||||
|
locals: map[utils.ContextKey]any{
|
||||||
|
utils.ContextKeyAccount: adminAcc,
|
||||||
|
utils.ContextKeyRegion: "us-west-1",
|
||||||
|
},
|
||||||
|
body: euLocConstBody,
|
||||||
|
},
|
||||||
|
output: testOutput{
|
||||||
|
response: &Response{
|
||||||
|
MetaOpts: &MetaOptions{BucketOwner: adminAcc.Access},
|
||||||
|
},
|
||||||
|
err: s3err.GetIllegalLocationConstraintErr("eu-central-1"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing location constraint",
|
||||||
|
input: testInput{
|
||||||
|
locals: map[utils.ContextKey]any{
|
||||||
|
utils.ContextKeyAccount: adminAcc,
|
||||||
|
utils.ContextKeyRegion: "us-west-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: testOutput{
|
||||||
|
response: &Response{
|
||||||
|
MetaOpts: &MetaOptions{BucketOwner: adminAcc.Access},
|
||||||
|
},
|
||||||
|
err: s3err.GetIllegalLocationConstraintErr(""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matching location constraint",
|
||||||
|
input: testInput{
|
||||||
|
locals: map[utils.ContextKey]any{
|
||||||
|
utils.ContextKeyAccount: adminAcc,
|
||||||
|
utils.ContextKeyRegion: "us-west-1",
|
||||||
|
},
|
||||||
|
bucket: "my-bucket",
|
||||||
|
body: invLocConstBody,
|
||||||
|
},
|
||||||
|
output: testOutput{
|
||||||
|
response: &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: adminAcc.Access,
|
||||||
|
},
|
||||||
|
Headers: map[string]*string{
|
||||||
|
"Location": utils.GetStringPtr("/my-bucket"),
|
||||||
|
"x-amz-bucket-arn": utils.GetStringPtr("arn:aws:s3:::my-bucket"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "invalid ownership",
|
name: "invalid ownership",
|
||||||
input: testInput{
|
input: testInput{
|
||||||
|
|||||||
@@ -984,6 +984,20 @@ func GetCopySourceObjectTooLargeErr(limit int64) APIError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns illegal location constraint APIError. An empty constraint stands for
|
||||||
|
// a CreateBucket request that carried no LocationConstraint at all.
|
||||||
|
func GetIllegalLocationConstraintErr(constraint string) APIError {
|
||||||
|
if constraint == "" {
|
||||||
|
constraint = "unspecified"
|
||||||
|
}
|
||||||
|
|
||||||
|
return APIError{
|
||||||
|
Code: "IllegalLocationConstraintException",
|
||||||
|
Description: fmt.Sprintf("The %s location constraint is incompatible for the region specific endpoint this request was sent to.", constraint),
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetInvalidRedirectCodeErr(input int) APIError {
|
func GetInvalidRedirectCodeErr(input int) APIError {
|
||||||
return APIError{
|
return APIError{
|
||||||
Code: "InvalidRequest",
|
Code: "InvalidRequest",
|
||||||
|
|||||||
Reference in new issue
Block a user