mirror of
https://github.com/minio/minio.git
synced 2025-07-08 08:32:18 -04:00
Add support for new policy conditions (#7024)
This PR implements following condition types - StringEqualsIgnoreCase and StringNotEqualsIgnoreCase - BinaryEquals
This commit is contained in:
parent
2db22deb93
commit
4e4f855b30
@ -20,6 +20,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -183,7 +184,12 @@ func NewPolicySys() *PolicySys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getConditionValues(request *http.Request, locationConstraint string) map[string][]string {
|
func getConditionValues(request *http.Request, locationConstraint string) map[string][]string {
|
||||||
args := make(map[string][]string)
|
args := map[string][]string{
|
||||||
|
"SourceIp": {handlers.GetSourceIP(request)},
|
||||||
|
"SecureTransport": {fmt.Sprintf("%t", request.TLS != nil)},
|
||||||
|
"UserAgent": {request.UserAgent()},
|
||||||
|
"Referer": {request.Referer()},
|
||||||
|
}
|
||||||
|
|
||||||
for key, values := range request.Header {
|
for key, values := range request.Header {
|
||||||
if existingValues, found := args[key]; found {
|
if existingValues, found := args[key]; found {
|
||||||
@ -201,8 +207,6 @@ func getConditionValues(request *http.Request, locationConstraint string) map[st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args["SourceIp"] = []string{handlers.GetSourceIP(request)}
|
|
||||||
|
|
||||||
if locationConstraint != "" {
|
if locationConstraint != "" {
|
||||||
args["LocationConstraint"] = []string{locationConstraint}
|
args["LocationConstraint"] = []string{locationConstraint}
|
||||||
}
|
}
|
||||||
|
@ -174,39 +174,55 @@ func parseAction(s string) (Action, error) {
|
|||||||
|
|
||||||
// actionConditionKeyMap - holds mapping of supported condition key for an action.
|
// actionConditionKeyMap - holds mapping of supported condition key for an action.
|
||||||
var actionConditionKeyMap = map[Action]condition.KeySet{
|
var actionConditionKeyMap = map[Action]condition.KeySet{
|
||||||
|
AllActions: condition.NewKeySet(condition.AllSupportedKeys...),
|
||||||
|
|
||||||
AbortMultipartUploadAction: condition.NewKeySet(
|
AbortMultipartUploadAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
CreateBucketAction: condition.NewKeySet(
|
CreateBucketAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
DeleteBucketPolicyAction: condition.NewKeySet(
|
DeleteBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
DeleteObjectAction: condition.NewKeySet(
|
DeleteObjectAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketLocationAction: condition.NewKeySet(
|
GetBucketLocationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketNotificationAction: condition.NewKeySet(
|
GetBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketPolicyAction: condition.NewKeySet(
|
GetBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetObjectAction: condition.NewKeySet(
|
GetObjectAction: condition.NewKeySet(
|
||||||
@ -215,16 +231,22 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3XAmzStorageClass,
|
condition.S3XAmzStorageClass,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
HeadBucketAction: condition.NewKeySet(
|
HeadBucketAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListAllMyBucketsAction: condition.NewKeySet(
|
ListAllMyBucketsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListBucketAction: condition.NewKeySet(
|
ListBucketAction: condition.NewKeySet(
|
||||||
@ -233,31 +255,43 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3MaxKeys,
|
condition.S3MaxKeys,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListBucketMultipartUploadsAction: condition.NewKeySet(
|
ListBucketMultipartUploadsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListenBucketNotificationAction: condition.NewKeySet(
|
ListenBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListMultipartUploadPartsAction: condition.NewKeySet(
|
ListMultipartUploadPartsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutBucketNotificationAction: condition.NewKeySet(
|
PutBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutBucketPolicyAction: condition.NewKeySet(
|
PutBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutObjectAction: condition.NewKeySet(
|
PutObjectAction: condition.NewKeySet(
|
||||||
@ -268,5 +302,7 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3XAmzStorageClass,
|
condition.S3XAmzStorageClass,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -161,36 +161,50 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
AbortMultipartUploadAction: condition.NewKeySet(
|
AbortMultipartUploadAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
CreateBucketAction: condition.NewKeySet(
|
CreateBucketAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
DeleteBucketPolicyAction: condition.NewKeySet(
|
DeleteBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
DeleteObjectAction: condition.NewKeySet(
|
DeleteObjectAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketLocationAction: condition.NewKeySet(
|
GetBucketLocationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketNotificationAction: condition.NewKeySet(
|
GetBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetBucketPolicyAction: condition.NewKeySet(
|
GetBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
GetObjectAction: condition.NewKeySet(
|
GetObjectAction: condition.NewKeySet(
|
||||||
@ -199,16 +213,22 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3XAmzStorageClass,
|
condition.S3XAmzStorageClass,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
HeadBucketAction: condition.NewKeySet(
|
HeadBucketAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListAllMyBucketsAction: condition.NewKeySet(
|
ListAllMyBucketsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListBucketAction: condition.NewKeySet(
|
ListBucketAction: condition.NewKeySet(
|
||||||
@ -217,31 +237,43 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3MaxKeys,
|
condition.S3MaxKeys,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListBucketMultipartUploadsAction: condition.NewKeySet(
|
ListBucketMultipartUploadsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListenBucketNotificationAction: condition.NewKeySet(
|
ListenBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListMultipartUploadPartsAction: condition.NewKeySet(
|
ListMultipartUploadPartsAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutBucketNotificationAction: condition.NewKeySet(
|
PutBucketNotificationAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutBucketPolicyAction: condition.NewKeySet(
|
PutBucketPolicyAction: condition.NewKeySet(
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
|
|
||||||
PutObjectAction: condition.NewKeySet(
|
PutObjectAction: condition.NewKeySet(
|
||||||
@ -252,5 +284,7 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3XAmzStorageClass,
|
condition.S3XAmzStorageClass,
|
||||||
condition.AWSReferer,
|
condition.AWSReferer,
|
||||||
condition.AWSSourceIP,
|
condition.AWSSourceIP,
|
||||||
|
condition.AWSUserAgent,
|
||||||
|
condition.AWSSecureTransport,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
138
pkg/policy/condition/binaryequalsfunc.go
Normal file
138
pkg/policy/condition/binaryequalsfunc.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package condition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/pkg/s3utils"
|
||||||
|
"github.com/minio/minio-go/pkg/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toBinaryEqualsFuncString(n name, key Key, values set.StringSet) string {
|
||||||
|
valueStrings := values.ToSlice()
|
||||||
|
sort.Strings(valueStrings)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v:%v:%v", n, key, valueStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// binaryEqualsFunc - String equals function. It checks whether value by Key in given
|
||||||
|
// values map is in condition values.
|
||||||
|
// For example,
|
||||||
|
// - if values = ["mybucket/foo"], at evaluate() it returns whether string
|
||||||
|
// in value map for Key is in values.
|
||||||
|
type binaryEqualsFunc struct {
|
||||||
|
k Key
|
||||||
|
values set.StringSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate() - evaluates to check whether value by Key in given values is in
|
||||||
|
// condition values.
|
||||||
|
func (f binaryEqualsFunc) evaluate(values map[string][]string) bool {
|
||||||
|
requestValue, ok := values[http.CanonicalHeaderKey(f.k.Name())]
|
||||||
|
if !ok {
|
||||||
|
requestValue = values[f.k.Name()]
|
||||||
|
}
|
||||||
|
|
||||||
|
return !f.values.Intersection(set.CreateStringSet(requestValue...)).IsEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
// key() - returns condition key which is used by this condition function.
|
||||||
|
func (f binaryEqualsFunc) key() Key {
|
||||||
|
return f.k
|
||||||
|
}
|
||||||
|
|
||||||
|
// name() - returns "BinaryEquals" condition name.
|
||||||
|
func (f binaryEqualsFunc) name() name {
|
||||||
|
return binaryEquals
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f binaryEqualsFunc) String() string {
|
||||||
|
return toBinaryEqualsFuncString(binaryEquals, f.k, f.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toMap - returns map representation of this function.
|
||||||
|
func (f binaryEqualsFunc) toMap() map[Key]ValueSet {
|
||||||
|
if !f.k.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
values := NewValueSet()
|
||||||
|
for _, value := range f.values.ToSlice() {
|
||||||
|
values.Add(NewStringValue(base64.StdEncoding.EncodeToString([]byte(value))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[Key]ValueSet{
|
||||||
|
f.k: values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateBinaryEqualsValues(n name, key Key, values set.StringSet) error {
|
||||||
|
vslice := values.ToSlice()
|
||||||
|
for _, s := range vslice {
|
||||||
|
sbytes, err := base64.StdEncoding.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
values.Remove(s)
|
||||||
|
s = string(sbytes)
|
||||||
|
switch key {
|
||||||
|
case S3XAmzCopySource:
|
||||||
|
bucket, object := path2BucketAndObject(s)
|
||||||
|
if object == "" {
|
||||||
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzCopySource, n)
|
||||||
|
}
|
||||||
|
if err = s3utils.CheckValidBucketName(bucket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case S3XAmzServerSideEncryption:
|
||||||
|
if s != "aws:kms" && s != "AES256" {
|
||||||
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzServerSideEncryption, n)
|
||||||
|
}
|
||||||
|
case S3XAmzMetadataDirective:
|
||||||
|
if s != "COPY" && s != "REPLACE" {
|
||||||
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzMetadataDirective, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values.Add(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBinaryEqualsFunc - returns new BinaryEquals function.
|
||||||
|
func newBinaryEqualsFunc(key Key, values ValueSet) (Function, error) {
|
||||||
|
valueStrings, err := valuesToStringSlice(binaryEquals, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewBinaryEqualsFunc(key, valueStrings...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBinaryEqualsFunc - returns new BinaryEquals function.
|
||||||
|
func NewBinaryEqualsFunc(key Key, values ...string) (Function, error) {
|
||||||
|
sset := set.CreateStringSet(values...)
|
||||||
|
if err := validateBinaryEqualsValues(binaryEquals, key, sset); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &binaryEqualsFunc{key, sset}, nil
|
||||||
|
}
|
387
pkg/policy/condition/binaryequalsfunc_test.go
Normal file
387
pkg/policy/condition/binaryequalsfunc_test.go
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package condition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBinaryEqualsFuncEvaluate(t *testing.T) {
|
||||||
|
case1Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
values map[string][]string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"mybucket/myobject"}}, true},
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"yourbucket/myobject"}}, false},
|
||||||
|
{case1Function, map[string][]string{}, false},
|
||||||
|
{case1Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"AES256"}}, true},
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"aws:kms"}}, false},
|
||||||
|
{case2Function, map[string][]string{}, false},
|
||||||
|
{case2Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"REPLACE"}}, true},
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"COPY"}}, false},
|
||||||
|
{case3Function, map[string][]string{}, false},
|
||||||
|
{case3Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"eu-west-1"}}, true},
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"us-east-1"}}, false},
|
||||||
|
{case4Function, map[string][]string{}, false},
|
||||||
|
{case4Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.evaluate(testCase.values)
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryEqualsFuncKey(t *testing.T) {
|
||||||
|
case1Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
expectedResult Key
|
||||||
|
}{
|
||||||
|
{case1Function, S3XAmzCopySource},
|
||||||
|
{case2Function, S3XAmzServerSideEncryption},
|
||||||
|
{case3Function, S3XAmzMetadataDirective},
|
||||||
|
{case4Function, S3LocationConstraint},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.key()
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryEqualsFuncToMap(t *testing.T) {
|
||||||
|
case1Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case1Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))),
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("yourbucket/myobject"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("yourbucket/myobject"))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))),
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("aws:kms"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("aws:kms"))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))),
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("COPY"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("COPY"))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))),
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("us-west-1"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("us-west-1"))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
f Function
|
||||||
|
expectedResult map[Key]ValueSet
|
||||||
|
}{
|
||||||
|
{case1Function, case1Result},
|
||||||
|
{case2Function, case2Result},
|
||||||
|
{case3Function, case3Result},
|
||||||
|
{case4Function, case4Result},
|
||||||
|
{case5Function, case5Result},
|
||||||
|
{case6Function, case6Result},
|
||||||
|
{case7Function, case7Result},
|
||||||
|
{case8Function, case8Result},
|
||||||
|
{&binaryEqualsFunc{}, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.f.toMap()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewBinaryEqualsFunc(t *testing.T) {
|
||||||
|
case1Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newBinaryEqualsFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("yourbucket/myobject"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newBinaryEqualsFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("aws:kms"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newBinaryEqualsFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("COPY"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newBinaryEqualsFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("us-west-1"))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
key Key
|
||||||
|
values ValueSet
|
||||||
|
expectedResult Function
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject")))), case1Function, false},
|
||||||
|
{S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("yourbucket/myobject"))),
|
||||||
|
), case2Function, false},
|
||||||
|
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256")))), case3Function, false},
|
||||||
|
{S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("aws:kms"))),
|
||||||
|
), case4Function, false},
|
||||||
|
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE")))), case5Function, false},
|
||||||
|
{S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("COPY"))),
|
||||||
|
), case6Function, false},
|
||||||
|
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1")))), case7Function, false},
|
||||||
|
{S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1"))),
|
||||||
|
NewStringValue(base64.StdEncoding.EncodeToString([]byte("us-west-1"))),
|
||||||
|
), case8Function, false},
|
||||||
|
|
||||||
|
// Unsupported value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket/myobject"))), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("AES256"))), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("REPLACE"))), NewIntValue(7)), nil, true},
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("eu-west-1"))), NewIntValue(7)), nil, true},
|
||||||
|
|
||||||
|
// Invalid value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("mybucket")))), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("SSE-C")))), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue(base64.StdEncoding.EncodeToString([]byte("DUPLICATE")))), nil, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result, err := newBinaryEqualsFunc(testCase.key, testCase.values)
|
||||||
|
expectErr := (err != nil)
|
||||||
|
|
||||||
|
if expectErr != testCase.expectErr {
|
||||||
|
t.Fatalf("case %v: error: expected: %v, got: %v\n", i+1, testCase.expectErr, expectErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !testCase.expectErr {
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -88,6 +88,20 @@ func (functions Functions) String() string {
|
|||||||
return fmt.Sprintf("%v", funcStrings)
|
return fmt.Sprintf("%v", funcStrings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var conditionFuncMap = map[name]func(Key, ValueSet) (Function, error){
|
||||||
|
stringEquals: newStringEqualsFunc,
|
||||||
|
stringNotEquals: newStringNotEqualsFunc,
|
||||||
|
stringEqualsIgnoreCase: newStringEqualsIgnoreCaseFunc,
|
||||||
|
stringNotEqualsIgnoreCase: newStringNotEqualsIgnoreCaseFunc,
|
||||||
|
binaryEquals: newBinaryEqualsFunc,
|
||||||
|
stringLike: newStringLikeFunc,
|
||||||
|
stringNotLike: newStringNotLikeFunc,
|
||||||
|
ipAddress: newIPAddressFunc,
|
||||||
|
notIPAddress: newNotIPAddressFunc,
|
||||||
|
null: newNullFunc,
|
||||||
|
// Add new conditions here.
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON - decodes JSON data to Functions.
|
// UnmarshalJSON - decodes JSON data to Functions.
|
||||||
func (functions *Functions) UnmarshalJSON(data []byte) error {
|
func (functions *Functions) UnmarshalJSON(data []byte) error {
|
||||||
// As string kind, int kind then json.Unmarshaler is checked at
|
// As string kind, int kind then json.Unmarshaler is checked at
|
||||||
@ -119,38 +133,14 @@ func (functions *Functions) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var f Function
|
vfn, ok := conditionFuncMap[n]
|
||||||
switch n {
|
if !ok {
|
||||||
case stringEquals:
|
return fmt.Errorf("condition %v is not handled", n)
|
||||||
if f, err = newStringEqualsFunc(key, values); err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
f, err := vfn(key, values)
|
||||||
case stringNotEquals:
|
if err != nil {
|
||||||
if f, err = newStringNotEqualsFunc(key, values); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
case stringLike:
|
|
||||||
if f, err = newStringLikeFunc(key, values); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case stringNotLike:
|
|
||||||
if f, err = newStringNotLikeFunc(key, values); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case ipAddress:
|
|
||||||
if f, err = newIPAddressFunc(key, values); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case notIPAddress:
|
|
||||||
if f, err = newNotIPAddressFunc(key, values); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case null:
|
|
||||||
if f, err = newNullFunc(key, values); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%v is not handled", n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
funcs = append(funcs, f)
|
funcs = append(funcs, f)
|
||||||
|
@ -268,6 +268,11 @@ func TestFunctionsUnmarshalJSON(t *testing.T) {
|
|||||||
|
|
||||||
case3Data := []byte(`{}`)
|
case3Data := []byte(`{}`)
|
||||||
|
|
||||||
|
// Remove this test after supporting date conditions.
|
||||||
|
case4Data := []byte(`{
|
||||||
|
"DateEquals": { "aws:CurrentTime": "2013-06-30T00:00:00Z" }
|
||||||
|
}`)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
data []byte
|
data []byte
|
||||||
expectedResult Functions
|
expectedResult Functions
|
||||||
@ -278,6 +283,8 @@ func TestFunctionsUnmarshalJSON(t *testing.T) {
|
|||||||
{case2Data, NewFunctions(func6), false},
|
{case2Data, NewFunctions(func6), false},
|
||||||
// empty condition error.
|
// empty condition error.
|
||||||
{case3Data, nil, true},
|
{case3Data, nil, true},
|
||||||
|
// unsupported condition error.
|
||||||
|
{case4Data, nil, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
|
@ -68,17 +68,38 @@ const (
|
|||||||
|
|
||||||
// AWSSourceIP - key representing client's IP address (not intermittent proxies) of any API.
|
// AWSSourceIP - key representing client's IP address (not intermittent proxies) of any API.
|
||||||
AWSSourceIP = "aws:SourceIp"
|
AWSSourceIP = "aws:SourceIp"
|
||||||
|
|
||||||
|
// AWSUserAgent - key representing UserAgent header for any API.
|
||||||
|
AWSUserAgent = "aws:UserAgent"
|
||||||
|
|
||||||
|
// AWSSecureTransport - key representing if the clients request is authenticated or not.
|
||||||
|
AWSSecureTransport = "aws:SecureTransport"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AllSupportedKeys - is list of all all supported keys.
|
||||||
|
var AllSupportedKeys = []Key{
|
||||||
|
S3XAmzCopySource,
|
||||||
|
S3XAmzServerSideEncryption,
|
||||||
|
S3XAmzServerSideEncryptionAwsKMSKeyID,
|
||||||
|
S3XAmzMetadataDirective,
|
||||||
|
S3XAmzStorageClass,
|
||||||
|
S3LocationConstraint,
|
||||||
|
S3Prefix,
|
||||||
|
S3Delimiter,
|
||||||
|
S3MaxKeys,
|
||||||
|
AWSReferer,
|
||||||
|
AWSSourceIP,
|
||||||
|
AWSUserAgent,
|
||||||
|
AWSSecureTransport,
|
||||||
|
// Add new supported condition keys.
|
||||||
|
}
|
||||||
|
|
||||||
// IsValid - checks if key is valid or not.
|
// IsValid - checks if key is valid or not.
|
||||||
func (key Key) IsValid() bool {
|
func (key Key) IsValid() bool {
|
||||||
switch key {
|
for _, supKey := range AllSupportedKeys {
|
||||||
case S3XAmzCopySource, S3XAmzServerSideEncryption, S3XAmzServerSideEncryptionAwsKMSKeyID:
|
if supKey == key {
|
||||||
fallthrough
|
return true
|
||||||
case S3XAmzMetadataDirective, S3XAmzStorageClass, S3LocationConstraint, S3Prefix:
|
}
|
||||||
fallthrough
|
|
||||||
case S3Delimiter, S3MaxKeys, AWSReferer, AWSSourceIP:
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -24,20 +24,36 @@ import (
|
|||||||
type name string
|
type name string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stringEquals name = "StringEquals"
|
stringEquals name = "StringEquals"
|
||||||
stringNotEquals = "StringNotEquals"
|
stringNotEquals = "StringNotEquals"
|
||||||
stringLike = "StringLike"
|
stringEqualsIgnoreCase = "StringEqualsIgnoreCase"
|
||||||
stringNotLike = "StringNotLike"
|
stringNotEqualsIgnoreCase = "StringNotEqualsIgnoreCase"
|
||||||
ipAddress = "IpAddress"
|
stringLike = "StringLike"
|
||||||
notIPAddress = "NotIpAddress"
|
stringNotLike = "StringNotLike"
|
||||||
null = "Null"
|
binaryEquals = "BinaryEquals"
|
||||||
|
ipAddress = "IpAddress"
|
||||||
|
notIPAddress = "NotIpAddress"
|
||||||
|
null = "Null"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsValid - checks if name is valid or not.
|
// IsValid - checks if name is valid or not.
|
||||||
func (n name) IsValid() bool {
|
func (n name) IsValid() bool {
|
||||||
switch n {
|
for _, supn := range []name{
|
||||||
case stringEquals, stringNotEquals, stringLike, stringNotLike, ipAddress, notIPAddress, null:
|
stringEquals,
|
||||||
return true
|
stringNotEquals,
|
||||||
|
stringEqualsIgnoreCase,
|
||||||
|
stringNotEqualsIgnoreCase,
|
||||||
|
binaryEquals,
|
||||||
|
stringLike,
|
||||||
|
stringNotLike,
|
||||||
|
ipAddress,
|
||||||
|
notIPAddress,
|
||||||
|
null,
|
||||||
|
// Add new conditions here.
|
||||||
|
} {
|
||||||
|
if n == supn {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -20,8 +20,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/pkg/s3utils"
|
||||||
"github.com/minio/minio-go/pkg/set"
|
"github.com/minio/minio-go/pkg/set"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -127,11 +127,13 @@ func validateStringEqualsValues(n name, key Key, values set.StringSet) error {
|
|||||||
for _, s := range values.ToSlice() {
|
for _, s := range values.ToSlice() {
|
||||||
switch key {
|
switch key {
|
||||||
case S3XAmzCopySource:
|
case S3XAmzCopySource:
|
||||||
tokens := strings.SplitN(s, "/", 2)
|
bucket, object := path2BucketAndObject(s)
|
||||||
if len(tokens) < 2 {
|
if object == "" {
|
||||||
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzCopySource, n)
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzCopySource, n)
|
||||||
}
|
}
|
||||||
// FIXME: tokens[0] must be a valid bucket name.
|
if err := s3utils.CheckValidBucketName(bucket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case S3XAmzServerSideEncryption:
|
case S3XAmzServerSideEncryption:
|
||||||
if s != "aws:kms" && s != "AES256" {
|
if s != "aws:kms" && s != "AES256" {
|
||||||
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzServerSideEncryption, n)
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzServerSideEncryption, n)
|
||||||
|
157
pkg/policy/condition/stringequalsignorecasefunc.go
Normal file
157
pkg/policy/condition/stringequalsignorecasefunc.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package condition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/pkg/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toStringEqualsIgnoreCaseFuncString(n name, key Key, values set.StringSet) string {
|
||||||
|
valueStrings := values.ToSlice()
|
||||||
|
sort.Strings(valueStrings)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v:%v:%v", n, key, valueStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringEqualsIgnoreCaseFunc - String equals function. It checks whether value by Key in given
|
||||||
|
// values map is in condition values.
|
||||||
|
// For example,
|
||||||
|
// - if values = ["mybucket/foo"], at evaluate() it returns whether string
|
||||||
|
// in value map for Key is in values.
|
||||||
|
type stringEqualsIgnoreCaseFunc struct {
|
||||||
|
k Key
|
||||||
|
values set.StringSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate() - evaluates to check whether value by Key in given values is in
|
||||||
|
// condition values, ignores case.
|
||||||
|
func (f stringEqualsIgnoreCaseFunc) evaluate(values map[string][]string) bool {
|
||||||
|
requestValue, ok := values[http.CanonicalHeaderKey(f.k.Name())]
|
||||||
|
if !ok {
|
||||||
|
requestValue = values[f.k.Name()]
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range requestValue {
|
||||||
|
if !f.values.FuncMatch(strings.EqualFold, v).IsEmpty() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// key() - returns condition key which is used by this condition function.
|
||||||
|
func (f stringEqualsIgnoreCaseFunc) key() Key {
|
||||||
|
return f.k
|
||||||
|
}
|
||||||
|
|
||||||
|
// name() - returns "StringEqualsIgnoreCase" condition name.
|
||||||
|
func (f stringEqualsIgnoreCaseFunc) name() name {
|
||||||
|
return stringEqualsIgnoreCase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f stringEqualsIgnoreCaseFunc) String() string {
|
||||||
|
return toStringEqualsIgnoreCaseFuncString(stringEqualsIgnoreCase, f.k, f.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toMap - returns map representation of this function.
|
||||||
|
func (f stringEqualsIgnoreCaseFunc) toMap() map[Key]ValueSet {
|
||||||
|
if !f.k.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
values := NewValueSet()
|
||||||
|
for _, value := range f.values.ToSlice() {
|
||||||
|
values.Add(NewStringValue(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[Key]ValueSet{
|
||||||
|
f.k: values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringNotEqualsIgnoreCaseFunc - String not equals function. It checks whether value by Key in
|
||||||
|
// given values is NOT in condition values.
|
||||||
|
// For example,
|
||||||
|
// - if values = ["mybucket/foo"], at evaluate() it returns whether string
|
||||||
|
// in value map for Key is NOT in values.
|
||||||
|
type stringNotEqualsIgnoreCaseFunc struct {
|
||||||
|
stringEqualsIgnoreCaseFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate() - evaluates to check whether value by Key in given values is NOT in
|
||||||
|
// condition values.
|
||||||
|
func (f stringNotEqualsIgnoreCaseFunc) evaluate(values map[string][]string) bool {
|
||||||
|
return !f.stringEqualsIgnoreCaseFunc.evaluate(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// name() - returns "StringNotEqualsIgnoreCase" condition name.
|
||||||
|
func (f stringNotEqualsIgnoreCaseFunc) name() name {
|
||||||
|
return stringNotEqualsIgnoreCase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f stringNotEqualsIgnoreCaseFunc) String() string {
|
||||||
|
return toStringEqualsIgnoreCaseFuncString(stringNotEqualsIgnoreCase, f.stringEqualsIgnoreCaseFunc.k, f.stringEqualsIgnoreCaseFunc.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateStringEqualsIgnoreCaseValues(n name, key Key, values set.StringSet) error {
|
||||||
|
return validateStringEqualsValues(n, key, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newStringEqualsIgnoreCaseFunc - returns new StringEqualsIgnoreCase function.
|
||||||
|
func newStringEqualsIgnoreCaseFunc(key Key, values ValueSet) (Function, error) {
|
||||||
|
valueStrings, err := valuesToStringSlice(stringEqualsIgnoreCase, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewStringEqualsIgnoreCaseFunc(key, valueStrings...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStringEqualsIgnoreCaseFunc - returns new StringEqualsIgnoreCase function.
|
||||||
|
func NewStringEqualsIgnoreCaseFunc(key Key, values ...string) (Function, error) {
|
||||||
|
sset := set.CreateStringSet(values...)
|
||||||
|
if err := validateStringEqualsIgnoreCaseValues(stringEqualsIgnoreCase, key, sset); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stringEqualsIgnoreCaseFunc{key, sset}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newStringNotEqualsIgnoreCaseFunc - returns new StringNotEqualsIgnoreCase function.
|
||||||
|
func newStringNotEqualsIgnoreCaseFunc(key Key, values ValueSet) (Function, error) {
|
||||||
|
valueStrings, err := valuesToStringSlice(stringNotEqualsIgnoreCase, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewStringNotEqualsIgnoreCaseFunc(key, valueStrings...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStringNotEqualsIgnoreCaseFunc - returns new StringNotEqualsIgnoreCase function.
|
||||||
|
func NewStringNotEqualsIgnoreCaseFunc(key Key, values ...string) (Function, error) {
|
||||||
|
sset := set.CreateStringSet(values...)
|
||||||
|
if err := validateStringEqualsIgnoreCaseValues(stringNotEqualsIgnoreCase, key, sset); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stringNotEqualsIgnoreCaseFunc{stringEqualsIgnoreCaseFunc{key, sset}}, nil
|
||||||
|
}
|
720
pkg/policy/condition/stringequalsignorecasefunc_test.go
Normal file
720
pkg/policy/condition/stringequalsignorecasefunc_test.go
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package condition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringEqualsIgnoreCaseFuncEvaluate(t *testing.T) {
|
||||||
|
case1Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
values map[string][]string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"mybucket/myobject"}}, true},
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"yourbucket/myobject"}}, false},
|
||||||
|
{case1Function, map[string][]string{}, false},
|
||||||
|
{case1Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"AES256"}}, true},
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"aes256"}}, true},
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"aws:kms"}}, false},
|
||||||
|
{case2Function, map[string][]string{}, false},
|
||||||
|
{case2Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"REPLACE"}}, true},
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"replace"}}, true},
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"COPY"}}, false},
|
||||||
|
{case3Function, map[string][]string{}, false},
|
||||||
|
{case3Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"eu-west-1"}}, true},
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"us-east-1"}}, false},
|
||||||
|
{case4Function, map[string][]string{}, false},
|
||||||
|
{case4Function, map[string][]string{"delimiter": {"/"}}, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.evaluate(testCase.values)
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringEqualsIgnoreCaseFuncKey(t *testing.T) {
|
||||||
|
case1Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
expectedResult Key
|
||||||
|
}{
|
||||||
|
{case1Function, S3XAmzCopySource},
|
||||||
|
{case2Function, S3XAmzServerSideEncryption},
|
||||||
|
{case3Function, S3XAmzMetadataDirective},
|
||||||
|
{case4Function, S3LocationConstraint},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.key()
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringEqualsIgnoreCaseFuncToMap(t *testing.T) {
|
||||||
|
case1Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case1Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(NewStringValue("mybucket/myobject")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(NewStringValue("AES256")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(NewStringValue("REPLACE")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(NewStringValue("eu-west-1")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
f Function
|
||||||
|
expectedResult map[Key]ValueSet
|
||||||
|
}{
|
||||||
|
{case1Function, case1Result},
|
||||||
|
{case2Function, case2Result},
|
||||||
|
{case3Function, case3Result},
|
||||||
|
{case4Function, case4Result},
|
||||||
|
{case5Function, case5Result},
|
||||||
|
{case6Function, case6Result},
|
||||||
|
{case7Function, case7Result},
|
||||||
|
{case8Function, case8Result},
|
||||||
|
{&stringEqualsFunc{}, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.f.toMap()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringNotEqualsIgnoreCaseFuncEvaluate(t *testing.T) {
|
||||||
|
case1Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
values map[string][]string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"mybucket/myobject"}}, false},
|
||||||
|
{case1Function, map[string][]string{"x-amz-copy-source": {"yourbucket/myobject"}}, true},
|
||||||
|
{case1Function, map[string][]string{}, true},
|
||||||
|
{case1Function, map[string][]string{"delimiter": {"/"}}, true},
|
||||||
|
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"AES256"}}, false},
|
||||||
|
{case2Function, map[string][]string{"x-amz-server-side-encryption": {"aws:kms"}}, true},
|
||||||
|
{case2Function, map[string][]string{}, true},
|
||||||
|
{case2Function, map[string][]string{"delimiter": {"/"}}, true},
|
||||||
|
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"REPLACE"}}, false},
|
||||||
|
{case3Function, map[string][]string{"x-amz-metadata-directive": {"COPY"}}, true},
|
||||||
|
{case3Function, map[string][]string{}, true},
|
||||||
|
{case3Function, map[string][]string{"delimiter": {"/"}}, true},
|
||||||
|
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"eu-west-1"}}, false},
|
||||||
|
{case4Function, map[string][]string{"LocationConstraint": {"us-east-1"}}, true},
|
||||||
|
{case4Function, map[string][]string{}, true},
|
||||||
|
{case4Function, map[string][]string{"delimiter": {"/"}}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.evaluate(testCase.values)
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringNotEqualsIgnoreCaseFuncKey(t *testing.T) {
|
||||||
|
case1Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
function Function
|
||||||
|
expectedResult Key
|
||||||
|
}{
|
||||||
|
{case1Function, S3XAmzCopySource},
|
||||||
|
{case2Function, S3XAmzServerSideEncryption},
|
||||||
|
{case3Function, S3XAmzMetadataDirective},
|
||||||
|
{case4Function, S3LocationConstraint},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.function.key()
|
||||||
|
|
||||||
|
if result != testCase.expectedResult {
|
||||||
|
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringNotEqualsIgnoreCaseFuncToMap(t *testing.T) {
|
||||||
|
case1Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case1Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(NewStringValue("mybucket/myobject")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Result := map[Key]ValueSet{
|
||||||
|
S3XAmzCopySource: NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(NewStringValue("AES256")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Result := map[Key]ValueSet{
|
||||||
|
S3XAmzServerSideEncryption: NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(NewStringValue("REPLACE")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Result := map[Key]ValueSet{
|
||||||
|
S3XAmzMetadataDirective: NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(NewStringValue("eu-west-1")),
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Result := map[Key]ValueSet{
|
||||||
|
S3LocationConstraint: NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
f Function
|
||||||
|
expectedResult map[Key]ValueSet
|
||||||
|
}{
|
||||||
|
{case1Function, case1Result},
|
||||||
|
{case2Function, case2Result},
|
||||||
|
{case3Function, case3Result},
|
||||||
|
{case4Function, case4Result},
|
||||||
|
{case5Function, case5Result},
|
||||||
|
{case6Function, case6Result},
|
||||||
|
{case7Function, case7Result},
|
||||||
|
{case8Function, case8Result},
|
||||||
|
{&stringNotEqualsFunc{}, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := testCase.f.toMap()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewStringEqualsIgnoreCaseFunc(t *testing.T) {
|
||||||
|
case1Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newStringEqualsIgnoreCaseFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newStringEqualsIgnoreCaseFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
key Key
|
||||||
|
values ValueSet
|
||||||
|
expectedResult Function
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")), case1Function, false},
|
||||||
|
{S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
), case2Function, false},
|
||||||
|
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")), case3Function, false},
|
||||||
|
{S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
), case4Function, false},
|
||||||
|
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")), case5Function, false},
|
||||||
|
{S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
), case6Function, false},
|
||||||
|
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")), case7Function, false},
|
||||||
|
{S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
), case8Function, false},
|
||||||
|
|
||||||
|
// Unsupported value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256"), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE"), NewIntValue(7)), nil, true},
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1"), NewIntValue(7)), nil, true},
|
||||||
|
|
||||||
|
// Invalid value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket")), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("SSE-C")), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("DUPLICATE")), nil, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result, err := newStringEqualsIgnoreCaseFunc(testCase.key, testCase.values)
|
||||||
|
expectErr := (err != nil)
|
||||||
|
|
||||||
|
if expectErr != testCase.expectErr {
|
||||||
|
t.Fatalf("case %v: error: expected: %v, got: %v\n", i+1, testCase.expectErr, expectErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !testCase.expectErr {
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewStringNotEqualsIgnoreCaseFunc(t *testing.T) {
|
||||||
|
case1Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case2Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case3Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case4Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case5Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case6Function, err := newStringNotEqualsIgnoreCaseFunc(S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case7Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case8Function, err := newStringNotEqualsIgnoreCaseFunc(S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error. %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
key Key
|
||||||
|
values ValueSet
|
||||||
|
expectedResult Function
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")), case1Function, false},
|
||||||
|
{S3XAmzCopySource,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("mybucket/myobject"),
|
||||||
|
NewStringValue("yourbucket/myobject"),
|
||||||
|
), case2Function, false},
|
||||||
|
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")), case3Function, false},
|
||||||
|
{S3XAmzServerSideEncryption,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("AES256"),
|
||||||
|
NewStringValue("aws:kms"),
|
||||||
|
), case4Function, false},
|
||||||
|
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE")), case5Function, false},
|
||||||
|
{S3XAmzMetadataDirective,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("REPLACE"),
|
||||||
|
NewStringValue("COPY"),
|
||||||
|
), case6Function, false},
|
||||||
|
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1")), case7Function, false},
|
||||||
|
{S3LocationConstraint,
|
||||||
|
NewValueSet(
|
||||||
|
NewStringValue("eu-west-1"),
|
||||||
|
NewStringValue("us-west-1"),
|
||||||
|
), case8Function, false},
|
||||||
|
|
||||||
|
// Unsupported value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256"), NewIntValue(7)), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPLACE"), NewIntValue(7)), nil, true},
|
||||||
|
{S3LocationConstraint, NewValueSet(NewStringValue("eu-west-1"), NewIntValue(7)), nil, true},
|
||||||
|
|
||||||
|
// Invalid value error.
|
||||||
|
{S3XAmzCopySource, NewValueSet(NewStringValue("mybucket")), nil, true},
|
||||||
|
{S3XAmzServerSideEncryption, NewValueSet(NewStringValue("SSE-C")), nil, true},
|
||||||
|
{S3XAmzMetadataDirective, NewValueSet(NewStringValue("DUPLICATE")), nil, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result, err := newStringNotEqualsIgnoreCaseFunc(testCase.key, testCase.values)
|
||||||
|
expectErr := (err != nil)
|
||||||
|
|
||||||
|
if expectErr != testCase.expectErr {
|
||||||
|
t.Fatalf("case %v: error: expected: %v, got: %v\n", i+1, testCase.expectErr, expectErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !testCase.expectErr {
|
||||||
|
if !reflect.DeepEqual(result, testCase.expectedResult) {
|
||||||
|
t.Fatalf("case %v: result: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,8 +20,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/pkg/s3utils"
|
||||||
"github.com/minio/minio-go/pkg/set"
|
"github.com/minio/minio-go/pkg/set"
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
)
|
)
|
||||||
@ -118,12 +118,13 @@ func validateStringLikeValues(n name, key Key, values set.StringSet) error {
|
|||||||
for _, s := range values.ToSlice() {
|
for _, s := range values.ToSlice() {
|
||||||
switch key {
|
switch key {
|
||||||
case S3XAmzCopySource:
|
case S3XAmzCopySource:
|
||||||
tokens := strings.SplitN(s, "/", 2)
|
bucket, object := path2BucketAndObject(s)
|
||||||
if len(tokens) < 2 {
|
if object == "" {
|
||||||
return fmt.Errorf("invalid value '%v' for '%v' in %v condition", s, key, n)
|
return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzCopySource, n)
|
||||||
|
}
|
||||||
|
if err := s3utils.CheckValidBucketName(bucket); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: tokens[0] must be a valid bucket name.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,26 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Splits an incoming path into bucket and object components.
|
||||||
|
func path2BucketAndObject(path string) (bucket, object string) {
|
||||||
|
// Skip the first element if it is '/', split the rest.
|
||||||
|
path = strings.TrimPrefix(path, "/")
|
||||||
|
pathComponents := strings.SplitN(path, "/", 2)
|
||||||
|
|
||||||
|
// Save the bucket and object extracted from path.
|
||||||
|
switch len(pathComponents) {
|
||||||
|
case 1:
|
||||||
|
bucket = pathComponents[0]
|
||||||
|
case 2:
|
||||||
|
bucket = pathComponents[0]
|
||||||
|
object = pathComponents[1]
|
||||||
|
}
|
||||||
|
return bucket, object
|
||||||
|
}
|
||||||
|
|
||||||
// Value - is enum type of string, int or bool.
|
// Value - is enum type of string, int or bool.
|
||||||
type Value struct {
|
type Value struct {
|
||||||
t reflect.Kind
|
t reflect.Kind
|
||||||
|
Loading…
x
Reference in New Issue
Block a user