1/* 2 * Minio Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2018 Minio, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package minio 19 20import ( 21 "context" 22 "net/http" 23 "net/url" 24) 25 26type accessControlPolicy struct { 27 Owner struct { 28 ID string `xml:"ID"` 29 DisplayName string `xml:"DisplayName"` 30 } `xml:"Owner"` 31 AccessControlList struct { 32 Grant []struct { 33 Grantee struct { 34 ID string `xml:"ID"` 35 DisplayName string `xml:"DisplayName"` 36 URI string `xml:"URI"` 37 } `xml:"Grantee"` 38 Permission string `xml:"Permission"` 39 } `xml:"Grant"` 40 } `xml:"AccessControlList"` 41} 42 43//GetObjectACL get object ACLs 44func (c Client) GetObjectACL(bucketName, objectName string) (*ObjectInfo, error) { 45 46 resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ 47 bucketName: bucketName, 48 objectName: objectName, 49 queryValues: url.Values{ 50 "acl": []string{""}, 51 }, 52 }) 53 if err != nil { 54 return nil, err 55 } 56 defer closeResponse(resp) 57 58 if resp.StatusCode != http.StatusOK { 59 return nil, httpRespToErrorResponse(resp, bucketName, objectName) 60 } 61 62 res := &accessControlPolicy{} 63 64 if err := xmlDecoder(resp.Body, res); err != nil { 65 return nil, err 66 } 67 68 objInfo, err := c.statObject(context.Background(), bucketName, objectName, StatObjectOptions{}) 69 if err != nil { 70 return nil, err 71 } 72 73 cannedACL := getCannedACL(res) 74 if cannedACL != "" { 75 objInfo.Metadata.Add("X-Amz-Acl", cannedACL) 76 return &objInfo, nil 77 } 78 79 grantACL := getAmzGrantACL(res) 80 for k, v := range grantACL { 81 objInfo.Metadata[k] = v 82 } 83 84 return &objInfo, nil 85} 86 87func getCannedACL(aCPolicy *accessControlPolicy) string { 88 grants := aCPolicy.AccessControlList.Grant 89 90 switch { 91 case len(grants) == 1: 92 if grants[0].Grantee.URI == "" && grants[0].Permission == "FULL_CONTROL" { 93 return "private" 94 } 95 case len(grants) == 2: 96 for _, g := range grants { 97 if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" && g.Permission == "READ" { 98 return "authenticated-read" 99 } 100 if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "READ" { 101 return "public-read" 102 } 103 if g.Permission == "READ" && g.Grantee.ID == aCPolicy.Owner.ID { 104 return "bucket-owner-read" 105 } 106 } 107 case len(grants) == 3: 108 for _, g := range grants { 109 if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "WRITE" { 110 return "public-read-write" 111 } 112 } 113 } 114 return "" 115} 116 117func getAmzGrantACL(aCPolicy *accessControlPolicy) map[string][]string { 118 grants := aCPolicy.AccessControlList.Grant 119 res := map[string][]string{} 120 121 for _, g := range grants { 122 switch { 123 case g.Permission == "READ": 124 res["X-Amz-Grant-Read"] = append(res["X-Amz-Grant-Read"], "id="+g.Grantee.ID) 125 case g.Permission == "WRITE": 126 res["X-Amz-Grant-Write"] = append(res["X-Amz-Grant-Write"], "id="+g.Grantee.ID) 127 case g.Permission == "READ_ACP": 128 res["X-Amz-Grant-Read-Acp"] = append(res["X-Amz-Grant-Read-Acp"], "id="+g.Grantee.ID) 129 case g.Permission == "WRITE_ACP": 130 res["X-Amz-Grant-Write-Acp"] = append(res["X-Amz-Grant-Write-Acp"], "id="+g.Grantee.ID) 131 case g.Permission == "FULL_CONTROL": 132 res["X-Amz-Grant-Full-Control"] = append(res["X-Amz-Grant-Full-Control"], "id="+g.Grantee.ID) 133 } 134 } 135 return res 136} 137