forked from TrueCloudLab/frostfs-s3-gw
[#353] Add check of listing parameters and versionID
Add properties in policy check: * s3:delimiter * s3:prefix * s3:max-keys * s3:VersionId Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
parent
8407b3ea4c
commit
37d05dcefd
4 changed files with 202 additions and 22 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -270,7 +271,7 @@ func TestACLAPE(t *testing.T) {
|
|||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
||||
|
||||
// Allow operations and check
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"})
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
listBuckets(router, ns)
|
||||
})
|
||||
|
@ -296,7 +297,7 @@ func TestACLAPE(t *testing.T) {
|
|||
listBuckets(router, ns)
|
||||
|
||||
// Deny operations and check
|
||||
denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"})
|
||||
denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"}, nil)
|
||||
createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied)
|
||||
listBucketsErr(router, ns, apiErrors.ErrAccessDenied)
|
||||
})
|
||||
|
@ -344,22 +345,136 @@ func TestACLAPE(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func allowOperations(router *routerMock, ns string, operations []string) {
|
||||
addPolicy(router, ns, "allow", engineiam.AllowEffect, operations)
|
||||
func TestRequestParametersCheck(t *testing.T) {
|
||||
t.Run("prefix parameter, allow specific value", func(t *testing.T) {
|
||||
router := prepareRouter(t)
|
||||
|
||||
ns, bktName, prefix := "", "bucket", "prefix"
|
||||
router.middlewareSettings.denyByDefault = true
|
||||
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
|
||||
// Add policies and check
|
||||
denyOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondStringNotEquals: engineiam.Condition{s3.PropertyKeyPrefix: []string{prefix}},
|
||||
})
|
||||
allowOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondStringEquals: engineiam.Condition{s3.PropertyKeyPrefix: []string{prefix}},
|
||||
})
|
||||
|
||||
listObjectsV1(router, ns, bktName, prefix, "", "")
|
||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
||||
listObjectsV1Err(router, ns, bktName, "invalid", "", "", apiErrors.ErrAccessDenied)
|
||||
})
|
||||
|
||||
t.Run("delimiter parameter, prohibit specific value", func(t *testing.T) {
|
||||
router := prepareRouter(t)
|
||||
|
||||
ns, bktName, delimiter := "", "bucket", "delimiter"
|
||||
router.middlewareSettings.denyByDefault = true
|
||||
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
|
||||
// Add policies and check
|
||||
denyOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondStringEquals: engineiam.Condition{s3.PropertyKeyDelimiter: []string{delimiter}},
|
||||
})
|
||||
allowOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondStringNotEquals: engineiam.Condition{s3.PropertyKeyDelimiter: []string{delimiter}},
|
||||
})
|
||||
|
||||
listObjectsV1(router, ns, bktName, "", "", "")
|
||||
listObjectsV1(router, ns, bktName, "", "some-delimiter", "")
|
||||
listObjectsV1Err(router, ns, bktName, "", delimiter, "", apiErrors.ErrAccessDenied)
|
||||
})
|
||||
|
||||
t.Run("max-keys parameter, allow specific value", func(t *testing.T) {
|
||||
router := prepareRouter(t)
|
||||
|
||||
ns, bktName, maxKeys := "", "bucket", 10
|
||||
router.middlewareSettings.denyByDefault = true
|
||||
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
|
||||
// Add policies and check
|
||||
denyOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericNotEquals: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
allowOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericEquals: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
|
||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1), apiErrors.ErrAccessDenied)
|
||||
listObjectsV1Err(router, ns, bktName, "", "", "invalid", apiErrors.ErrAccessDenied)
|
||||
})
|
||||
|
||||
t.Run("max-keys parameter, allow range of values", func(t *testing.T) {
|
||||
router := prepareRouter(t)
|
||||
|
||||
ns, bktName, maxKeys := "", "bucket", 10
|
||||
router.middlewareSettings.denyByDefault = true
|
||||
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
|
||||
// Add policies and check
|
||||
denyOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericGreaterThan: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
allowOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericLessThanEquals: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
|
||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys+1), apiErrors.ErrAccessDenied)
|
||||
})
|
||||
|
||||
t.Run("max-keys parameter, prohibit specific value", func(t *testing.T) {
|
||||
router := prepareRouter(t)
|
||||
|
||||
ns, bktName, maxKeys := "", "bucket", 10
|
||||
router.middlewareSettings.denyByDefault = true
|
||||
|
||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, nil)
|
||||
createBucket(router, ns, bktName)
|
||||
|
||||
// Add policies and check
|
||||
denyOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericEquals: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
allowOperations(router, ns, []string{"s3:ListBucket"}, engineiam.Conditions{
|
||||
engineiam.CondNumericNotEquals: engineiam.Condition{s3.PropertyKeyMaxKeys: []string{strconv.Itoa(maxKeys)}},
|
||||
})
|
||||
|
||||
listObjectsV1(router, ns, bktName, "", "", "")
|
||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys), apiErrors.ErrAccessDenied)
|
||||
})
|
||||
}
|
||||
|
||||
func denyOperations(router *routerMock, ns string, operations []string) {
|
||||
addPolicy(router, ns, "deny", engineiam.DenyEffect, operations)
|
||||
func allowOperations(router *routerMock, ns string, operations []string, conditions engineiam.Conditions) {
|
||||
addPolicy(router, ns, "allow", engineiam.AllowEffect, operations, conditions)
|
||||
}
|
||||
|
||||
func addPolicy(router *routerMock, ns string, id string, effect engineiam.Effect, operations []string) {
|
||||
func denyOperations(router *routerMock, ns string, operations []string, conditions engineiam.Conditions) {
|
||||
addPolicy(router, ns, "deny", engineiam.DenyEffect, operations, conditions)
|
||||
}
|
||||
|
||||
func addPolicy(router *routerMock, ns string, id string, effect engineiam.Effect, operations []string, conditions engineiam.Conditions) {
|
||||
policy := engineiam.Policy{
|
||||
Version: "2012-10-17",
|
||||
Statement: []engineiam.Statement{{
|
||||
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||
Effect: effect,
|
||||
Action: engineiam.Action(operations),
|
||||
Resource: engineiam.Resource{fmt.Sprintf(s3.ResourceFormatS3All)},
|
||||
Principal: map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}},
|
||||
Effect: effect,
|
||||
Action: engineiam.Action(operations),
|
||||
Resource: engineiam.Resource{fmt.Sprintf(s3.ResourceFormatS3All)},
|
||||
Conditions: conditions,
|
||||
}},
|
||||
}
|
||||
|
||||
|
@ -441,6 +556,38 @@ func putObjectBase(router *routerMock, namespace, bktName, objName string) *http
|
|||
return w
|
||||
}
|
||||
|
||||
func listObjectsV1(router *routerMock, namespace, bktName, prefix, delimiter, maxKeys string) handlerResult {
|
||||
w := listObjectsV1Base(router, namespace, bktName, prefix, delimiter, maxKeys)
|
||||
resp := readResponse(router.t, w)
|
||||
require.Equal(router.t, s3middleware.ListObjectsV1Operation, resp.Method)
|
||||
return resp
|
||||
}
|
||||
|
||||
func listObjectsV1Err(router *routerMock, namespace, bktName, prefix, delimiter, maxKeys string, errCode apiErrors.ErrorCode) {
|
||||
w := listObjectsV1Base(router, namespace, bktName, prefix, delimiter, maxKeys)
|
||||
assertAPIError(router.t, w, errCode)
|
||||
}
|
||||
|
||||
func listObjectsV1Base(router *routerMock, namespace, bktName, prefix, delimiter, maxKeys string) *httptest.ResponseRecorder {
|
||||
queries := url.Values{}
|
||||
if len(prefix) > 0 {
|
||||
queries.Add(s3middleware.QueryPrefix, prefix)
|
||||
}
|
||||
if len(delimiter) > 0 {
|
||||
queries.Add(s3middleware.QueryDelimiter, delimiter)
|
||||
}
|
||||
if len(maxKeys) > 0 {
|
||||
queries.Add(s3middleware.QueryMaxKeys, maxKeys)
|
||||
}
|
||||
encoded := queries.Encode()
|
||||
|
||||
w, r := httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/"+bktName, nil)
|
||||
r.URL.RawQuery = encoded
|
||||
r.Header.Set(FrostfsNamespaceHeader, namespace)
|
||||
router.ServeHTTP(w, r)
|
||||
return w
|
||||
}
|
||||
|
||||
func TestOwnerIDRetrieving(t *testing.T) {
|
||||
chiRouter := prepareRouter(t)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue