storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/iam/policy/resource.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 "encoding/json" 21 "path" 22 "strings" 23 24 "storj.io/minio/pkg/bucket/policy/condition" 25 "storj.io/minio/pkg/wildcard" 26 ) 27 28 // ResourceARNPrefix - resource ARN prefix as per AWS S3 specification. 29 const ResourceARNPrefix = "arn:aws:s3:::" 30 31 // Resource - resource in policy statement. 32 type Resource struct { 33 BucketName string 34 Pattern string 35 } 36 37 func (r Resource) isBucketPattern() bool { 38 return !strings.Contains(r.Pattern, "/") || r.Pattern == "*" 39 } 40 41 func (r Resource) isObjectPattern() bool { 42 return strings.Contains(r.Pattern, "/") || strings.Contains(r.BucketName, "*") || r.Pattern == "*/*" 43 } 44 45 // IsValid - checks whether Resource is valid or not. 46 func (r Resource) IsValid() bool { 47 return r.Pattern != "" 48 } 49 50 // Match - matches object name with resource pattern. 51 func (r Resource) Match(resource string, conditionValues map[string][]string) bool { 52 pattern := r.Pattern 53 for _, key := range condition.CommonKeys { 54 // Empty values are not supported for policy variables. 55 if rvalues, ok := conditionValues[key.Name()]; ok && rvalues[0] != "" { 56 pattern = strings.Replace(pattern, key.VarName(), rvalues[0], -1) 57 } 58 } 59 if cp := path.Clean(resource); cp != "." && cp == pattern { 60 return true 61 } 62 return wildcard.Match(pattern, resource) 63 } 64 65 // MarshalJSON - encodes Resource to JSON data. 66 func (r Resource) MarshalJSON() ([]byte, error) { 67 if !r.IsValid() { 68 return nil, Errorf("invalid resource %v", r) 69 } 70 71 return json.Marshal(r.String()) 72 } 73 74 func (r Resource) String() string { 75 return ResourceARNPrefix + r.Pattern 76 } 77 78 // UnmarshalJSON - decodes JSON data to Resource. 79 func (r *Resource) UnmarshalJSON(data []byte) error { 80 var s string 81 if err := json.Unmarshal(data, &s); err != nil { 82 return err 83 } 84 85 parsedResource, err := parseResource(s) 86 if err != nil { 87 return err 88 } 89 90 *r = parsedResource 91 92 return nil 93 } 94 95 // Validate - validates Resource is for given bucket or not. 96 func (r Resource) Validate() error { 97 if !r.IsValid() { 98 return Errorf("invalid resource") 99 } 100 return nil 101 } 102 103 // parseResource - parses string to Resource. 104 func parseResource(s string) (Resource, error) { 105 if !strings.HasPrefix(s, ResourceARNPrefix) { 106 return Resource{}, Errorf("invalid resource '%v'", s) 107 } 108 109 pattern := strings.TrimPrefix(s, ResourceARNPrefix) 110 tokens := strings.SplitN(pattern, "/", 2) 111 bucketName := tokens[0] 112 if bucketName == "" { 113 return Resource{}, Errorf("invalid resource format '%v'", s) 114 } 115 116 return Resource{ 117 BucketName: bucketName, 118 Pattern: pattern, 119 }, nil 120 } 121 122 // NewResource - creates new resource. 123 func NewResource(bucketName, keyName string) Resource { 124 pattern := bucketName 125 if keyName != "" { 126 if !strings.HasPrefix(keyName, "/") { 127 pattern += "/" 128 } 129 130 pattern += keyName 131 } 132 133 return Resource{ 134 BucketName: bucketName, 135 Pattern: pattern, 136 } 137 }