mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Fail PutBucketPolicy if conditions are incompatible with actions. (#3659)
This commit is contained in:
parent
9b6bcb30d9
commit
2665aba555
@ -97,6 +97,9 @@ func bucketPolicyConditionMatch(conditions map[string]set.StringSet, statement p
|
|||||||
// - s3:max-keys
|
// - s3:max-keys
|
||||||
// - s3:aws-Referer
|
// - s3:aws-Referer
|
||||||
|
|
||||||
|
// The following loop evaluates the logical AND of all the
|
||||||
|
// conditions in the statement. Note: we can break out of the
|
||||||
|
// loop if and only if a condition evaluates to false.
|
||||||
for condition, conditionKeyVal := range statement.Conditions {
|
for condition, conditionKeyVal := range statement.Conditions {
|
||||||
prefixConditon := conditionKeyVal["s3:prefix"]
|
prefixConditon := conditionKeyVal["s3:prefix"]
|
||||||
maxKeyCondition := conditionKeyVal["s3:max-keys"]
|
maxKeyCondition := conditionKeyVal["s3:max-keys"]
|
||||||
@ -126,13 +129,17 @@ func bucketPolicyConditionMatch(conditions map[string]set.StringSet, statement p
|
|||||||
}
|
}
|
||||||
// wildcard match of referer in statement was not empty.
|
// wildcard match of referer in statement was not empty.
|
||||||
// StringLike has a match, i.e, condition evaluates to true.
|
// StringLike has a match, i.e, condition evaluates to true.
|
||||||
|
refererFound := false
|
||||||
for referer := range conditions["referer"] {
|
for referer := range conditions["referer"] {
|
||||||
if !awsReferers.FuncMatch(refererMatch, referer).IsEmpty() {
|
if !awsReferers.FuncMatch(refererMatch, referer).IsEmpty() {
|
||||||
return true
|
refererFound = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No matching referer found, so the condition is false.
|
// No matching referer found, so the condition is false.
|
||||||
return false
|
if !refererFound {
|
||||||
|
return false
|
||||||
|
}
|
||||||
} else if condition == "StringNotLike" {
|
} else if condition == "StringNotLike" {
|
||||||
awsReferers := conditionKeyVal["aws:Referer"]
|
awsReferers := conditionKeyVal["aws:Referer"]
|
||||||
// Skip empty condition, it is trivially satisfied.
|
// Skip empty condition, it is trivially satisfied.
|
||||||
@ -146,11 +153,9 @@ func bucketPolicyConditionMatch(conditions map[string]set.StringSet, statement p
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No matching referer found, so the condition is true.
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No conditions were present in the statement, so trivially true (always).
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ import (
|
|||||||
"github.com/minio/minio-go/pkg/set"
|
"github.com/minio/minio-go/pkg/set"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var conditionKeyActionMap = map[string]set.StringSet{
|
||||||
|
"s3:prefix": set.CreateStringSet("s3:ListBucket"),
|
||||||
|
"s3:max-keys": set.CreateStringSet("s3:ListBucket"),
|
||||||
|
}
|
||||||
|
|
||||||
// supportedActionMap - lists all the actions supported by minio.
|
// supportedActionMap - lists all the actions supported by minio.
|
||||||
var supportedActionMap = set.CreateStringSet("*", "s3:*", "s3:GetObject",
|
var supportedActionMap = set.CreateStringSet("*", "s3:*", "s3:GetObject",
|
||||||
"s3:ListBucket", "s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject",
|
"s3:ListBucket", "s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject",
|
||||||
@ -178,11 +183,12 @@ func isValidPrincipals(principal interface{}) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidConditions - are valid conditions.
|
// isValidConditions - returns nil if the given conditions valid and
|
||||||
func isValidConditions(conditions map[string]map[string]set.StringSet) (err error) {
|
// corresponding error otherwise.
|
||||||
// Verify conditions should be valid.
|
func isValidConditions(actions set.StringSet, conditions map[string]map[string]set.StringSet) (err error) {
|
||||||
// Validate if stringEquals, stringNotEquals are present
|
// Verify conditions should be valid. Validate if only
|
||||||
// if not throw an error.
|
// supported condition keys are present and return error
|
||||||
|
// otherwise.
|
||||||
conditionKeyVal := make(map[string]set.StringSet)
|
conditionKeyVal := make(map[string]set.StringSet)
|
||||||
for conditionType := range conditions {
|
for conditionType := range conditions {
|
||||||
if !supportedConditionsType.Contains(conditionType) {
|
if !supportedConditionsType.Contains(conditionType) {
|
||||||
@ -194,6 +200,15 @@ func isValidConditions(conditions map[string]map[string]set.StringSet) (err erro
|
|||||||
err = fmt.Errorf("Unsupported condition key '%s', please validate your policy document", conditionType)
|
err = fmt.Errorf("Unsupported condition key '%s', please validate your policy document", conditionType)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compatibleActions := conditionKeyActionMap[key]
|
||||||
|
if !compatibleActions.IsEmpty() &&
|
||||||
|
compatibleActions.Intersection(actions).IsEmpty() {
|
||||||
|
err = fmt.Errorf("Unsupported condition key %s for the given actions %s, "+
|
||||||
|
"please validate your policy document", key, actions)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
conditionVal, ok := conditionKeyVal[key]
|
conditionVal, ok := conditionKeyVal[key]
|
||||||
if ok && !value.Intersection(conditionVal).IsEmpty() {
|
if ok && !value.Intersection(conditionVal).IsEmpty() {
|
||||||
err = fmt.Errorf("Ambigious condition values for key '%s', please validate your policy document", key)
|
err = fmt.Errorf("Ambigious condition values for key '%s', please validate your policy document", key)
|
||||||
@ -222,8 +237,8 @@ func resourcePrefix(resource string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checkBucketPolicyResources validates Resources in unmarshalled bucket policy structure.
|
// checkBucketPolicyResources validates Resources in unmarshalled bucket policy structure.
|
||||||
// First valation of Resources done for given set of Actions.
|
// - Resources are validated against the given set of Actions.
|
||||||
// Later its validated for recursive Resources.
|
// -
|
||||||
func checkBucketPolicyResources(bucket string, bucketPolicy *bucketPolicy) APIErrorCode {
|
func checkBucketPolicyResources(bucket string, bucketPolicy *bucketPolicy) APIErrorCode {
|
||||||
// Validate statements for special actions and collect resources
|
// Validate statements for special actions and collect resources
|
||||||
// for others to validate nesting.
|
// for others to validate nesting.
|
||||||
@ -317,7 +332,7 @@ func parseBucketPolicy(bucketPolicyReader io.Reader, policy *bucketPolicy) (err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Statement conditions should be valid.
|
// Statement conditions should be valid.
|
||||||
if err := isValidConditions(statement.Conditions); err != nil {
|
if err := isValidConditions(statement.Actions, statement.Conditions); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,7 +433,12 @@ func TestIsValidConditions(t *testing.T) {
|
|||||||
generateConditions("StringNotEquals", "s3:max-keys", "100"),
|
generateConditions("StringNotEquals", "s3:max-keys", "100"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getObjectActionSet := set.CreateStringSet("s3:GetObject")
|
||||||
|
roBucketActionSet := set.CreateStringSet(readOnlyBucketActions...)
|
||||||
|
maxKeysConditionErr := fmt.Errorf("Unsupported condition key %s for the given actions %s, "+
|
||||||
|
"please validate your policy document", "s3:max-keys", getObjectActionSet)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
inputActions set.StringSet
|
||||||
inputCondition map[string]map[string]set.StringSet
|
inputCondition map[string]map[string]set.StringSet
|
||||||
// expected result.
|
// expected result.
|
||||||
expectedErr error
|
expectedErr error
|
||||||
@ -443,46 +448,44 @@ func TestIsValidConditions(t *testing.T) {
|
|||||||
// Malformed conditions.
|
// Malformed conditions.
|
||||||
// Test case - 1.
|
// Test case - 1.
|
||||||
// "StringValues" is an invalid type.
|
// "StringValues" is an invalid type.
|
||||||
{testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " +
|
{roBucketActionSet, testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " +
|
||||||
"please validate your policy document"), false},
|
"please validate your policy document"), false},
|
||||||
// Test case - 2.
|
// Test case - 2.
|
||||||
// "s3:Object" is an invalid key.
|
// "s3:Object" is an invalid key.
|
||||||
{testConditions[1], fmt.Errorf("Unsupported condition key " +
|
{roBucketActionSet, testConditions[1], fmt.Errorf("Unsupported condition key " +
|
||||||
"'StringEquals', please validate your policy document"), false},
|
"'StringEquals', please validate your policy document"), false},
|
||||||
// Test case - 3.
|
// Test case - 3.
|
||||||
// Test case with Ambigious conditions set.
|
// Test case with Ambigious conditions set.
|
||||||
{testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " +
|
{roBucketActionSet, testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " +
|
||||||
"please validate your policy document"), false},
|
"please validate your policy document"), false},
|
||||||
// Test case - 4.
|
// Test case - 4.
|
||||||
// Test case with valid and invalid condition types.
|
// Test case with valid and invalid condition types.
|
||||||
{testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " +
|
{roBucketActionSet, testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " +
|
||||||
"please validate your policy document"), false},
|
"please validate your policy document"), false},
|
||||||
// Test case - 5.
|
// Test case - 5.
|
||||||
// Test case with valid and invalid condition keys.
|
// Test case with valid and invalid condition keys.
|
||||||
{testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " +
|
{roBucketActionSet, testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " +
|
||||||
"please validate your policy document"), false},
|
"please validate your policy document"), false},
|
||||||
// Test cases with valid conditions.
|
// Test cases with valid conditions.
|
||||||
// Test case - 6.
|
// Test case - 6.
|
||||||
{testConditions[5], nil, true},
|
{roBucketActionSet, testConditions[5], nil, true},
|
||||||
// Test case - 7.
|
// Test case - 7.
|
||||||
{testConditions[6], nil, true},
|
{roBucketActionSet, testConditions[6], nil, true},
|
||||||
// Test case - 8.
|
// Test case - 8.
|
||||||
{testConditions[7], nil, true},
|
{roBucketActionSet, testConditions[7], nil, true},
|
||||||
// Test case - 9.
|
// Test case - 9.
|
||||||
{testConditions[8], nil, true},
|
{roBucketActionSet, testConditions[8], nil, true},
|
||||||
// Test case - 10.
|
// Test case - 10.
|
||||||
{testConditions[9], nil, true},
|
{roBucketActionSet, testConditions[9], nil, true},
|
||||||
// Test case - 11.
|
// Test case - 11.
|
||||||
{testConditions[10], nil, true},
|
{roBucketActionSet, testConditions[10], nil, true},
|
||||||
// Test case - 12.
|
// Test case - 12.
|
||||||
{testConditions[11], nil, true},
|
{roBucketActionSet, testConditions[11], nil, true},
|
||||||
// Test case - 13.
|
// Test case - 13.
|
||||||
{testConditions[11], nil, true},
|
{getObjectActionSet, testConditions[11], maxKeysConditionErr, false},
|
||||||
// Test case - 14.
|
|
||||||
{testConditions[11], nil, true},
|
|
||||||
}
|
}
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
actualErr := isValidConditions(testCase.inputCondition)
|
actualErr := isValidConditions(testCase.inputActions, testCase.inputCondition)
|
||||||
if actualErr != nil && testCase.shouldPass {
|
if actualErr != nil && testCase.shouldPass {
|
||||||
t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error())
|
t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user