storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/policy/policy.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 "io" 22 ) 23 24 // DefaultVersion - default policy version as per AWS S3 specification. 25 const DefaultVersion = "2012-10-17" 26 27 // Args - arguments to policy to check whether it is allowed 28 type Args struct { 29 AccountName string `json:"account"` 30 Groups []string `json:"groups"` 31 Action Action `json:"action"` 32 BucketName string `json:"bucket"` 33 ConditionValues map[string][]string `json:"conditions"` 34 IsOwner bool `json:"owner"` 35 ObjectName string `json:"object"` 36 } 37 38 // Policy - bucket policy. 39 type Policy struct { 40 ID ID `json:"ID,omitempty"` 41 Version string 42 Statements []Statement `json:"Statement"` 43 } 44 45 // IsAllowed - checks given policy args is allowed to continue the Rest API. 46 func (policy Policy) IsAllowed(args Args) bool { 47 // Check all deny statements. If any one statement denies, return false. 48 for _, statement := range policy.Statements { 49 if statement.Effect == Deny { 50 if !statement.IsAllowed(args) { 51 return false 52 } 53 } 54 } 55 56 // For owner, its allowed by default. 57 if args.IsOwner { 58 return true 59 } 60 61 // Check all allow statements. If any one statement allows, return true. 62 for _, statement := range policy.Statements { 63 if statement.Effect == Allow { 64 if statement.IsAllowed(args) { 65 return true 66 } 67 } 68 } 69 70 return false 71 } 72 73 // IsEmpty - returns whether policy is empty or not. 74 func (policy Policy) IsEmpty() bool { 75 return len(policy.Statements) == 0 76 } 77 78 // isValid - checks if Policy is valid or not. 79 func (policy Policy) isValid() error { 80 if policy.Version != DefaultVersion && policy.Version != "" { 81 return Errorf("invalid version '%v'", policy.Version) 82 } 83 84 for _, statement := range policy.Statements { 85 if err := statement.isValid(); err != nil { 86 return err 87 } 88 } 89 90 return nil 91 } 92 93 // MarshalJSON - encodes Policy to JSON data. 94 func (policy Policy) MarshalJSON() ([]byte, error) { 95 if err := policy.isValid(); err != nil { 96 return nil, err 97 } 98 99 // subtype to avoid recursive call to MarshalJSON() 100 type subPolicy Policy 101 return json.Marshal(subPolicy(policy)) 102 } 103 104 // Merge merges two policies documents and drop 105 // duplicate statements if any. 106 func (policy Policy) Merge(input Policy) Policy { 107 var mergedPolicy Policy 108 if policy.Version != "" { 109 mergedPolicy.Version = policy.Version 110 } else { 111 mergedPolicy.Version = input.Version 112 } 113 for _, st := range policy.Statements { 114 mergedPolicy.Statements = append(mergedPolicy.Statements, st.Clone()) 115 } 116 for _, st := range input.Statements { 117 mergedPolicy.Statements = append(mergedPolicy.Statements, st.Clone()) 118 } 119 mergedPolicy.dropDuplicateStatements() 120 return mergedPolicy 121 } 122 123 func (policy *Policy) dropDuplicateStatements() { 124 redo: 125 for i := range policy.Statements { 126 for j, statement := range policy.Statements[i+1:] { 127 if !policy.Statements[i].Equals(statement) { 128 continue 129 } 130 policy.Statements = append(policy.Statements[:j], policy.Statements[j+1:]...) 131 goto redo 132 } 133 } 134 } 135 136 // UnmarshalJSON - decodes JSON data to Policy. 137 func (policy *Policy) UnmarshalJSON(data []byte) error { 138 // subtype to avoid recursive call to UnmarshalJSON() 139 type subPolicy Policy 140 var sp subPolicy 141 if err := json.Unmarshal(data, &sp); err != nil { 142 return err 143 } 144 145 p := Policy(sp) 146 if err := p.isValid(); err != nil { 147 return err 148 } 149 150 p.dropDuplicateStatements() 151 152 *policy = p 153 154 return nil 155 } 156 157 // Validate - validates all statements are for given bucket or not. 158 func (policy Policy) Validate(bucketName string) error { 159 if err := policy.isValid(); err != nil { 160 return err 161 } 162 163 for _, statement := range policy.Statements { 164 if err := statement.Validate(bucketName); err != nil { 165 return err 166 } 167 } 168 169 return nil 170 } 171 172 // ParseConfig - parses data in given reader to Policy. 173 func ParseConfig(reader io.Reader, bucketName string) (*Policy, error) { 174 var policy Policy 175 176 decoder := json.NewDecoder(reader) 177 decoder.DisallowUnknownFields() 178 if err := decoder.Decode(&policy); err != nil { 179 return nil, Errorf("%w", err) 180 } 181 182 err := policy.Validate(bucketName) 183 return &policy, err 184 }