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 }