// ConditionKeyMap.Remove() is called and the result is validated.
func TestConditionKeyMapRemove(t *testing.T) {
	condKeyMap := make(ConditionKeyMap)
	condKeyMap.Add("s3:prefix", set.CreateStringSet("hello", "world"))

	testCases := []struct {
		key            string
		value          set.StringSet
		expectedResult string
	}{
		// Remove non-existent key and value.
		{"s3:myprefix", set.CreateStringSet("hello"), `{"s3:prefix":["hello","world"]}`},
		// Remove existing key and value.
		{"s3:prefix", set.CreateStringSet("hello"), `{"s3:prefix":["world"]}`},
		// Remove existing key to make the key also removed.
		{"s3:prefix", set.CreateStringSet("world"), `{}`},
	}

	for _, testCase := range testCases {
		condKeyMap.Remove(testCase.key, testCase.value)
		if data, err := json.Marshal(condKeyMap); err != nil {
			t.Fatalf("Unable to marshal ConditionKeyMap to JSON, %s", err)
		} else {
			if string(data) != testCase.expectedResult {
				t.Fatalf("case: %+v: expected: %s, got: %s", testCase, testCase.expectedResult, string(data))
			}
		}
	}
}
// ConditionMap.Add() is called and the result is validated.
func TestConditionMapAdd(t *testing.T) {
	condMap := make(ConditionMap)

	condKeyMap1 := make(ConditionKeyMap)
	condKeyMap1.Add("s3:prefix", set.CreateStringSet("hello"))

	condKeyMap2 := make(ConditionKeyMap)
	condKeyMap2.Add("s3:prefix", set.CreateStringSet("hello", "world"))

	testCases := []struct {
		key            string
		value          ConditionKeyMap
		expectedResult string
	}{
		// Add new key and value.
		{"StringEquals", condKeyMap1, `{"StringEquals":{"s3:prefix":["hello"]}}`},
		// Add existing key and value.
		{"StringEquals", condKeyMap1, `{"StringEquals":{"s3:prefix":["hello"]}}`},
		// Add existing key and not value.
		{"StringEquals", condKeyMap2, `{"StringEquals":{"s3:prefix":["hello","world"]}}`},
	}

	for _, testCase := range testCases {
		condMap.Add(testCase.key, testCase.value)
		if data, err := json.Marshal(condMap); err != nil {
			t.Fatalf("Unable to marshal ConditionKeyMap to JSON, %s", err)
		} else {
			if string(data) != testCase.expectedResult {
				t.Fatalf("case: %+v: expected: %s, got: %s", testCase, testCase.expectedResult, string(data))
			}
		}
	}
}
// Obtain object statements for write only bucketPolicy.
func getWriteOnlyObjectStatement(bucketName, objectPrefix string) policyStatement {
	objectResourceStatement := policyStatement{}
	objectResourceStatement.Effect = "Allow"
	objectResourceStatement.Principal.AWS = set.CreateStringSet([]string{"*"}...)
	objectResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName+"/"+objectPrefix+"*")}...)
	objectResourceStatement.Actions = set.CreateStringSet(writeOnlyObjectActions...)
	return objectResourceStatement
}
// Obtain object statement for read-write bucketPolicy.
func getReadWriteBucketStatement(bucketName, objectPrefix string) policyStatement {
	bucketResourceStatement := policyStatement{}
	bucketResourceStatement.Effect = "Allow"
	bucketResourceStatement.Principal.AWS = set.CreateStringSet([]string{"*"}...)
	bucketResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName)}...)
	bucketResourceStatement.Actions = set.CreateStringSet(readWriteBucketActions...)
	return bucketResourceStatement
}
// Obtain bucket statement for read-write bucketPolicy.
func getReadWriteObjectStatement(bucketName, objectPrefix string) policyStatement {
	objectResourceStatement := policyStatement{}
	objectResourceStatement.Effect = "Allow"
	objectResourceStatement.Principal = map[string]interface{}{
		"AWS": "*",
	}
	objectResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName+"/"+objectPrefix+"*")}...)
	objectResourceStatement.Actions = set.CreateStringSet(readWriteObjectActions...)
	return objectResourceStatement
}
// Obtain bucket statement for read only bucketPolicy.
func getReadOnlyBucketStatement(bucketName, objectPrefix string) policyStatement {
	bucketResourceStatement := policyStatement{}
	bucketResourceStatement.Effect = "Allow"
	bucketResourceStatement.Principal = map[string]interface{}{
		"AWS": "*",
	}
	bucketResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName)}...)
	bucketResourceStatement.Actions = set.CreateStringSet(readOnlyBucketActions...)
	return bucketResourceStatement
}
Exemplo n.º 7
0
// Returns new statements with bucket actions for given policy.
func newBucketStatement(policy BucketPolicy, bucketName string, prefix string) (statements []Statement) {
	statements = []Statement{}
	if policy == BucketPolicyNone || bucketName == "" {
		return statements
	}

	bucketResource := set.CreateStringSet(awsResourcePrefix + bucketName)

	statement := Statement{
		Actions:   commonBucketActions,
		Effect:    "Allow",
		Principal: User{AWS: set.CreateStringSet("*")},
		Resources: bucketResource,
		Sid:       "",
	}
	statements = append(statements, statement)

	if policy == BucketPolicyReadOnly || policy == BucketPolicyReadWrite {
		statement = Statement{
			Actions:   readOnlyBucketActions,
			Effect:    "Allow",
			Principal: User{AWS: set.CreateStringSet("*")},
			Resources: bucketResource,
			Sid:       "",
		}
		if prefix != "" {
			condKeyMap := make(ConditionKeyMap)
			condKeyMap.Add("s3:prefix", set.CreateStringSet(prefix))
			condMap := make(ConditionMap)
			condMap.Add("StringEquals", condKeyMap)
			statement.Conditions = condMap
		}
		statements = append(statements, statement)
	}

	if policy == BucketPolicyWriteOnly || policy == BucketPolicyReadWrite {
		statement = Statement{
			Actions:   writeOnlyBucketActions,
			Effect:    "Allow",
			Principal: User{AWS: set.CreateStringSet("*")},
			Resources: bucketResource,
			Sid:       "",
		}
		statements = append(statements, statement)
	}

	return statements
}
// CopyConditionKeyMap() is called and the result is validated.
func TestCopyConditionKeyMap(t *testing.T) {
	emptyCondKeyMap := make(ConditionKeyMap)
	nonEmptyCondKeyMap := make(ConditionKeyMap)
	nonEmptyCondKeyMap.Add("s3:prefix", set.CreateStringSet("hello", "world"))

	testCases := []struct {
		condKeyMap     ConditionKeyMap
		expectedResult string
	}{
		// To test empty ConditionKeyMap.
		{emptyCondKeyMap, `{}`},
		// To test non-empty ConditionKeyMap.
		{nonEmptyCondKeyMap, `{"s3:prefix":["hello","world"]}`},
	}

	for _, testCase := range testCases {
		condKeyMap := CopyConditionKeyMap(testCase.condKeyMap)
		if data, err := json.Marshal(condKeyMap); err != nil {
			t.Fatalf("Unable to marshal ConditionKeyMap to JSON, %s", err)
		} else {
			if string(data) != testCase.expectedResult {
				t.Fatalf("case: %+v: expected: %s, got: %s", testCase, testCase.expectedResult, string(data))
			}
		}
	}
}
Exemplo n.º 9
0
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
// Enforces bucket policies for a bucket for a given tatusaction.
func enforceBucketPolicy(bucket string, action string, reqURL *url.URL) (s3Error APIErrorCode) {
	if !IsValidBucketName(bucket) {
		return ErrInvalidBucketName
	}
	// Fetch bucket policy, if policy is not set return access denied.
	policy := globalBucketPolicies.GetBucketPolicy(bucket)
	if policy == nil {
		return ErrAccessDenied
	}

	// Construct resource in 'arn:aws:s3:::examplebucket/object' format.
	resource := AWSResourcePrefix + strings.TrimSuffix(strings.TrimPrefix(reqURL.Path, "/"), "/")

	// Get conditions for policy verification.
	conditionKeyMap := make(map[string]set.StringSet)
	for queryParam := range reqURL.Query() {
		conditionKeyMap[queryParam] = set.CreateStringSet(reqURL.Query().Get(queryParam))
	}

	// Validate action, resource and conditions with current policy statements.
	if !bucketPolicyEvalStatements(action, resource, conditionKeyMap, policy.Statements) {
		return ErrAccessDenied
	}
	return ErrNone
}
// mergeConditionMap() is called and the result is validated.
func TestMergeConditionMap(t *testing.T) {
	condKeyMap1 := make(ConditionKeyMap)
	condKeyMap1.Add("s3:prefix", set.CreateStringSet("hello"))
	condMap1 := make(ConditionMap)
	condMap1.Add("StringEquals", condKeyMap1)

	condKeyMap2 := make(ConditionKeyMap)
	condKeyMap2.Add("s3:prefix", set.CreateStringSet("world"))
	condMap2 := make(ConditionMap)
	condMap2.Add("StringEquals", condKeyMap2)

	condMap3 := make(ConditionMap)
	condMap3.Add("StringNotEquals", condKeyMap2)

	testCases := []struct {
		condMap1       ConditionMap
		condMap2       ConditionMap
		expectedResult string
	}{
		// Both arguments are empty.
		{make(ConditionMap), make(ConditionMap), `{}`},
		// First argument is empty.
		{make(ConditionMap), condMap1, `{"StringEquals":{"s3:prefix":["hello"]}}`},
		// Second argument is empty.
		{condMap1, make(ConditionMap), `{"StringEquals":{"s3:prefix":["hello"]}}`},
		// Both arguments are same value.
		{condMap1, condMap1, `{"StringEquals":{"s3:prefix":["hello"]}}`},
		// Value of second argument will be merged.
		{condMap1, condMap2, `{"StringEquals":{"s3:prefix":["hello","world"]}}`},
		// second argument will be added.
		{condMap1, condMap3, `{"StringEquals":{"s3:prefix":["hello"]},"StringNotEquals":{"s3:prefix":["world"]}}`},
	}

	for _, testCase := range testCases {
		condMap := mergeConditionMap(testCase.condMap1, testCase.condMap2)
		if data, err := json.Marshal(condMap); err != nil {
			t.Fatalf("Unable to marshal ConditionKeyMap to JSON, %s", err)
		} else {
			if string(data) != testCase.expectedResult {
				t.Fatalf("case: %+v: expected: %s, got: %s", testCase, testCase.expectedResult, string(data))
			}
		}
	}
}
// Tests validate Bucket policy resource matcher.
func TestBucketPolicyResourceMatch(t *testing.T) {

	// generates statement with given resource..
	generateStatement := func(resource string) policyStatement {
		statement := policyStatement{}
		statement.Resources = set.CreateStringSet([]string{resource}...)
		return statement
	}

	// generates resource prefix.
	generateResource := func(bucketName, objectName string) string {
		return AWSResourcePrefix + bucketName + "/" + objectName
	}

	testCases := []struct {
		resourceToMatch       string
		statement             policyStatement
		expectedResourceMatch bool
	}{
		// Test case 1-4.
		// Policy with resource ending with bucket/* allows access to all objects inside the given bucket.
		{generateResource("minio-bucket", ""), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/*")), true},
		{generateResource("minio-bucket", ""), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/*")), true},
		{generateResource("minio-bucket", ""), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/*")), true},
		{generateResource("minio-bucket", ""), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/*")), true},
		// Test case - 5.
		// Policy with resource ending with bucket/oo* should not allow access to bucket/output.txt.
		{generateResource("minio-bucket", "output.txt"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/oo*")), false},
		// Test case - 6.
		// Policy with resource ending with bucket/oo* should allow access to bucket/ootput.txt.
		{generateResource("minio-bucket", "ootput.txt"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/oo*")), true},
		// Test case - 7.
		// Policy with resource ending with bucket/oo* allows access to all sub-dirs starting with "oo" inside given bucket.
		{generateResource("minio-bucket", "oop-bucket/my-file"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/oo*")), true},
		// Test case - 8.
		{generateResource("minio-bucket", "Asia/India/1.pjg"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/Asia/Japan/*")), false},
		// Test case - 9.
		{generateResource("minio-bucket", "Asia/India/1.pjg"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix, "minio-bucket"+"/Asia/Japan/*")), false},
		// Test case - 10.
		// Proves that the name space is flat.
		{generateResource("minio-bucket", "Africa/Bihar/India/design_info.doc/Bihar"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix,
			"minio-bucket"+"/*/India/*/Bihar")), true},
		// Test case - 11.
		// Proves that the name space is flat.
		{generateResource("minio-bucket", "Asia/China/India/States/Bihar/output.txt"), generateStatement(fmt.Sprintf("%s%s", AWSResourcePrefix,
			"minio-bucket"+"/*/India/*/Bihar/*")), true},
	}
	for i, testCase := range testCases {
		actualResourceMatch := bucketPolicyResourceMatch(testCase.resourceToMatch, testCase.statement)
		if testCase.expectedResourceMatch != actualResourceMatch {
			t.Errorf("Test %d: Expected Resource match to be `%v`, but instead found it to be `%v`", i+1, testCase.expectedResourceMatch, actualResourceMatch)
		}
	}
}
// Tests validate Action validator.
func TestIsValidActions(t *testing.T) {
	testCases := []struct {
		// input.
		actions set.StringSet
		// expected output.
		err error
		// flag indicating whether the test should pass.
		shouldPass bool
	}{
		// Inputs with unsupported Action.
		// Test case - 1.
		// "s3:ListObject" is an invalid Action.
		{set.CreateStringSet([]string{"s3:GetObject", "s3:ListObject", "s3:RemoveObject"}...),
			errors.New("Unsupported actions found: ‘set.StringSet{\"s3:RemoveObject\":struct {}{}, \"s3:ListObject\":struct {}{}}’, please validate your policy document."), false},
		// Test case - 2.
		// Empty Actions.
		{set.CreateStringSet([]string{}...), errors.New("Action list cannot be empty."), false},
		// Test case - 3.
		// "s3:DeleteEverything"" is an invalid Action.
		{set.CreateStringSet([]string{"s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteEverything"}...),
			errors.New("Unsupported actions found: ‘set.StringSet{\"s3:DeleteEverything\":struct {}{}}’, please validate your policy document."), false},
		// Inputs with valid Action.
		// Test Case - 4.
		{set.CreateStringSet([]string{
			"s3:*", "*", "s3:GetObject", "s3:ListBucket",
			"s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject",
			"s3:AbortMultipartUpload", "s3:ListBucketMultipartUploads",
			"s3:ListMultipartUploadParts"}...), nil, true},
	}
	for i, testCase := range testCases {
		err := isValidActions(testCase.actions)
		if err != nil && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error())
		}
		if err == nil && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error())
		}
	}
}
Exemplo n.º 13
0
// isValidPrincipals - are valid principals.
func isValidPrincipals(principals set.StringSet) (err error) {
	// Statement principal should have a value.
	if len(principals) == 0 {
		err = errors.New("Principal cannot be empty.")
		return err
	}
	if unsuppPrincipals := principals.Difference(set.CreateStringSet([]string{"*"}...)); !unsuppPrincipals.IsEmpty() {
		// Minio does not support or implement IAM, "*" is the only valid value.
		// Amazon s3 doc on principals: http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Principal
		err = fmt.Errorf("Unsupported principals found: ‘%#v’, please validate your policy document.", unsuppPrincipals)
		return err
	}
	return nil
}
Exemplo n.º 14
0
// Returns new statements contains object actions for given policy.
func newObjectStatement(policy BucketPolicy, bucketName string, prefix string) (statements []Statement) {
	statements = []Statement{}
	if policy == BucketPolicyNone || bucketName == "" {
		return statements
	}

	statement := Statement{
		Effect:    "Allow",
		Principal: User{AWS: set.CreateStringSet("*")},
		Resources: set.CreateStringSet(awsResourcePrefix + bucketName + "/" + prefix + "*"),
		Sid:       "",
	}

	if policy == BucketPolicyReadOnly {
		statement.Actions = readOnlyObjectActions
	} else if policy == BucketPolicyWriteOnly {
		statement.Actions = writeOnlyObjectActions
	} else if policy == BucketPolicyReadWrite {
		statement.Actions = readWriteObjectActions
	}

	statements = append(statements, statement)
	return statements
}
Exemplo n.º 15
0
// Parse principals parses a incoming json. Handles cases for
// these three combinations.
// - "Principal": "*",
// - "Principal": { "AWS" : "*" }
// - "Principal": { "AWS" : [ "*" ]}
func parsePrincipals(principal interface{}) set.StringSet {
	principals, ok := principal.(map[string]interface{})
	if !ok {
		var principalStr string
		principalStr, ok = principal.(string)
		if ok {
			return set.CreateStringSet(principalStr)
		}
	} // else {
	var principalStrs []string
	for _, p := range principals {
		principalStr, isStr := p.(string)
		if !isStr {
			principalsAdd, isInterface := p.([]interface{})
			if !isInterface {
				principalStrsAddr, isStrs := p.([]string)
				if !isStrs {
					continue
				}
				principalStrs = append(principalStrs, principalStrsAddr...)
			} else {
				for _, pa := range principalsAdd {
					var pstr string
					pstr, isStr = pa.(string)
					if !isStr {
						continue
					}
					principalStrs = append(principalStrs, pstr)
				}
			}
			continue
		} // else {
		principalStrs = append(principalStrs, principalStr)
	}
	return set.CreateStringSet(principalStrs...)
}
// Tests validate Resources validator.
func TestIsValidResources(t *testing.T) {
	testCases := []struct {
		// input.
		resources []string
		// expected output.
		err error
		// flag indicating whether the test should pass.
		shouldPass bool
	}{
		// Inputs with unsupported Action.
		// Test case - 1.
		// Empty Resources.
		{[]string{}, errors.New("Resource list cannot be empty."), false},
		// Test case - 2.
		// A valid resource should have prefix "arn:aws:s3:::".
		{[]string{"my-resource"}, errors.New("Unsupported resource style found: ‘my-resource’, please validate your policy document."), false},
		// Test case - 3.
		// A Valid resource should have bucket name followed by "arn:aws:s3:::".
		{[]string{"arn:aws:s3:::"}, errors.New("Invalid resource style found: ‘arn:aws:s3:::’, please validate your policy document."), false},
		// Test Case - 4.
		// Valid resource shouldn't have slash('/') followed by "arn:aws:s3:::".
		{[]string{"arn:aws:s3:::/"}, errors.New("Invalid resource style found: ‘arn:aws:s3:::/’, please validate your policy document."), false},

		// Test cases with valid Resources.
		{[]string{"arn:aws:s3:::my-bucket"}, nil, true},
		{[]string{"arn:aws:s3:::my-bucket/Asia/*"}, nil, true},
		{[]string{"arn:aws:s3:::my-bucket/Asia/India/*"}, nil, true},
	}
	for i, testCase := range testCases {
		err := isValidResources(set.CreateStringSet(testCase.resources...))
		if err != nil && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error())
		}
		if err == nil && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error())
		}
		// Failed as expected, but does it fail for the expected reason.
		if err != nil && !testCase.shouldPass {
			if err.Error() != testCase.err.Error() {
				t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error())
			}
		}
	}
}
Exemplo n.º 17
0
func waitForFormattingDisks(disks, ignoredDisks []string) ([]StorageAPI, error) {
	// FS Setup
	if len(disks) == 1 {
		storage, err := newStorageAPI(disks[0])
		if err != nil && err != errDiskNotFound {
			return nil, err
		}
		return []StorageAPI{storage}, nil
	}

	// XL Setup
	if err := checkSufficientDisks(disks); err != nil {
		return nil, err
	}

	disksSet := set.NewStringSet()
	if len(ignoredDisks) > 0 {
		disksSet = set.CreateStringSet(ignoredDisks...)
	}
	// Bootstrap disks.
	storageDisks := make([]StorageAPI, len(disks))
	for index, disk := range disks {
		// Check if disk is ignored.
		if disksSet.Contains(disk) {
			// Set this situation as disk not found.
			storageDisks[index] = nil
			continue
		}
		// Intentionally ignore disk not found errors. XL is designed
		// to handle these errors internally.
		storage, err := newStorageAPI(disk)
		if err != nil && err != errDiskNotFound {
			return nil, err
		}
		storageDisks[index] = storage
	}
	// Start wait loop retrying formatting disks.
	return retryFormattingDisks(disks, storageDisks)
}
Exemplo n.º 18
0
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
// Enforces bucket policies for a bucket for a given tatusaction.
func enforceBucketPolicy(bucket string, action string, reqURL *url.URL) (s3Error APIErrorCode) {
	// Verify if bucket actually exists
	if err := isBucketExist(bucket, newObjectLayerFn()); err != nil {
		err = errorCause(err)
		switch err.(type) {
		case BucketNameInvalid:
			// Return error for invalid bucket name.
			return ErrInvalidBucketName
		case BucketNotFound:
			// For no bucket found we return NoSuchBucket instead.
			return ErrNoSuchBucket
		}
		errorIf(err, "Unable to read bucket policy.")
		// Return internal error for any other errors so that we can investigate.
		return ErrInternalError
	}

	// Fetch bucket policy, if policy is not set return access denied.
	policy := globalBucketPolicies.GetBucketPolicy(bucket)
	if policy == nil {
		return ErrAccessDenied
	}

	// Construct resource in 'arn:aws:s3:::examplebucket/object' format.
	resource := AWSResourcePrefix + strings.TrimSuffix(strings.TrimPrefix(reqURL.Path, "/"), "/")

	// Get conditions for policy verification.
	conditionKeyMap := make(map[string]set.StringSet)
	for queryParam := range reqURL.Query() {
		conditionKeyMap[queryParam] = set.CreateStringSet(reqURL.Query().Get(queryParam))
	}

	// Validate action, resource and conditions with current policy statements.
	if !bucketPolicyEvalStatements(action, resource, conditionKeyMap, policy.Statements) {
		return ErrAccessDenied
	}
	return ErrNone
}
// Tests validate principals validator.
func TestIsValidPrincipals(t *testing.T) {
	testCases := []struct {
		// input.
		principals []string
		// expected output.
		err error
		// flag indicating whether the test should pass.
		shouldPass bool
	}{
		// Inputs with unsupported Principals.
		// Test case - 1.
		// Empty Principals list.
		{[]string{}, errors.New("Principal cannot be empty."), false},
		// Test case - 2.
		// "*" is the only valid principal.
		{[]string{"my-principal"}, errors.New("Unsupported principals found: ‘set.StringSet{\"my-principal\":struct {}{}}’, please validate your policy document."), false},
		// Test case - 3.
		{[]string{"*", "111122233"}, errors.New("Unsupported principals found: ‘set.StringSet{\"111122233\":struct {}{}}’, please validate your policy document."), false},
		// Test case - 4.
		// Test case with valid principal value.
		{[]string{"*"}, nil, true},
	}
	for i, testCase := range testCases {
		err := isValidPrincipals(set.CreateStringSet(testCase.principals...))
		if err != nil && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error())
		}
		if err == nil && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error())
		}
		// Failed as expected, but does it fail for the expected reason.
		if err != nil && !testCase.shouldPass {
			if err.Error() != testCase.err.Error() {
				t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error())
			}
		}
	}
}
Exemplo n.º 20
0
	"io"
	"path"
	"sort"
	"strings"

	"github.com/minio/minio-go/pkg/set"
)

const (
	// AWSResourcePrefix - bucket policy resource prefix.
	AWSResourcePrefix = "arn:aws:s3:::"
)

// supportedActionMap - lists all the actions supported by minio.
var supportedActionMap = set.CreateStringSet("*", "*", "s3:*", "s3:GetObject",
	"s3:ListBucket", "s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject",
	"s3:AbortMultipartUpload", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts")

// supported Conditions type.
var supportedConditionsType = set.CreateStringSet("StringEquals", "StringNotEquals")

// Validate s3:prefix, s3:max-keys are present if not
// supported keys for the conditions.
var supportedConditionsKey = set.CreateStringSet("s3:prefix", "s3:max-keys")

// supportedEffectMap - supported effects.
var supportedEffectMap = set.CreateStringSet("Allow", "Deny")

// policyUser - canonical users list.
type policyUser struct {
	AWS           set.StringSet `json:"AWS,omitempty"`
// Tests validate parsing of BucketAccessPolicy.
func TestParseBucketPolicy(t *testing.T) {
	// set Unsupported Actions.
	setUnsupportedActions := func(statements []policyStatement) []policyStatement {
		// "s3:DeleteEverything"" is an Unsupported Action.
		statements[0].Actions = set.CreateStringSet([]string{"s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteEverything"}...)
		return statements
	}
	// set unsupported Effect.
	setUnsupportedEffect := func(statements []policyStatement) []policyStatement {
		// Effect "Don't allow" is Unsupported.
		statements[0].Effect = "DontAllow"
		return statements
	}
	// set unsupported principals.
	setUnsupportedPrincipals := func(statements []policyStatement) []policyStatement {
		// "User1111"" is an Unsupported Principal.
		statements[0].Principal.AWS = set.CreateStringSet([]string{"*", "User1111"}...)
		return statements
	}
	// set unsupported Resources.
	setUnsupportedResources := func(statements []policyStatement) []policyStatement {
		// "s3:DeleteEverything"" is an Unsupported Action.
		statements[0].Resources = set.CreateStringSet([]string{"my-resource"}...)
		return statements
	}
	// List of bucketPolicy used for test cases.
	bucketAccesPolicies := []bucketPolicy{
		// bucketPolicy - 0.
		// bucketPolicy statement empty.
		{Version: "1.0"},
		// bucketPolicy - 1.
		// bucketPolicy version empty.
		{Version: "", Statements: []policyStatement{}},
		// bucketPolicy - 2.
		// Readonly bucketPolicy.
		{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket", "")},
		// bucketPolicy - 3.
		// Read-Write bucket policy.
		{Version: "1.0", Statements: getReadWriteStatement("minio-bucket", "Asia/")},
		// bucketPolicy - 4.
		// Write only bucket policy.
		{Version: "1.0", Statements: getWriteOnlyStatement("minio-bucket", "Asia/India/")},
		// bucketPolicy - 5.
		// bucketPolicy statement contains unsupported action.
		{Version: "1.0", Statements: setUnsupportedActions(getReadOnlyStatement("minio-bucket", ""))},
		// bucketPolicy - 6.
		// bucketPolicy statement contains unsupported Effect.
		{Version: "1.0", Statements: setUnsupportedEffect(getReadWriteStatement("minio-bucket", "Asia/"))},
		// bucketPolicy - 7.
		// bucketPolicy statement contains unsupported Principal.
		{Version: "1.0", Statements: setUnsupportedPrincipals(getWriteOnlyStatement("minio-bucket", "Asia/India/"))},
		// bucketPolicy - 8.
		// bucketPolicy statement contains unsupported Resource.
		{Version: "1.0", Statements: setUnsupportedResources(getWriteOnlyStatement("minio-bucket", "Asia/India/"))},
	}

	testCases := []struct {
		inputPolicy bucketPolicy
		// expected results.
		expectedPolicy bucketPolicy
		err            error
		// Flag indicating whether the test should pass.
		shouldPass bool
	}{
		// Test case - 1.
		// bucketPolicy statement empty.
		{bucketAccesPolicies[0], bucketPolicy{}, errors.New("Policy statement cannot be empty."), false},
		// Test case - 2.
		// bucketPolicy version empty.
		{bucketAccesPolicies[1], bucketPolicy{}, errors.New("Policy version cannot be empty."), false},
		// Test case - 3.
		// Readonly bucketPolicy.
		{bucketAccesPolicies[2], bucketAccesPolicies[2], nil, true},
		// Test case - 4.
		// Read-Write bucket policy.
		{bucketAccesPolicies[3], bucketAccesPolicies[3], nil, true},
		// Test case - 5.
		// Write only bucket policy.
		{bucketAccesPolicies[4], bucketAccesPolicies[4], nil, true},
		// Test case - 6.
		// bucketPolicy statement contains unsupported action.
		{bucketAccesPolicies[5], bucketAccesPolicies[5], fmt.Errorf("Unsupported actions found: ‘set.StringSet{\"s3:DeleteEverything\":struct {}{}}’, please validate your policy document."), false},
		// Test case - 7.
		// bucketPolicy statement contains unsupported Effect.
		{bucketAccesPolicies[6], bucketAccesPolicies[6], fmt.Errorf("Unsupported Effect found: ‘DontAllow’, please validate your policy document."), false},
		// Test case - 8.
		// bucketPolicy statement contains unsupported Principal.
		{bucketAccesPolicies[7], bucketAccesPolicies[7], fmt.Errorf("Unsupported principals found: ‘set.StringSet{\"User1111\":struct {}{}}’, please validate your policy document."), false},
		// Test case - 9.
		// bucketPolicy statement contains unsupported Resource.
		{bucketAccesPolicies[8], bucketAccesPolicies[8], fmt.Errorf("Unsupported resource style found: ‘my-resource’, please validate your policy document."), false},
	}
	for i, testCase := range testCases {
		var buffer bytes.Buffer
		encoder := json.NewEncoder(&buffer)
		err := encoder.Encode(testCase.inputPolicy)
		if err != nil {
			t.Fatalf("Test %d: Couldn't Marshal bucket policy %s", i+1, err)
		}

		var actualAccessPolicy = &bucketPolicy{}
		err = parseBucketPolicy(&buffer, actualAccessPolicy)
		if err != nil && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error())
		}
		if err == nil && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error())
		}
		// Failed as expected, but does it fail for the expected reason.
		if err != nil && !testCase.shouldPass {
			if err.Error() != testCase.err.Error() {
				t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error())
			}
		}
		// Test passes as expected, but the output values are verified for correctness here.
		if err == nil && testCase.shouldPass {
			if testCase.expectedPolicy.String() != actualAccessPolicy.String() {
				t.Errorf("Test %d: The expected statements from resource statement generator doesn't match the actual statements", i+1)
			}
		}
	}
}
// Tests validate Policy Action and Resource fields.
func TestCheckbucketPolicyResources(t *testing.T) {
	// constructing policy statement without invalidPrefixActions (check bucket-policy-parser.go).
	setValidPrefixActions := func(statements []policyStatement) []policyStatement {
		statements[0].Actions = set.CreateStringSet([]string{"s3:DeleteObject", "s3:PutObject"}...)
		return statements
	}
	// contracting policy statement with recursive resources.
	// should result in ErrMalformedPolicy
	setRecurseResource := func(statements []policyStatement) []policyStatement {
		statements[0].Resources = set.CreateStringSet([]string{"arn:aws:s3:::minio-bucket/Asia/*", "arn:aws:s3:::minio-bucket/Asia/India/*"}...)
		return statements
	}

	// constructing policy statement with lexically close characters.
	// should not result in ErrMalformedPolicy
	setResourceLexical := func(statements []policyStatement) []policyStatement {
		statements[0].Resources = set.CreateStringSet([]string{"arn:aws:s3:::minio-bucket/op*", "arn:aws:s3:::minio-bucket/oo*"}...)
		return statements
	}

	// List of bucketPolicy used for tests.
	bucketAccessPolicies := []bucketPolicy{
		// bucketPolicy - 1.
		// Contains valid read only policy statement.
		{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket", "")},
		// bucketPolicy - 2.
		// Contains valid read-write only policy statement.
		{Version: "1.0", Statements: getReadWriteStatement("minio-bucket", "Asia/")},
		// bucketPolicy - 3.
		// Contains valid write only policy statement.
		{Version: "1.0", Statements: getWriteOnlyStatement("minio-bucket", "Asia/India/")},
		// bucketPolicy - 4.
		// Contains invalidPrefixActions.
		// Since resourcePrefix is not to the bucket-name, it return ErrMalformedPolicy.
		{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket-fail", "Asia/India/")},
		// bucketPolicy - 5.
		// constructing policy statement without invalidPrefixActions (check bucket-policy-parser.go).
		// but bucket part of the resource is not equal to the bucket name.
		// this results in return of ErrMalformedPolicy.
		{Version: "1.0", Statements: setValidPrefixActions(getWriteOnlyStatement("minio-bucket-fail", "Asia/India/"))},
		// bucketPolicy - 6.
		// contracting policy statement with recursive resources.
		// should result in ErrMalformedPolicy
		{Version: "1.0", Statements: setRecurseResource(setValidPrefixActions(getWriteOnlyStatement("minio-bucket", "")))},
		// BucketPolciy - 7.
		// constructing policy statement with non recursive but
		// lexically close resources.
		// should result in ErrNone.
		{Version: "1.0", Statements: setResourceLexical(setValidPrefixActions(getWriteOnlyStatement("minio-bucket", "oo")))},
	}

	testCases := []struct {
		inputPolicy bucketPolicy
		// expected results.
		apiErrCode APIErrorCode
		// Flag indicating whether the test should pass.
		shouldPass bool
	}{
		// Test case - 1.
		{bucketAccessPolicies[0], ErrNone, true},
		// Test case - 2.
		{bucketAccessPolicies[1], ErrNone, true},
		// Test case - 3.
		{bucketAccessPolicies[2], ErrNone, true},
		// Test case - 4.
		// contains invalidPrefixActions (check bucket-policy-parser.go).
		// Resource prefix will not be equal to the bucket name in this case.
		{bucketAccessPolicies[3], ErrMalformedPolicy, false},
		// Test case - 5.
		// actions contain invalidPrefixActions (check bucket-policy-parser.go).
		// Resource prefix bucket part is not equal to the bucket name in this case.
		{bucketAccessPolicies[4], ErrMalformedPolicy, false},
		// Test case - 6.
		// contracting policy statement with recursive resources.
		// should result in ErrPolicyNesting.
		{bucketAccessPolicies[5], ErrPolicyNesting, false},
		// Test case - 7.
		// constructing policy statement with lexically close
		// characters.
		// should result in ErrNone.
		{bucketAccessPolicies[6], ErrNone, true},
	}
	for i, testCase := range testCases {
		apiErrCode := checkBucketPolicyResources("minio-bucket", &testCase.inputPolicy)
		if apiErrCode != ErrNone && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with Errocode %v", i+1, apiErrCode)
		}
		if apiErrCode == ErrNone && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with ErrCode %v, but passed instead", i+1, testCase.apiErrCode)
		}
		// Failed as expected, but does it fail for the expected reason.
		if apiErrCode != ErrNone && !testCase.shouldPass {
			if testCase.apiErrCode != apiErrCode {
				t.Errorf("Test %d: Expected to fail with error code %v, but instead failed with error code %v", i+1, testCase.apiErrCode, apiErrCode)
			}
		}
	}
}
// Tests validate policyStatement condition validator.
func TestIsValidConditions(t *testing.T) {
	// returns empty conditions map.
	setEmptyConditions := func() map[string]map[string]set.StringSet {
		return make(map[string]map[string]set.StringSet)
	}

	// returns map with the "StringEquals" set to empty map.
	setEmptyStringEquals := func() map[string]map[string]set.StringSet {
		emptyMap := make(map[string]set.StringSet)
		conditions := make(map[string]map[string]set.StringSet)
		conditions["StringEquals"] = emptyMap
		return conditions

	}

	// returns map with the "StringNotEquals" set to empty map.
	setEmptyStringNotEquals := func() map[string]map[string]set.StringSet {
		emptyMap := make(map[string]set.StringSet)
		conditions := make(map[string]map[string]set.StringSet)
		conditions["StringNotEquals"] = emptyMap
		return conditions

	}
	// Generate conditions.
	generateConditions := func(key1, key2, value string) map[string]map[string]set.StringSet {
		innerMap := make(map[string]set.StringSet)
		innerMap[key2] = set.CreateStringSet(value)
		conditions := make(map[string]map[string]set.StringSet)
		conditions[key1] = innerMap
		return conditions
	}

	// generate ambigious conditions.
	generateAmbigiousConditions := func() map[string]map[string]set.StringSet {
		innerMap := make(map[string]set.StringSet)
		innerMap["s3:prefix"] = set.CreateStringSet("Asia/")
		conditions := make(map[string]map[string]set.StringSet)
		conditions["StringEquals"] = innerMap
		conditions["StringNotEquals"] = innerMap
		return conditions
	}

	// generate valid and non valid type in the condition map.
	generateValidInvalidConditions := func() map[string]map[string]set.StringSet {
		innerMap := make(map[string]set.StringSet)
		innerMap["s3:prefix"] = set.CreateStringSet("Asia/")
		conditions := make(map[string]map[string]set.StringSet)
		conditions["StringEquals"] = innerMap
		conditions["InvalidType"] = innerMap
		return conditions
	}

	// generate valid and invalid keys for valid types in the same condition map.
	generateValidInvalidConditionKeys := func() map[string]map[string]set.StringSet {
		innerMapValid := make(map[string]set.StringSet)
		innerMapValid["s3:prefix"] = set.CreateStringSet("Asia/")
		innerMapInValid := make(map[string]set.StringSet)
		innerMapInValid["s3:invalid"] = set.CreateStringSet("Asia/")
		conditions := make(map[string]map[string]set.StringSet)
		conditions["StringEquals"] = innerMapValid
		conditions["StringEquals"] = innerMapInValid
		return conditions
	}

	// List of Conditions used for test cases.
	testConditions := []map[string]map[string]set.StringSet{
		generateConditions("StringValues", "s3:max-keys", "100"),
		generateConditions("StringEquals", "s3:Object", "100"),
		generateAmbigiousConditions(),
		generateValidInvalidConditions(),
		generateValidInvalidConditionKeys(),
		setEmptyConditions(),
		setEmptyStringEquals(),
		setEmptyStringNotEquals(),
		generateConditions("StringEquals", "s3:prefix", "Asia/"),
		generateConditions("StringEquals", "s3:max-keys", "100"),
		generateConditions("StringNotEquals", "s3:prefix", "Asia/"),
		generateConditions("StringNotEquals", "s3:max-keys", "100"),
	}

	testCases := []struct {
		inputCondition map[string]map[string]set.StringSet
		// expected result.
		expectedErr error
		// flag indicating whether test should pass.
		shouldPass bool
	}{
		// Malformed conditions.
		// Test case - 1.
		// "StringValues" is an invalid type.
		{testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " +
			"please validate your policy document."), false},
		// Test case - 2.
		// "s3:Object" is an invalid key.
		{testConditions[1], fmt.Errorf("Unsupported condition key " +
			"'StringEquals', please validate your policy document."), false},
		// Test case - 3.
		// Test case with Ambigious conditions set.
		{testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " +
			"please validate your policy document."), false},
		// Test case - 4.
		// Test case with valid and invalid condition types.
		{testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " +
			"please validate your policy document."), false},
		// Test case - 5.
		// Test case with valid and invalid condition keys.
		{testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " +
			"please validate your policy document."), false},
		// Test cases with valid conditions.
		// Test case - 6.
		{testConditions[5], nil, true},
		// Test case - 7.
		{testConditions[6], nil, true},
		// Test case - 8.
		{testConditions[7], nil, true},
		// Test case - 9.
		{testConditions[8], nil, true},
		// Test case - 10.
		{testConditions[9], nil, true},
		// Test case - 11.
		{testConditions[10], nil, true},
		// Test case 10.
		{testConditions[11], nil, true},
	}
	for i, testCase := range testCases {
		actualErr := isValidConditions(testCase.inputCondition)
		if actualErr != nil && testCase.shouldPass {
			t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error())
		}
		if actualErr == nil && !testCase.shouldPass {
			t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.expectedErr.Error())
		}
		// Failed as expected, but does it fail for the expected reason.
		if actualErr != nil && !testCase.shouldPass {
			if actualErr.Error() != testCase.expectedErr.Error() {
				t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.expectedErr.Error(), actualErr.Error())
			}
		}
	}
}
Exemplo n.º 24
0
// newXLObjects - initialize new xl object layer.
func newXLObjects(disks, ignoredDisks []string) (ObjectLayer, error) {
	if disks == nil {
		return nil, errInvalidArgument
	}
	disksSet := set.NewStringSet()
	if len(ignoredDisks) > 0 {
		disksSet = set.CreateStringSet(ignoredDisks...)
	}
	// Bootstrap disks.
	storageDisks := make([]StorageAPI, len(disks))
	for index, disk := range disks {
		// Check if disk is ignored.
		if disksSet.Contains(disk) {
			storageDisks[index] = nil
			continue
		}
		var err error
		// Intentionally ignore disk not found errors. XL is designed
		// to handle these errors internally.
		storageDisks[index], err = newStorageAPI(disk)
		if err != nil && err != errDiskNotFound {
			switch diskType := storageDisks[index].(type) {
			case networkStorage:
				diskType.rpcClient.Close()
			}
			return nil, err
		}
	}

	// Fix format files in case of fresh or corrupted disks
	repairDiskMetadata(storageDisks)

	// Runs house keeping code, like t, cleaning up tmp files etc.
	if err := xlHouseKeeping(storageDisks); err != nil {
		return nil, err
	}

	// Load saved XL format.json and validate.
	newPosixDisks, err := loadFormatXL(storageDisks)
	if err != nil {
		// errCorruptedDisk - healing failed
		return nil, fmt.Errorf("Unable to recognize backend format, %s", err)
	}

	// Calculate data and parity blocks.
	dataBlocks, parityBlocks := len(newPosixDisks)/2, len(newPosixDisks)/2

	// Initialize object cache.
	objCache := objcache.New(globalMaxCacheSize, globalCacheExpiry)

	// Initialize list pool.
	listPool := newTreeWalkPool(globalLookupTimeout)

	// Initialize xl objects.
	xl := xlObjects{
		storageDisks:    newPosixDisks,
		dataBlocks:      dataBlocks,
		parityBlocks:    parityBlocks,
		listPool:        listPool,
		objCache:        objCache,
		objCacheEnabled: globalMaxCacheSize > 0,
	}

	// Figure out read and write quorum based on number of storage disks.
	// READ and WRITE quorum is always set to (N/2) number of disks.
	xl.readQuorum = len(xl.storageDisks) / 2
	xl.writeQuorum = len(xl.storageDisks)/2 + 1

	// Return successfully initialized object layer.
	return xl, nil
}
// TestBucketPolicyConditionMatch - Tests to validate whether bucket policy conditions match.
func TestBucketPolicyConditionMatch(t *testing.T) {
	// obtain the inner map[string]set.StringSet for policyStatement.Conditions .
	getInnerMap := func(key2, value string) map[string]set.StringSet {
		innerMap := make(map[string]set.StringSet)
		innerMap[key2] = set.CreateStringSet(value)
		return innerMap
	}

	// obtain policyStatement with Conditions set.
	getStatementWithCondition := func(key1, key2, value string) policyStatement {
		innerMap := getInnerMap(key2, value)
		// to set policyStatment.Conditions .
		conditions := make(map[string]map[string]set.StringSet)
		conditions[key1] = innerMap
		// new policy statement.
		statement := policyStatement{}
		// set the condition.
		statement.Conditions = conditions
		return statement
	}

	testCases := []struct {
		statementCondition policyStatement
		condition          map[string]set.StringSet

		expectedMatch bool
	}{

		// Test case - 1.
		// StringEquals condition matches.
		{

			statementCondition: getStatementWithCondition("StringEquals", "s3:prefix", "Asia/"),
			condition:          getInnerMap("prefix", "Asia/"),

			expectedMatch: true,
		},
		// Test case - 2.
		// StringEquals condition doesn't match.
		{

			statementCondition: getStatementWithCondition("StringEquals", "s3:prefix", "Asia/"),
			condition:          getInnerMap("prefix", "Africa/"),

			expectedMatch: false,
		},
		// Test case - 3.
		// StringEquals condition matches.
		{

			statementCondition: getStatementWithCondition("StringEquals", "s3:max-keys", "Asia/"),
			condition:          getInnerMap("max-keys", "Asia/"),

			expectedMatch: true,
		},
		// Test case - 4.
		// StringEquals condition doesn't match.
		{

			statementCondition: getStatementWithCondition("StringEquals", "s3:max-keys", "Asia/"),
			condition:          getInnerMap("max-keys", "Africa/"),

			expectedMatch: false,
		},
		// Test case - 5.
		// StringNotEquals condition matches.
		{

			statementCondition: getStatementWithCondition("StringNotEquals", "s3:prefix", "Asia/"),
			condition:          getInnerMap("prefix", "Asia/"),

			expectedMatch: true,
		},
		// Test case - 6.
		// StringNotEquals condition doesn't match.
		{

			statementCondition: getStatementWithCondition("StringNotEquals", "s3:prefix", "Asia/"),
			condition:          getInnerMap("prefix", "Africa/"),

			expectedMatch: false,
		},
		// Test case - 7.
		// StringNotEquals condition matches.
		{

			statementCondition: getStatementWithCondition("StringNotEquals", "s3:max-keys", "Asia/"),
			condition:          getInnerMap("max-keys", "Asia/"),

			expectedMatch: true,
		},
		// Test case - 8.
		// StringNotEquals condition doesn't match.
		{

			statementCondition: getStatementWithCondition("StringNotEquals", "s3:max-keys", "Asia/"),
			condition:          getInnerMap("max-keys", "Africa/"),

			expectedMatch: false,
		},
	}

	for i, tc := range testCases {
		t.Run(fmt.Sprintf("Test case %d: Failed.", i+1), func(t *testing.T) {
			// call the function under test and assert the result with the expected result.
			doesMatch := bucketPolicyConditionMatch(tc.condition, tc.statementCondition)
			if tc.expectedMatch != doesMatch {
				t.Errorf("Expected the match to be `%v`; got `%v`.", tc.expectedMatch, doesMatch)
			}
		})
	}
}
Exemplo n.º 26
0
// testWebListAllBucketPoliciesHandler - Test ListAllBucketPolicies web handler
func testWebListAllBucketPoliciesHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
	// Register the API end points with XL/FS object layer.
	apiRouter := initTestWebRPCEndPoint(obj)
	// initialize the server and obtain the credentials and root.
	// credentials are necessary to sign the HTTP request.
	rootPath, err := newTestConfig("us-east-1")
	if err != nil {
		t.Fatalf("Init Test config failed")
	}
	// remove the root directory after the test ends.
	defer removeAll(rootPath)

	credentials := serverConfig.GetCredential()

	authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey)
	if err != nil {
		t.Fatal("Cannot authenticate")
	}

	rec := httptest.NewRecorder()

	bucketName := getRandomBucketName()
	if err := obj.MakeBucket(bucketName); err != nil {
		t.Fatal("Unexpected error: ", err)
	}

	policyVal := bucketPolicy{
		Version: "2012-10-17",
		Statements: []policyStatement{
			{
				Actions:   set.CreateStringSet("s3:GetBucketLocation"),
				Effect:    "Allow",
				Principal: map[string][]string{"AWS": {"*"}},
				Resources: set.CreateStringSet("arn:aws:s3:::" + bucketName),
				Sid:       "",
			},
			{
				Actions: set.CreateStringSet("s3:ListBucket"),
				Conditions: map[string]map[string]set.StringSet{
					"StringEquals": {
						"s3:prefix": set.CreateStringSet("hello"),
					},
				},
				Effect:    "Allow",
				Principal: map[string][]string{"AWS": {"*"}},
				Resources: set.CreateStringSet("arn:aws:s3:::" + bucketName),
				Sid:       "",
			},
			{
				Actions:   set.CreateStringSet("s3:ListBucketMultipartUploads"),
				Effect:    "Allow",
				Principal: map[string][]string{"AWS": {"*"}},
				Resources: set.CreateStringSet("arn:aws:s3:::" + bucketName),
				Sid:       "",
			},
			{
				Actions: set.CreateStringSet("s3:AbortMultipartUpload", "s3:DeleteObject",
					"s3:GetObject", "s3:ListMultipartUploadParts", "s3:PutObject"),
				Effect:    "Allow",
				Principal: map[string][]string{"AWS": {"*"}},
				Resources: set.CreateStringSet("arn:aws:s3:::" + bucketName + "/hello*"),
				Sid:       "",
			},
		},
	}
	if err := writeBucketPolicy(bucketName, obj, &policyVal); err != nil {
		t.Fatal("Unexpected error: ", err)
	}

	testCaseResult1 := []bucketAccessPolicy{{
		Prefix: bucketName + "/hello*",
		Policy: policy.BucketPolicyReadWrite,
	}}
	testCases := []struct {
		bucketName     string
		expectedResult []bucketAccessPolicy
	}{
		{bucketName, testCaseResult1},
	}

	for i, testCase := range testCases {
		args := &ListAllBucketPoliciesArgs{BucketName: testCase.bucketName}
		reply := &ListAllBucketPoliciesRep{}
		req, err := newTestWebRPCRequest("Web.ListAllBucketPolicies", authorization, args)
		if err != nil {
			t.Fatalf("Test %d: Failed to create HTTP request: <ERROR> %v", i+1, err)
		}
		apiRouter.ServeHTTP(rec, req)
		if rec.Code != http.StatusOK {
			t.Fatalf("Test %d: Expected the response status to be 200, but instead found `%d`", i+1, rec.Code)
		}
		if err = getTestWebRPCResponse(rec, &reply); err != nil {
			t.Fatalf("Test %d: Should succeed but it didn't, %v", i+1, err)
		}
		if !reflect.DeepEqual(testCase.expectedResult, reply.Policies) {
			t.Fatalf("Test %d: expected: %v, got: %v", i+1, testCase.expectedResult, reply.Policies)
		}
	}
}
Exemplo n.º 27
0
)

// isValidBucketPolicy - Is provided policy value supported.
func (p BucketPolicy) IsValidBucketPolicy() bool {
	switch p {
	case BucketPolicyNone, BucketPolicyReadOnly, BucketPolicyReadWrite, BucketPolicyWriteOnly:
		return true
	}
	return false
}

// Resource prefix for all aws resources.
const awsResourcePrefix = "arn:aws:s3:::"

// Common bucket actions for both read and write policies.
var commonBucketActions = set.CreateStringSet("s3:GetBucketLocation")

// Read only bucket actions.
var readOnlyBucketActions = set.CreateStringSet("s3:ListBucket")

// Write only bucket actions.
var writeOnlyBucketActions = set.CreateStringSet("s3:ListBucketMultipartUploads")

// Read only object actions.
var readOnlyObjectActions = set.CreateStringSet("s3:GetObject")

// Write only object actions.
var writeOnlyObjectActions = set.CreateStringSet("s3:AbortMultipartUpload", "s3:DeleteObject", "s3:ListMultipartUploadParts", "s3:PutObject")

// Read and write object actions.
var readWriteObjectActions = readOnlyObjectActions.Union(writeOnlyObjectActions)