storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/bucket-policy.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018,2020 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 cmd
    18  
    19  import (
    20  	"encoding/json"
    21  	"net/http"
    22  	"net/url"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	jsoniter "github.com/json-iterator/go"
    28  	miniogopolicy "github.com/minio/minio-go/v7/pkg/policy"
    29  
    30  	xhttp "storj.io/minio/cmd/http"
    31  	"storj.io/minio/cmd/logger"
    32  	"storj.io/minio/pkg/bucket/policy"
    33  	"storj.io/minio/pkg/handlers"
    34  )
    35  
    36  // PolicySys - policy subsystem.
    37  type PolicySys struct{}
    38  
    39  // Get returns stored bucket policy
    40  func (sys *PolicySys) Get(bucket string) (*policy.Policy, error) {
    41  	return globalBucketMetadataSys.GetPolicyConfig(bucket)
    42  }
    43  
    44  // IsAllowed - checks given policy args is allowed to continue the Rest API.
    45  func (sys *PolicySys) IsAllowed(args policy.Args) bool {
    46  	p, err := sys.Get(args.BucketName)
    47  	if err == nil {
    48  		return p.IsAllowed(args)
    49  	}
    50  
    51  	// Log unhandled errors.
    52  	if _, ok := err.(BucketPolicyNotFound); !ok {
    53  		logger.LogIf(GlobalContext, err)
    54  	}
    55  
    56  	// As policy is not available for given bucket name, returns IsOwner i.e.
    57  	// operation is allowed only for owner.
    58  	return args.IsOwner
    59  }
    60  
    61  // NewPolicySys - creates new policy system.
    62  func NewPolicySys() *PolicySys {
    63  	return &PolicySys{}
    64  }
    65  
    66  func getConditionValues(r *http.Request, lc string, username string, claims map[string]interface{}) map[string][]string {
    67  	currTime := UTCNow()
    68  
    69  	principalType := "Anonymous"
    70  	if username != "" {
    71  		principalType = "User"
    72  		if len(claims) > 0 {
    73  			principalType = "AssumedRole"
    74  		}
    75  		if username == globalActiveCred.AccessKey {
    76  			principalType = "Account"
    77  		}
    78  	}
    79  
    80  	vid := r.URL.Query().Get("versionId")
    81  	if vid == "" {
    82  		if u, err := url.Parse(r.Header.Get(xhttp.AmzCopySource)); err == nil {
    83  			vid = u.Query().Get("versionId")
    84  		}
    85  	}
    86  
    87  	authType := getRequestAuthType(r)
    88  	var signatureVersion string
    89  	switch authType {
    90  	case authTypeSignedV2, authTypePresignedV2:
    91  		signatureVersion = signV2Algorithm
    92  	case authTypeSigned, authTypePresigned, authTypeStreamingSigned, authTypePostPolicy:
    93  		signatureVersion = signV4Algorithm
    94  	}
    95  
    96  	var authtype string
    97  	switch authType {
    98  	case authTypePresignedV2, authTypePresigned:
    99  		authtype = "REST-QUERY-STRING"
   100  	case authTypeSignedV2, authTypeSigned, authTypeStreamingSigned:
   101  		authtype = "REST-HEADER"
   102  	case authTypePostPolicy:
   103  		authtype = "POST"
   104  	}
   105  
   106  	args := map[string][]string{
   107  		"CurrentTime":      {currTime.Format(time.RFC3339)},
   108  		"EpochTime":        {strconv.FormatInt(currTime.Unix(), 10)},
   109  		"SecureTransport":  {strconv.FormatBool(r.TLS != nil)},
   110  		"SourceIp":         {handlers.GetSourceIP(r)},
   111  		"UserAgent":        {r.UserAgent()},
   112  		"Referer":          {r.Referer()},
   113  		"principaltype":    {principalType},
   114  		"userid":           {username},
   115  		"username":         {username},
   116  		"versionid":        {vid},
   117  		"signatureversion": {signatureVersion},
   118  		"authType":         {authtype},
   119  	}
   120  
   121  	if lc != "" {
   122  		args["LocationConstraint"] = []string{lc}
   123  	}
   124  
   125  	cloneHeader := r.Header.Clone()
   126  
   127  	for _, objLock := range []string{
   128  		xhttp.AmzObjectLockMode,
   129  		xhttp.AmzObjectLockLegalHold,
   130  		xhttp.AmzObjectLockRetainUntilDate,
   131  	} {
   132  		if values, ok := cloneHeader[objLock]; ok {
   133  			args[strings.TrimPrefix(objLock, "X-Amz-")] = values
   134  		}
   135  		cloneHeader.Del(objLock)
   136  	}
   137  
   138  	for key, values := range cloneHeader {
   139  		if existingValues, found := args[key]; found {
   140  			args[key] = append(existingValues, values...)
   141  		} else {
   142  			args[key] = values
   143  		}
   144  	}
   145  
   146  	var cloneURLValues = url.Values{}
   147  	for k, v := range r.URL.Query() {
   148  		cloneURLValues[k] = v
   149  	}
   150  
   151  	for _, objLock := range []string{
   152  		xhttp.AmzObjectLockMode,
   153  		xhttp.AmzObjectLockLegalHold,
   154  		xhttp.AmzObjectLockRetainUntilDate,
   155  	} {
   156  		if values, ok := cloneURLValues[objLock]; ok {
   157  			args[strings.TrimPrefix(objLock, "X-Amz-")] = values
   158  		}
   159  		cloneURLValues.Del(objLock)
   160  	}
   161  
   162  	for key, values := range cloneURLValues {
   163  		if existingValues, found := args[key]; found {
   164  			args[key] = append(existingValues, values...)
   165  		} else {
   166  			args[key] = values
   167  		}
   168  	}
   169  
   170  	// JWT specific values
   171  	for k, v := range claims {
   172  		vStr, ok := v.(string)
   173  		if ok {
   174  			// Special case for AD/LDAP STS users
   175  			if k == ldapUser {
   176  				args["user"] = []string{vStr}
   177  			} else {
   178  				args[k] = []string{vStr}
   179  			}
   180  		}
   181  	}
   182  
   183  	return args
   184  }
   185  
   186  // PolicyToBucketAccessPolicy converts a MinIO policy into a minio-go policy data structure.
   187  func PolicyToBucketAccessPolicy(bucketPolicy *policy.Policy) (*miniogopolicy.BucketAccessPolicy, error) {
   188  	// Return empty BucketAccessPolicy for empty bucket policy.
   189  	if bucketPolicy == nil {
   190  		return &miniogopolicy.BucketAccessPolicy{Version: policy.DefaultVersion}, nil
   191  	}
   192  
   193  	data, err := json.Marshal(bucketPolicy)
   194  	if err != nil {
   195  		// This should not happen because bucketPolicy is valid to convert to JSON data.
   196  		return nil, err
   197  	}
   198  
   199  	var policyInfo miniogopolicy.BucketAccessPolicy
   200  	var json = jsoniter.ConfigCompatibleWithStandardLibrary
   201  	if err = json.Unmarshal(data, &policyInfo); err != nil {
   202  		// This should not happen because data is valid to JSON data.
   203  		return nil, err
   204  	}
   205  
   206  	return &policyInfo, nil
   207  }
   208  
   209  // BucketAccessPolicyToPolicy - converts minio-go/policy.BucketAccessPolicy to policy.Policy.
   210  func BucketAccessPolicyToPolicy(policyInfo *miniogopolicy.BucketAccessPolicy) (*policy.Policy, error) {
   211  	data, err := json.Marshal(policyInfo)
   212  	if err != nil {
   213  		// This should not happen because policyInfo is valid to convert to JSON data.
   214  		return nil, err
   215  	}
   216  
   217  	var bucketPolicy policy.Policy
   218  	var json = jsoniter.ConfigCompatibleWithStandardLibrary
   219  	if err = json.Unmarshal(data, &bucketPolicy); err != nil {
   220  		// This should not happen because data is valid to JSON data.
   221  		return nil, err
   222  	}
   223  
   224  	return &bucketPolicy, nil
   225  }