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  }