storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/policy/condition/ipaddressfunc.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 condition
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  	"net/http"
    23  	"sort"
    24  )
    25  
    26  func toIPAddressFuncString(n name, key Key, values []*net.IPNet) string {
    27  	valueStrings := []string{}
    28  	for _, value := range values {
    29  		valueStrings = append(valueStrings, value.String())
    30  	}
    31  	sort.Strings(valueStrings)
    32  
    33  	return fmt.Sprintf("%v:%v:%v", n, key, valueStrings)
    34  }
    35  
    36  // ipAddressFunc - IP address function. It checks whether value by Key in given
    37  // values is in IP network.  Here Key must be AWSSourceIP.
    38  // For example,
    39  //   - if values = [192.168.1.0/24], at evaluate() it returns whether IP address
    40  //     in value map for AWSSourceIP falls in the network 192.168.1.10/24.
    41  type ipAddressFunc struct {
    42  	k      Key
    43  	values []*net.IPNet
    44  }
    45  
    46  // evaluate() - evaluates to check whether IP address in values map for AWSSourceIP
    47  // falls in one of network or not.
    48  func (f ipAddressFunc) evaluate(values map[string][]string) bool {
    49  	IPs := []net.IP{}
    50  	requestValue, ok := values[http.CanonicalHeaderKey(f.k.Name())]
    51  	if !ok {
    52  		requestValue = values[f.k.Name()]
    53  	}
    54  
    55  	for _, s := range requestValue {
    56  		IP := net.ParseIP(s)
    57  		if IP == nil {
    58  			panic(fmt.Errorf("invalid IP address '%v'", s))
    59  		}
    60  
    61  		IPs = append(IPs, IP)
    62  	}
    63  
    64  	for _, IP := range IPs {
    65  		for _, IPNet := range f.values {
    66  			if IPNet.Contains(IP) {
    67  				return true
    68  			}
    69  		}
    70  	}
    71  
    72  	return false
    73  }
    74  
    75  // key() - returns condition key which is used by this condition function.
    76  // Key is always AWSSourceIP.
    77  func (f ipAddressFunc) key() Key {
    78  	return f.k
    79  }
    80  
    81  // name() - returns "IpAddress" condition name.
    82  func (f ipAddressFunc) name() name {
    83  	return ipAddress
    84  }
    85  
    86  func (f ipAddressFunc) String() string {
    87  	return toIPAddressFuncString(ipAddress, f.k, f.values)
    88  }
    89  
    90  // toMap - returns map representation of this function.
    91  func (f ipAddressFunc) toMap() map[Key]ValueSet {
    92  	if !f.k.IsValid() {
    93  		return nil
    94  	}
    95  
    96  	values := NewValueSet()
    97  	for _, value := range f.values {
    98  		values.Add(NewStringValue(value.String()))
    99  	}
   100  
   101  	return map[Key]ValueSet{
   102  		f.k: values,
   103  	}
   104  }
   105  
   106  // notIPAddressFunc - Not IP address function. It checks whether value by Key in given
   107  // values is NOT in IP network.  Here Key must be AWSSourceIP.
   108  // For example,
   109  //   - if values = [192.168.1.0/24], at evaluate() it returns whether IP address
   110  //     in value map for AWSSourceIP does not fall in the network 192.168.1.10/24.
   111  type notIPAddressFunc struct {
   112  	ipAddressFunc
   113  }
   114  
   115  // evaluate() - evaluates to check whether IP address in values map for AWSSourceIP
   116  // does not fall in one of network.
   117  func (f notIPAddressFunc) evaluate(values map[string][]string) bool {
   118  	return !f.ipAddressFunc.evaluate(values)
   119  }
   120  
   121  // name() - returns "NotIpAddress" condition name.
   122  func (f notIPAddressFunc) name() name {
   123  	return notIPAddress
   124  }
   125  
   126  func (f notIPAddressFunc) String() string {
   127  	return toIPAddressFuncString(notIPAddress, f.ipAddressFunc.k, f.ipAddressFunc.values)
   128  }
   129  
   130  func valuesToIPNets(n name, values ValueSet) ([]*net.IPNet, error) {
   131  	IPNets := []*net.IPNet{}
   132  	for v := range values {
   133  		s, err := v.GetString()
   134  		if err != nil {
   135  			return nil, fmt.Errorf("value %v must be string representation of CIDR for %v condition", v, n)
   136  		}
   137  
   138  		var IPNet *net.IPNet
   139  		_, IPNet, err = net.ParseCIDR(s)
   140  		if err != nil {
   141  			return nil, fmt.Errorf("value %v must be CIDR string for %v condition", s, n)
   142  		}
   143  
   144  		IPNets = append(IPNets, IPNet)
   145  	}
   146  
   147  	return IPNets, nil
   148  }
   149  
   150  // newIPAddressFunc - returns new IP address function.
   151  func newIPAddressFunc(key Key, values ValueSet) (Function, error) {
   152  	IPNets, err := valuesToIPNets(ipAddress, values)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	return NewIPAddressFunc(key, IPNets...)
   158  }
   159  
   160  // NewIPAddressFunc - returns new IP address function.
   161  func NewIPAddressFunc(key Key, IPNets ...*net.IPNet) (Function, error) {
   162  	if key != AWSSourceIP {
   163  		return nil, fmt.Errorf("only %v key is allowed for %v condition", AWSSourceIP, ipAddress)
   164  	}
   165  
   166  	return &ipAddressFunc{key, IPNets}, nil
   167  }
   168  
   169  // newNotIPAddressFunc - returns new Not IP address function.
   170  func newNotIPAddressFunc(key Key, values ValueSet) (Function, error) {
   171  	IPNets, err := valuesToIPNets(notIPAddress, values)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	return NewNotIPAddressFunc(key, IPNets...)
   177  }
   178  
   179  // NewNotIPAddressFunc - returns new Not IP address function.
   180  func NewNotIPAddressFunc(key Key, IPNets ...*net.IPNet) (Function, error) {
   181  	if key != AWSSourceIP {
   182  		return nil, fmt.Errorf("only %v key is allowed for %v condition", AWSSourceIP, notIPAddress)
   183  	}
   184  
   185  	return &notIPAddressFunc{ipAddressFunc{key, IPNets}}, nil
   186  }