storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/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 policy 18 19 import ( 20 "encoding/json" 21 "strings" 22 23 "storj.io/minio/pkg/bucket/policy/condition" 24 ) 25 26 // Statement - policy statement. 27 type Statement struct { 28 SID ID `json:"Sid,omitempty"` 29 Effect Effect `json:"Effect"` 30 Principal Principal `json:"Principal"` 31 Actions ActionSet `json:"Action"` 32 Resources ResourceSet `json:"Resource"` 33 Conditions condition.Functions `json:"Condition,omitempty"` 34 } 35 36 // Equals checks if two statements are equal 37 func (statement Statement) Equals(st Statement) bool { 38 if statement.Effect != st.Effect { 39 return false 40 } 41 if !statement.Principal.Equals(st.Principal) { 42 return false 43 } 44 if !statement.Actions.Equals(st.Actions) { 45 return false 46 } 47 if !statement.Resources.Equals(st.Resources) { 48 return false 49 } 50 if !statement.Conditions.Equals(st.Conditions) { 51 return false 52 } 53 return true 54 } 55 56 // IsAllowed - checks given policy args is allowed to continue the Rest API. 57 func (statement Statement) IsAllowed(args Args) bool { 58 check := func() bool { 59 if !statement.Principal.Match(args.AccountName) { 60 return false 61 } 62 63 if !statement.Actions.Contains(args.Action) { 64 return false 65 } 66 67 resource := args.BucketName 68 if args.ObjectName != "" { 69 if !strings.HasPrefix(args.ObjectName, "/") { 70 resource += "/" 71 } 72 73 resource += args.ObjectName 74 } 75 76 if !statement.Resources.Match(resource, args.ConditionValues) { 77 return false 78 } 79 80 return statement.Conditions.Evaluate(args.ConditionValues) 81 } 82 83 return statement.Effect.IsAllowed(check()) 84 } 85 86 // isValid - checks whether statement is valid or not. 87 func (statement Statement) isValid() error { 88 if !statement.Effect.IsValid() { 89 return Errorf("invalid Effect %v", statement.Effect) 90 } 91 92 if !statement.Principal.IsValid() { 93 return Errorf("invalid Principal %v", statement.Principal) 94 } 95 96 if len(statement.Actions) == 0 { 97 return Errorf("Action must not be empty") 98 } 99 100 if len(statement.Resources) == 0 { 101 return Errorf("Resource must not be empty") 102 } 103 104 for action := range statement.Actions { 105 if action.isObjectAction() { 106 if !statement.Resources.objectResourceExists() { 107 return Errorf("unsupported Resource found %v for action %v", statement.Resources, action) 108 } 109 } else { 110 if !statement.Resources.bucketResourceExists() { 111 return Errorf("unsupported Resource found %v for action %v", statement.Resources, action) 112 } 113 } 114 115 keys := statement.Conditions.Keys() 116 keyDiff := keys.Difference(actionConditionKeyMap[action]) 117 if !keyDiff.IsEmpty() { 118 return Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action) 119 } 120 } 121 122 return nil 123 } 124 125 // MarshalJSON - encodes JSON data to Statement. 126 func (statement Statement) MarshalJSON() ([]byte, error) { 127 if err := statement.isValid(); err != nil { 128 return nil, err 129 } 130 131 // subtype to avoid recursive call to MarshalJSON() 132 type subStatement Statement 133 ss := subStatement(statement) 134 return json.Marshal(ss) 135 } 136 137 // UnmarshalJSON - decodes JSON data to Statement. 138 func (statement *Statement) UnmarshalJSON(data []byte) error { 139 // subtype to avoid recursive call to UnmarshalJSON() 140 type subStatement Statement 141 var ss subStatement 142 143 if err := json.Unmarshal(data, &ss); err != nil { 144 return err 145 } 146 147 s := Statement(ss) 148 if err := s.isValid(); err != nil { 149 return err 150 } 151 152 *statement = s 153 154 return nil 155 } 156 157 // Validate - validates Statement is for given bucket or not. 158 func (statement Statement) Validate(bucketName string) error { 159 if err := statement.isValid(); err != nil { 160 return err 161 } 162 163 return statement.Resources.Validate(bucketName) 164 } 165 166 // Clone clones Statement structure 167 func (statement Statement) Clone() Statement { 168 return NewStatement(statement.Effect, statement.Principal.Clone(), 169 statement.Actions.Clone(), statement.Resources.Clone(), statement.Conditions.Clone()) 170 } 171 172 // NewStatement - creates new statement. 173 func NewStatement(effect Effect, principal Principal, actionSet ActionSet, resourceSet ResourceSet, conditions condition.Functions) Statement { 174 return Statement{ 175 Effect: effect, 176 Principal: principal, 177 Actions: actionSet, 178 Resources: resourceSet, 179 Conditions: conditions, 180 } 181 }