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  }