1// Copyright 2014 Google Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package storage 16 17import ( 18 "fmt" 19 "net/http" 20 "reflect" 21 22 "golang.org/x/net/context" 23 "google.golang.org/api/googleapi" 24 raw "google.golang.org/api/storage/v1" 25) 26 27// ACLRole is the level of access to grant. 28type ACLRole string 29 30const ( 31 RoleOwner ACLRole = "OWNER" 32 RoleReader ACLRole = "READER" 33 RoleWriter ACLRole = "WRITER" 34) 35 36// ACLEntity refers to a user or group. 37// They are sometimes referred to as grantees. 38// 39// It could be in the form of: 40// "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>", 41// "domain-<domain>" and "project-team-<projectId>". 42// 43// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers. 44type ACLEntity string 45 46const ( 47 AllUsers ACLEntity = "allUsers" 48 AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers" 49) 50 51// ACLRule represents a grant for a role to an entity (user, group or team) for a Google Cloud Storage object or bucket. 52type ACLRule struct { 53 Entity ACLEntity 54 Role ACLRole 55} 56 57// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object. 58type ACLHandle struct { 59 c *Client 60 bucket string 61 object string 62 isDefault bool 63 userProject string // for requester-pays buckets 64} 65 66// Delete permanently deletes the ACL entry for the given entity. 67func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) error { 68 if a.object != "" { 69 return a.objectDelete(ctx, entity) 70 } 71 if a.isDefault { 72 return a.bucketDefaultDelete(ctx, entity) 73 } 74 return a.bucketDelete(ctx, entity) 75} 76 77// Set sets the permission level for the given entity. 78func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) error { 79 if a.object != "" { 80 return a.objectSet(ctx, entity, role, false) 81 } 82 if a.isDefault { 83 return a.objectSet(ctx, entity, role, true) 84 } 85 return a.bucketSet(ctx, entity, role) 86} 87 88// List retrieves ACL entries. 89func (a *ACLHandle) List(ctx context.Context) ([]ACLRule, error) { 90 if a.object != "" { 91 return a.objectList(ctx) 92 } 93 if a.isDefault { 94 return a.bucketDefaultList(ctx) 95 } 96 return a.bucketList(ctx) 97} 98 99func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) { 100 var acls *raw.ObjectAccessControls 101 var err error 102 err = runWithRetry(ctx, func() error { 103 req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) 104 a.configureCall(req, ctx) 105 acls, err = req.Do() 106 return err 107 }) 108 if err != nil { 109 return nil, fmt.Errorf("storage: error listing default object ACL for bucket %q: %v", a.bucket, err) 110 } 111 return toACLRules(acls.Items), nil 112} 113 114func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { 115 err := runWithRetry(ctx, func() error { 116 req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) 117 a.configureCall(req, ctx) 118 return req.Do() 119 }) 120 if err != nil { 121 return fmt.Errorf("storage: error deleting default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) 122 } 123 return nil 124} 125 126func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { 127 var acls *raw.BucketAccessControls 128 var err error 129 err = runWithRetry(ctx, func() error { 130 req := a.c.raw.BucketAccessControls.List(a.bucket) 131 a.configureCall(req, ctx) 132 acls, err = req.Do() 133 return err 134 }) 135 if err != nil { 136 return nil, fmt.Errorf("storage: error listing bucket ACL for bucket %q: %v", a.bucket, err) 137 } 138 r := make([]ACLRule, len(acls.Items)) 139 for i, v := range acls.Items { 140 r[i].Entity = ACLEntity(v.Entity) 141 r[i].Role = ACLRole(v.Role) 142 } 143 return r, nil 144} 145 146func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { 147 acl := &raw.BucketAccessControl{ 148 Bucket: a.bucket, 149 Entity: string(entity), 150 Role: string(role), 151 } 152 err := runWithRetry(ctx, func() error { 153 req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) 154 a.configureCall(req, ctx) 155 _, err := req.Do() 156 return err 157 }) 158 if err != nil { 159 return fmt.Errorf("storage: error updating bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) 160 } 161 return nil 162} 163 164func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { 165 err := runWithRetry(ctx, func() error { 166 req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) 167 a.configureCall(req, ctx) 168 return req.Do() 169 }) 170 if err != nil { 171 return fmt.Errorf("storage: error deleting bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) 172 } 173 return nil 174} 175 176func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { 177 var acls *raw.ObjectAccessControls 178 var err error 179 err = runWithRetry(ctx, func() error { 180 req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) 181 a.configureCall(req, ctx) 182 acls, err = req.Do() 183 return err 184 }) 185 if err != nil { 186 return nil, fmt.Errorf("storage: error listing object ACL for bucket %q, file %q: %v", a.bucket, a.object, err) 187 } 188 return toACLRules(acls.Items), nil 189} 190 191func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { 192 type setRequest interface { 193 Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) 194 Header() http.Header 195 } 196 197 acl := &raw.ObjectAccessControl{ 198 Bucket: a.bucket, 199 Entity: string(entity), 200 Role: string(role), 201 } 202 var req setRequest 203 if isBucketDefault { 204 req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl) 205 } else { 206 req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) 207 } 208 a.configureCall(req, ctx) 209 err := runWithRetry(ctx, func() error { 210 _, err := req.Do() 211 return err 212 }) 213 if err != nil { 214 if isBucketDefault { 215 return fmt.Errorf("storage: error updating default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) 216 } else { 217 return fmt.Errorf("storage: error updating object ACL entry for bucket %q, object %q, entity %q: %v", a.bucket, a.object, entity, err) 218 } 219 } 220 return nil 221} 222 223func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { 224 err := runWithRetry(ctx, func() error { 225 req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) 226 a.configureCall(req, ctx) 227 return req.Do() 228 }) 229 if err != nil { 230 return fmt.Errorf("storage: error deleting object ACL entry for bucket %q, file %q, entity %q: %v", a.bucket, a.object, entity, err) 231 } 232 return nil 233} 234 235func (a *ACLHandle) configureCall(call interface { 236 Header() http.Header 237}, ctx context.Context) { 238 vc := reflect.ValueOf(call) 239 vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) 240 if a.userProject != "" { 241 vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)}) 242 } 243 setClientHeader(call.Header()) 244} 245 246func toACLRules(items []*raw.ObjectAccessControl) []ACLRule { 247 r := make([]ACLRule, 0, len(items)) 248 for _, item := range items { 249 r = append(r, ACLRule{Entity: ACLEntity(item.Entity), Role: ACLRole(item.Role)}) 250 } 251 return r 252} 253