frostfs-s3-gw/api/middleware/policy_test.go

547 lines
15 KiB
Go

package middleware
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
)
func TestReqTypeDetermination(t *testing.T) {
bkt, obj, domain := "test-bucket", "test-object", "domain"
for _, tc := range []struct {
name string
target string
host string
domains []string
expectedType ReqType
expectedBktName string
expectedObjName string
}{
{
name: "bucket request, path-style",
target: "/" + bkt,
expectedType: bucketType,
expectedBktName: bkt,
},
{
name: "bucket request with slash, path-style",
target: "/" + bkt + "/",
expectedType: bucketType,
expectedBktName: bkt,
},
{
name: "object request, path-style",
target: "/" + bkt + "/" + obj,
expectedType: objectType,
expectedBktName: bkt,
expectedObjName: obj,
},
{
name: "object request with slash, path-style",
target: "/" + bkt + "/" + obj + "/",
expectedType: objectType,
expectedBktName: bkt,
expectedObjName: obj + "/",
},
{
name: "none type request",
target: "/",
expectedType: noneType,
},
{
name: "bucket request, virtual-hosted style",
target: "/",
host: bkt + "." + domain,
domains: []string{"some-domain", domain},
expectedType: bucketType,
expectedBktName: bkt,
},
{
name: "object request, virtual-hosted style",
target: "/" + obj,
host: bkt + "." + domain,
domains: []string{"some-domain", domain},
expectedType: objectType,
expectedBktName: bkt,
expectedObjName: obj,
},
} {
t.Run(tc.name, func(t *testing.T) {
r := httptest.NewRequest(http.MethodPut, tc.target, nil)
r.Host = tc.host
reqType, bktName, objName := getBucketObject(r, tc.domains)
require.Equal(t, tc.expectedType, reqType)
require.Equal(t, tc.expectedBktName, bktName)
require.Equal(t, tc.expectedObjName, objName)
})
}
}
func TestDetermineBucketOperation(t *testing.T) {
const defaultValue = "value"
for _, tc := range []struct {
name string
method string
queryParam map[string]string
expected string
}{
{
name: "OptionsBucketOperation",
method: http.MethodOptions,
expected: OptionsBucketOperation,
},
{
name: "HeadBucketOperation",
method: http.MethodHead,
expected: HeadBucketOperation,
},
{
name: "ListMultipartUploadsOperation",
method: http.MethodGet,
queryParam: map[string]string{UploadsQuery: defaultValue},
expected: ListMultipartUploadsOperation,
},
{
name: "GetBucketLocationOperation",
method: http.MethodGet,
queryParam: map[string]string{LocationQuery: defaultValue},
expected: GetBucketLocationOperation,
},
{
name: "GetBucketPolicyOperation",
method: http.MethodGet,
queryParam: map[string]string{PolicyQuery: defaultValue},
expected: GetBucketPolicyOperation,
},
{
name: "GetBucketLifecycleOperation",
method: http.MethodGet,
queryParam: map[string]string{LifecycleQuery: defaultValue},
expected: GetBucketLifecycleOperation,
},
{
name: "GetBucketEncryptionOperation",
method: http.MethodGet,
queryParam: map[string]string{EncryptionQuery: defaultValue},
expected: GetBucketEncryptionOperation,
},
{
name: "GetBucketCorsOperation",
method: http.MethodGet,
queryParam: map[string]string{CorsQuery: defaultValue},
expected: GetBucketCorsOperation,
},
{
name: "GetBucketACLOperation",
method: http.MethodGet,
queryParam: map[string]string{ACLQuery: defaultValue},
expected: GetBucketACLOperation,
},
{
name: "GetBucketWebsiteOperation",
method: http.MethodGet,
queryParam: map[string]string{WebsiteQuery: defaultValue},
expected: GetBucketWebsiteOperation,
},
{
name: "GetBucketAccelerateOperation",
method: http.MethodGet,
queryParam: map[string]string{AccelerateQuery: defaultValue},
expected: GetBucketAccelerateOperation,
},
{
name: "GetBucketRequestPaymentOperation",
method: http.MethodGet,
queryParam: map[string]string{RequestPaymentQuery: defaultValue},
expected: GetBucketRequestPaymentOperation,
},
{
name: "GetBucketLoggingOperation",
method: http.MethodGet,
queryParam: map[string]string{LoggingQuery: defaultValue},
expected: GetBucketLoggingOperation,
},
{
name: "GetBucketReplicationOperation",
method: http.MethodGet,
queryParam: map[string]string{ReplicationQuery: defaultValue},
expected: GetBucketReplicationOperation,
},
{
name: "GetBucketTaggingOperation",
method: http.MethodGet,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: GetBucketTaggingOperation,
},
{
name: "GetBucketObjectLockConfigOperation",
method: http.MethodGet,
queryParam: map[string]string{ObjectLockQuery: defaultValue},
expected: GetBucketObjectLockConfigOperation,
},
{
name: "GetBucketVersioningOperation",
method: http.MethodGet,
queryParam: map[string]string{VersioningQuery: defaultValue},
expected: GetBucketVersioningOperation,
},
{
name: "GetBucketNotificationOperation",
method: http.MethodGet,
queryParam: map[string]string{NotificationQuery: defaultValue},
expected: GetBucketNotificationOperation,
},
{
name: "ListenBucketNotificationOperation",
method: http.MethodGet,
queryParam: map[string]string{EventsQuery: defaultValue},
expected: ListenBucketNotificationOperation,
},
{
name: "ListBucketObjectVersionsOperation",
method: http.MethodGet,
queryParam: map[string]string{VersionsQuery: defaultValue},
expected: ListBucketObjectVersionsOperation,
},
{
name: "ListObjectsV2MOperation",
method: http.MethodGet,
queryParam: map[string]string{ListTypeQuery: "2", MetadataQuery: "true"},
expected: ListObjectsV2MOperation,
},
{
name: "ListObjectsV2Operation",
method: http.MethodGet,
queryParam: map[string]string{ListTypeQuery: "2"},
expected: ListObjectsV2Operation,
},
{
name: "ListObjectsV1Operation",
method: http.MethodGet,
expected: ListObjectsV1Operation,
},
{
name: "PutBucketCorsOperation",
method: http.MethodPut,
queryParam: map[string]string{CorsQuery: defaultValue},
expected: PutBucketCorsOperation,
},
{
name: "PutBucketACLOperation",
method: http.MethodPut,
queryParam: map[string]string{ACLQuery: defaultValue},
expected: PutBucketACLOperation,
},
{
name: "PutBucketLifecycleOperation",
method: http.MethodPut,
queryParam: map[string]string{LifecycleQuery: defaultValue},
expected: PutBucketLifecycleOperation,
},
{
name: "PutBucketEncryptionOperation",
method: http.MethodPut,
queryParam: map[string]string{EncryptionQuery: defaultValue},
expected: PutBucketEncryptionOperation,
},
{
name: "PutBucketPolicyOperation",
method: http.MethodPut,
queryParam: map[string]string{PolicyQuery: defaultValue},
expected: PutBucketPolicyOperation,
},
{
name: "PutBucketObjectLockConfigOperation",
method: http.MethodPut,
queryParam: map[string]string{ObjectLockQuery: defaultValue},
expected: PutBucketObjectLockConfigOperation,
},
{
name: "PutBucketTaggingOperation",
method: http.MethodPut,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: PutBucketTaggingOperation,
},
{
name: "PutBucketVersioningOperation",
method: http.MethodPut,
queryParam: map[string]string{VersioningQuery: defaultValue},
expected: PutBucketVersioningOperation,
},
{
name: "PutBucketNotificationOperation",
method: http.MethodPut,
queryParam: map[string]string{NotificationQuery: defaultValue},
expected: PutBucketNotificationOperation,
},
{
name: "CreateBucketOperation",
method: http.MethodPut,
expected: CreateBucketOperation,
},
{
name: "DeleteMultipleObjectsOperation",
method: http.MethodPost,
queryParam: map[string]string{DeleteQuery: defaultValue},
expected: DeleteMultipleObjectsOperation,
},
{
name: "PostObjectOperation",
method: http.MethodPost,
expected: PostObjectOperation,
},
{
name: "DeleteBucketCorsOperation",
method: http.MethodDelete,
queryParam: map[string]string{CorsQuery: defaultValue},
expected: DeleteBucketCorsOperation,
},
{
name: "DeleteBucketWebsiteOperation",
method: http.MethodDelete,
queryParam: map[string]string{WebsiteQuery: defaultValue},
expected: DeleteBucketWebsiteOperation,
},
{
name: "DeleteBucketTaggingOperation",
method: http.MethodDelete,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: DeleteBucketTaggingOperation,
},
{
name: "DeleteBucketPolicyOperation",
method: http.MethodDelete,
queryParam: map[string]string{PolicyQuery: defaultValue},
expected: DeleteBucketPolicyOperation,
},
{
name: "DeleteBucketLifecycleOperation",
method: http.MethodDelete,
queryParam: map[string]string{LifecycleQuery: defaultValue},
expected: DeleteBucketLifecycleOperation,
},
{
name: "DeleteBucketEncryptionOperation",
method: http.MethodDelete,
queryParam: map[string]string{EncryptionQuery: defaultValue},
expected: DeleteBucketEncryptionOperation,
},
{
name: "DeleteBucketOperation",
method: http.MethodDelete,
expected: DeleteBucketOperation,
},
{
name: "UnmatchedBucketOperation",
method: "invalid-method",
expected: "UnmatchedBucketOperation",
},
} {
t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest(tc.method, "/test", nil)
if tc.queryParam != nil {
addQueryParams(req, tc.queryParam)
}
actual := determineBucketOperation(req)
require.Equal(t, tc.expected, actual)
})
}
}
func TestDetermineObjectOperation(t *testing.T) {
const (
amzCopySource = "X-Amz-Copy-Source"
defaultValue = "value"
)
for _, tc := range []struct {
name string
method string
queryParam map[string]string
headerKeys []string
expected string
}{
{
name: "OptionsObjectOperation",
method: http.MethodOptions,
expected: OptionsObjectOperation,
},
{
name: "HeadObjectOperation",
method: http.MethodHead,
expected: HeadObjectOperation,
},
{
name: "ListPartsOperation",
method: http.MethodGet,
queryParam: map[string]string{UploadIDQuery: defaultValue},
expected: ListPartsOperation,
},
{
name: "GetObjectACLOperation",
method: http.MethodGet,
queryParam: map[string]string{ACLQuery: defaultValue},
expected: GetObjectACLOperation,
},
{
name: "GetObjectTaggingOperation",
method: http.MethodGet,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: GetObjectTaggingOperation,
},
{
name: "GetObjectRetentionOperation",
method: http.MethodGet,
queryParam: map[string]string{RetentionQuery: defaultValue},
expected: GetObjectRetentionOperation,
},
{
name: "GetObjectLegalHoldOperation",
method: http.MethodGet,
queryParam: map[string]string{LegalQuery: defaultValue},
expected: GetObjectLegalHoldOperation,
},
{
name: "GetObjectAttributesOperation",
method: http.MethodGet,
queryParam: map[string]string{AttributesQuery: defaultValue},
expected: GetObjectAttributesOperation,
},
{
name: "GetObjectOperation",
method: http.MethodGet,
expected: GetObjectOperation,
},
{
name: "UploadPartCopyOperation",
method: http.MethodPut,
queryParam: map[string]string{PartNumberQuery: defaultValue, UploadIDQuery: defaultValue},
headerKeys: []string{amzCopySource},
expected: UploadPartCopyOperation,
},
{
name: "UploadPartOperation",
method: http.MethodPut,
queryParam: map[string]string{PartNumberQuery: defaultValue, UploadIDQuery: defaultValue},
expected: UploadPartOperation,
},
{
name: "PutObjectACLOperation",
method: http.MethodPut,
queryParam: map[string]string{ACLQuery: defaultValue},
expected: PutObjectACLOperation,
},
{
name: "PutObjectTaggingOperation",
method: http.MethodPut,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: PutObjectTaggingOperation,
},
{
name: "CopyObjectOperation",
method: http.MethodPut,
headerKeys: []string{amzCopySource},
expected: CopyObjectOperation,
},
{
name: "PutObjectRetentionOperation",
method: http.MethodPut,
queryParam: map[string]string{RetentionQuery: defaultValue},
expected: PutObjectRetentionOperation,
},
{
name: "PutObjectLegalHoldOperation",
method: http.MethodPut,
queryParam: map[string]string{LegalHoldQuery: defaultValue},
expected: PutObjectLegalHoldOperation,
},
{
name: "PutObjectOperation",
method: http.MethodPut,
expected: PutObjectOperation,
},
{
name: "CompleteMultipartUploadOperation",
method: http.MethodPost,
queryParam: map[string]string{UploadIDQuery: defaultValue},
expected: CompleteMultipartUploadOperation,
},
{
name: "CreateMultipartUploadOperation",
method: http.MethodPost,
queryParam: map[string]string{UploadsQuery: defaultValue},
expected: CreateMultipartUploadOperation,
},
{
name: "SelectObjectContentOperation",
method: http.MethodPost,
expected: SelectObjectContentOperation,
},
{
name: "AbortMultipartUploadOperation",
method: http.MethodDelete,
queryParam: map[string]string{UploadIDQuery: defaultValue},
expected: AbortMultipartUploadOperation,
},
{
name: "DeleteObjectTaggingOperation",
method: http.MethodDelete,
queryParam: map[string]string{TaggingQuery: defaultValue},
expected: DeleteObjectTaggingOperation,
},
{
name: "DeleteObjectOperation",
method: http.MethodDelete,
expected: DeleteObjectOperation,
},
{
name: "UnmatchedObjectOperation",
method: "invalid-method",
expected: "UnmatchedObjectOperation",
},
} {
t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest(tc.method, "/test", nil)
if tc.queryParam != nil {
addQueryParams(req, tc.queryParam)
}
if tc.headerKeys != nil {
addHeaderParams(req, tc.headerKeys)
}
actual := determineObjectOperation(req)
require.Equal(t, tc.expected, actual)
})
}
}
func addQueryParams(req *http.Request, pairs map[string]string) {
values := req.URL.Query()
for key, val := range pairs {
values.Add(key, val)
}
req.URL.RawQuery = values.Encode()
}
func addHeaderParams(req *http.Request, keys []string) {
for _, key := range keys {
req.Header.Set(key, "val")
}
}
func TestDetermineGeneralOperation(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/test", nil)
actual := determineGeneralOperation(req)
require.Equal(t, ListBucketsOperation, actual)
req = httptest.NewRequest(http.MethodPost, "/test", nil)
actual = determineGeneralOperation(req)
require.Equal(t, "UnmatchedOperation", actual)
}