storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/iam/policy/statement.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2018 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package iampolicy 18 19 import ( 20 "strings" 21 22 "storj.io/minio/pkg/bucket/policy" 23 "storj.io/minio/pkg/bucket/policy/condition" 24 ) 25 26 // Statement - iam policy statement. 27 type Statement struct { 28 SID policy.ID `json:"Sid,omitempty"` 29 Effect policy.Effect `json:"Effect"` 30 Actions ActionSet `json:"Action"` 31 Resources ResourceSet `json:"Resource,omitempty"` 32 Conditions condition.Functions `json:"Condition,omitempty"` 33 } 34 35 // IsAllowed - checks given policy args is allowed to continue the Rest API. 36 func (statement Statement) IsAllowed(args Args) bool { 37 check := func() bool { 38 if !statement.Actions.Match(args.Action) { 39 return false 40 } 41 42 resource := args.BucketName 43 if args.ObjectName != "" { 44 if !strings.HasPrefix(args.ObjectName, "/") { 45 resource += "/" 46 } 47 48 resource += args.ObjectName 49 } else { 50 resource += "/" 51 } 52 53 // For admin statements, resource match can be ignored. 54 if !statement.Resources.Match(resource, args.ConditionValues) && !statement.isAdmin() { 55 return false 56 } 57 58 return statement.Conditions.Evaluate(args.ConditionValues) 59 } 60 61 return statement.Effect.IsAllowed(check()) 62 } 63 func (statement Statement) isAdmin() bool { 64 for action := range statement.Actions { 65 if AdminAction(action).IsValid() { 66 return true 67 } 68 } 69 return false 70 } 71 72 // isValid - checks whether statement is valid or not. 73 func (statement Statement) isValid() error { 74 if !statement.Effect.IsValid() { 75 return Errorf("invalid Effect %v", statement.Effect) 76 } 77 78 if len(statement.Actions) == 0 { 79 return Errorf("Action must not be empty") 80 } 81 82 if statement.isAdmin() { 83 if err := statement.Actions.ValidateAdmin(); err != nil { 84 return err 85 } 86 for action := range statement.Actions { 87 keys := statement.Conditions.Keys() 88 keyDiff := keys.Difference(adminActionConditionKeyMap[action]) 89 if !keyDiff.IsEmpty() { 90 return Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action) 91 } 92 } 93 return nil 94 } 95 96 if !statement.SID.IsValid() { 97 return Errorf("invalid SID %v", statement.SID) 98 } 99 100 if len(statement.Resources) == 0 { 101 return Errorf("Resource must not be empty") 102 } 103 104 if err := statement.Resources.Validate(); err != nil { 105 return err 106 } 107 108 if err := statement.Actions.Validate(); err != nil { 109 return err 110 } 111 112 for action := range statement.Actions { 113 if !statement.Resources.objectResourceExists() && !statement.Resources.bucketResourceExists() { 114 return Errorf("unsupported Resource found %v for action %v", statement.Resources, action) 115 } 116 117 keys := statement.Conditions.Keys() 118 keyDiff := keys.Difference(iamActionConditionKeyMap.Lookup(action)) 119 if !keyDiff.IsEmpty() { 120 return Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action) 121 } 122 } 123 124 return nil 125 } 126 127 // Validate - validates Statement is for given bucket or not. 128 func (statement Statement) Validate() error { 129 return statement.isValid() 130 } 131 132 // Equals checks if two statements are equal 133 func (statement Statement) Equals(st Statement) bool { 134 if statement.Effect != st.Effect { 135 return false 136 } 137 if !statement.Actions.Equals(st.Actions) { 138 return false 139 } 140 if !statement.Resources.Equals(st.Resources) { 141 return false 142 } 143 if !statement.Conditions.Equals(st.Conditions) { 144 return false 145 } 146 return true 147 } 148 149 // Clone clones Statement structure 150 func (statement Statement) Clone() Statement { 151 return NewStatement(statement.Effect, statement.Actions.Clone(), 152 statement.Resources.Clone(), statement.Conditions.Clone()) 153 } 154 155 // NewStatement - creates new statement. 156 func NewStatement(effect policy.Effect, actionSet ActionSet, resourceSet ResourceSet, conditions condition.Functions) Statement { 157 return Statement{ 158 Effect: effect, 159 Actions: actionSet, 160 Resources: resourceSet, 161 Conditions: conditions, 162 } 163 }