Add boolean function condition support (#7027)
parent
1898961ce3
commit
2a0e4b6f58
@ -0,0 +1,105 @@ |
||||
/* |
||||
* 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" |
||||
"reflect" |
||||
"strconv" |
||||
) |
||||
|
||||
// booleanFunc - Bool condition function. It checks whether Key is true or false.
|
||||
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_Boolean
|
||||
type booleanFunc struct { |
||||
k Key |
||||
value string |
||||
} |
||||
|
||||
// evaluate() - evaluates to check whether Key is present in given values or not.
|
||||
// Depending on condition boolean value, this function returns true or false.
|
||||
func (f booleanFunc) evaluate(values map[string][]string) bool { |
||||
requestValue, ok := values[http.CanonicalHeaderKey(f.k.Name())] |
||||
if !ok { |
||||
requestValue = values[f.k.Name()] |
||||
} |
||||
|
||||
return f.value == requestValue[0] |
||||
} |
||||
|
||||
// key() - returns condition key which is used by this condition function.
|
||||
func (f booleanFunc) key() Key { |
||||
return f.k |
||||
} |
||||
|
||||
// name() - returns "Bool" condition name.
|
||||
func (f booleanFunc) name() name { |
||||
return boolean |
||||
} |
||||
|
||||
func (f booleanFunc) String() string { |
||||
return fmt.Sprintf("%v:%v:%v", boolean, f.k, f.value) |
||||
} |
||||
|
||||
// toMap - returns map representation of this function.
|
||||
func (f booleanFunc) toMap() map[Key]ValueSet { |
||||
if !f.k.IsValid() { |
||||
return nil |
||||
} |
||||
|
||||
return map[Key]ValueSet{ |
||||
f.k: NewValueSet(NewStringValue(f.value)), |
||||
} |
||||
} |
||||
|
||||
func newBooleanFunc(key Key, values ValueSet) (Function, error) { |
||||
if key != AWSSecureTransport { |
||||
return nil, fmt.Errorf("only %v key is allowed for %v condition", AWSSecureTransport, boolean) |
||||
} |
||||
|
||||
if len(values) != 1 { |
||||
return nil, fmt.Errorf("only one value is allowed for boolean condition") |
||||
} |
||||
|
||||
var value Value |
||||
for v := range values { |
||||
value = v |
||||
switch v.GetType() { |
||||
case reflect.Bool: |
||||
if _, err := v.GetBool(); err != nil { |
||||
return nil, err |
||||
} |
||||
case reflect.String: |
||||
s, err := v.GetString() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if _, err = strconv.ParseBool(s); err != nil { |
||||
return nil, fmt.Errorf("value must be a boolean string for boolean condition") |
||||
} |
||||
default: |
||||
return nil, fmt.Errorf("value must be a boolean for boolean condition") |
||||
} |
||||
} |
||||
|
||||
return &booleanFunc{key, value.String()}, nil |
||||
} |
||||
|
||||
// NewBoolFunc - returns new Bool function.
|
||||
func NewBoolFunc(key Key, value string) (Function, error) { |
||||
return &booleanFunc{key, value}, nil |
||||
} |
@ -0,0 +1,152 @@ |
||||
/* |
||||
* 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 TestBooleanFuncEvaluate(t *testing.T) { |
||||
case1Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(true))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
case2Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(false))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
testCases := []struct { |
||||
function Function |
||||
values map[string][]string |
||||
expectedResult bool |
||||
}{ |
||||
{case1Function, map[string][]string{"SecureTransport": {"true"}}, true}, |
||||
{case2Function, map[string][]string{"SecureTransport": {"false"}}, true}, |
||||
} |
||||
|
||||
for i, testCase := range testCases { |
||||
result := testCase.function.evaluate(testCase.values) |
||||
|
||||
if result != testCase.expectedResult { |
||||
t.Errorf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestBooleanFuncKey(t *testing.T) { |
||||
case1Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(true))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
testCases := []struct { |
||||
function Function |
||||
expectedResult Key |
||||
}{ |
||||
{case1Function, AWSSecureTransport}, |
||||
} |
||||
|
||||
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 TestBooleanFuncToMap(t *testing.T) { |
||||
case1Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(true))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
case1Result := map[Key]ValueSet{ |
||||
AWSSecureTransport: NewValueSet(NewStringValue("true")), |
||||
} |
||||
|
||||
case2Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(false))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
case2Result := map[Key]ValueSet{ |
||||
AWSSecureTransport: NewValueSet(NewStringValue("false")), |
||||
} |
||||
|
||||
testCases := []struct { |
||||
f Function |
||||
expectedResult map[Key]ValueSet |
||||
}{ |
||||
{case1Function, case1Result}, |
||||
{case2Function, case2Result}, |
||||
} |
||||
|
||||
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 TestNewBooleanFunc(t *testing.T) { |
||||
case1Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(true))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
case2Function, err := newBooleanFunc(AWSSecureTransport, NewValueSet(NewBoolValue(false))) |
||||
if err != nil { |
||||
t.Fatalf("unexpected error. %v\n", err) |
||||
} |
||||
|
||||
testCases := []struct { |
||||
key Key |
||||
values ValueSet |
||||
expectedResult Function |
||||
expectErr bool |
||||
}{ |
||||
{AWSSecureTransport, NewValueSet(NewBoolValue(true)), case1Function, false}, |
||||
{AWSSecureTransport, NewValueSet(NewStringValue("false")), case2Function, false}, |
||||
// Multiple values error.
|
||||
{AWSSecureTransport, NewValueSet(NewStringValue("true"), NewStringValue("false")), nil, true}, |
||||
// Invalid boolean string error.
|
||||
{AWSSecureTransport, NewValueSet(NewStringValue("foo")), nil, true}, |
||||
// Invalid value error.
|
||||
{AWSSecureTransport, NewValueSet(NewIntValue(7)), nil, true}, |
||||
} |
||||
|
||||
for i, testCase := range testCases { |
||||
result, err := newBooleanFunc(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) |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue