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