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 15 package storage 16 17 import ( 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. 28 type ACLRole string 29 30 const ( 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. 44 type ACLEntity string 45 46 const ( 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. 52 type 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. 58 type 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. 67 func (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. 78 func (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. 89 func (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 99 func (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 114 func (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 126 func (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 146 func (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 164 func (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 176 func (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 191 func (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 223 func (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 235 func (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 246 func 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