storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/acl-handlers.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/xml"
    21  	"io"
    22  	"net/http"
    23  
    24  	"github.com/gorilla/mux"
    25  
    26  	xhttp "storj.io/minio/cmd/http"
    27  	"storj.io/minio/cmd/logger"
    28  	"storj.io/minio/pkg/bucket/policy"
    29  )
    30  
    31  // Data types used for returning dummy access control
    32  // policy XML, these variables shouldn't be used elsewhere
    33  // they are only defined to be used in this file alone.
    34  type grantee struct {
    35  	XMLNS       string `xml:"xmlns:xsi,attr"`
    36  	XMLXSI      string `xml:"xsi:type,attr"`
    37  	Type        string `xml:"Type"`
    38  	ID          string `xml:"ID,omitempty"`
    39  	DisplayName string `xml:"DisplayName,omitempty"`
    40  	URI         string `xml:"URI,omitempty"`
    41  }
    42  
    43  type grant struct {
    44  	Grantee    grantee `xml:"Grantee"`
    45  	Permission string  `xml:"Permission"`
    46  }
    47  
    48  type accessControlPolicy struct {
    49  	XMLName           xml.Name `xml:"AccessControlPolicy"`
    50  	Owner             Owner    `xml:"Owner"`
    51  	AccessControlList struct {
    52  		Grants []grant `xml:"Grant"`
    53  	} `xml:"AccessControlList"`
    54  }
    55  
    56  // PutBucketACLHandler - PUT Bucket ACL
    57  // -----------------
    58  // This operation uses the ACL subresource
    59  // to set ACL for a bucket, this is a dummy call
    60  // only responds success if the ACL is private.
    61  func (api ObjectAPIHandlers) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
    62  	ctx := NewContext(r, w, "PutBucketACL")
    63  
    64  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
    65  
    66  	vars := mux.Vars(r)
    67  	bucket := vars["bucket"]
    68  
    69  	objAPI := api.ObjectAPI()
    70  	if objAPI == nil {
    71  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
    72  		return
    73  	}
    74  
    75  	// Allow putBucketACL if policy action is set, since this is a dummy call
    76  	// we are simply re-purposing the bucketPolicyAction.
    77  	if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketPolicyAction, bucket, ""); s3Error != ErrNone {
    78  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
    79  		return
    80  	}
    81  
    82  	// Before proceeding validate if bucket exists.
    83  	_, err := objAPI.GetBucketInfo(ctx, bucket)
    84  	if err != nil {
    85  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
    86  		return
    87  	}
    88  
    89  	aclHeader := r.Header.Get(xhttp.AmzACL)
    90  	if aclHeader == "" {
    91  		acl := &accessControlPolicy{}
    92  		if err = xmlDecoder(r.Body, acl, r.ContentLength); err != nil {
    93  			if err == io.EOF {
    94  				WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingSecurityHeader),
    95  					r.URL, guessIsBrowserReq(r))
    96  				return
    97  			}
    98  			WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
    99  			return
   100  		}
   101  
   102  		if len(acl.AccessControlList.Grants) == 0 {
   103  			WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   104  			return
   105  		}
   106  
   107  		if acl.AccessControlList.Grants[0].Permission != "FULL_CONTROL" {
   108  			WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   109  			return
   110  		}
   111  	}
   112  
   113  	if aclHeader != "" && aclHeader != "private" {
   114  		WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   115  		return
   116  	}
   117  
   118  	w.(http.Flusher).Flush()
   119  }
   120  
   121  // GetBucketACLHandler - GET Bucket ACL
   122  // -----------------
   123  // This operation uses the ACL
   124  // subresource to return the ACL of a specified bucket.
   125  func (api ObjectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
   126  	ctx := NewContext(r, w, "GetBucketACL")
   127  
   128  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   129  
   130  	vars := mux.Vars(r)
   131  	bucket := vars["bucket"]
   132  
   133  	objAPI := api.ObjectAPI()
   134  	if objAPI == nil {
   135  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
   136  		return
   137  	}
   138  
   139  	// Allow getBucketACL if policy action is set, since this is a dummy call
   140  	// we are simply re-purposing the bucketPolicyAction.
   141  	if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone {
   142  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
   143  		return
   144  	}
   145  
   146  	// Before proceeding validate if bucket exists.
   147  	_, err := objAPI.GetBucketInfo(ctx, bucket)
   148  	if err != nil {
   149  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   150  		return
   151  	}
   152  
   153  	acl := &accessControlPolicy{}
   154  	acl.AccessControlList.Grants = append(acl.AccessControlList.Grants, grant{
   155  		Grantee: grantee{
   156  			XMLNS:  "http://www.w3.org/2001/XMLSchema-instance",
   157  			XMLXSI: "CanonicalUser",
   158  			Type:   "CanonicalUser",
   159  		},
   160  		Permission: "FULL_CONTROL",
   161  	})
   162  
   163  	if err := xml.NewEncoder(w).Encode(acl); err != nil {
   164  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   165  		return
   166  	}
   167  
   168  	w.(http.Flusher).Flush()
   169  }
   170  
   171  // PutObjectACLHandler - PUT Object ACL
   172  // -----------------
   173  // This operation uses the ACL subresource
   174  // to set ACL for a bucket, this is a dummy call
   175  // only responds success if the ACL is private.
   176  func (api ObjectAPIHandlers) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
   177  	ctx := NewContext(r, w, "PutObjectACL")
   178  
   179  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   180  
   181  	vars := mux.Vars(r)
   182  	bucket := vars["bucket"]
   183  	object, err := unescapePath(vars["object"])
   184  	if err != nil {
   185  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   186  		return
   187  	}
   188  
   189  	objAPI := api.ObjectAPI()
   190  	if objAPI == nil {
   191  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
   192  		return
   193  	}
   194  
   195  	// Allow putObjectACL if policy action is set, since this is a dummy call
   196  	// we are simply re-purposing the bucketPolicyAction.
   197  	if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketPolicyAction, bucket, ""); s3Error != ErrNone {
   198  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
   199  		return
   200  	}
   201  
   202  	// Before proceeding validate if object exists.
   203  	_, err = objAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{})
   204  	if err != nil {
   205  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   206  		return
   207  	}
   208  
   209  	aclHeader := r.Header.Get(xhttp.AmzACL)
   210  	if aclHeader == "" {
   211  		acl := &accessControlPolicy{}
   212  		if err = xmlDecoder(r.Body, acl, r.ContentLength); err != nil {
   213  			WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   214  			return
   215  		}
   216  
   217  		if len(acl.AccessControlList.Grants) == 0 {
   218  			WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   219  			return
   220  		}
   221  
   222  		if acl.AccessControlList.Grants[0].Permission != "FULL_CONTROL" {
   223  			WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   224  			return
   225  		}
   226  	}
   227  
   228  	if aclHeader != "" && aclHeader != "private" {
   229  		WriteErrorResponse(ctx, w, ToAPIError(ctx, NotImplemented{}), r.URL, guessIsBrowserReq(r))
   230  		return
   231  	}
   232  
   233  	w.(http.Flusher).Flush()
   234  }
   235  
   236  // GetObjectACLHandler - GET Object ACL
   237  // -----------------
   238  // This operation uses the ACL
   239  // subresource to return the ACL of a specified object.
   240  func (api ObjectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
   241  	ctx := NewContext(r, w, "GetObjectACL")
   242  
   243  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   244  
   245  	vars := mux.Vars(r)
   246  	bucket := vars["bucket"]
   247  	object, err := unescapePath(vars["object"])
   248  	if err != nil {
   249  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   250  		return
   251  	}
   252  
   253  	objAPI := api.ObjectAPI()
   254  	if objAPI == nil {
   255  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
   256  		return
   257  	}
   258  
   259  	// Allow getObjectACL if policy action is set, since this is a dummy call
   260  	// we are simply re-purposing the bucketPolicyAction.
   261  	if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone {
   262  		WriteErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
   263  		return
   264  	}
   265  
   266  	// Before proceeding validate if object exists.
   267  	_, err = objAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{})
   268  	if err != nil {
   269  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   270  		return
   271  	}
   272  
   273  	acl := &accessControlPolicy{}
   274  	acl.AccessControlList.Grants = append(acl.AccessControlList.Grants, grant{
   275  		Grantee: grantee{
   276  			XMLNS:  "http://www.w3.org/2001/XMLSchema-instance",
   277  			XMLXSI: "CanonicalUser",
   278  			Type:   "CanonicalUser",
   279  		},
   280  		Permission: "FULL_CONTROL",
   281  	})
   282  	if err := xml.NewEncoder(w).Encode(acl); err != nil {
   283  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   284  		return
   285  	}
   286  
   287  	w.(http.Flusher).Flush()
   288  }