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