1 // Copyright 2014 Google LLC
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
22 "cloud.google.com/go/internal/trace"
23 "google.golang.org/api/googleapi"
24 raw "google.golang.org/api/storage/v1"
27 // ACLRole is the level of access to grant.
31 RoleOwner ACLRole = "OWNER"
32 RoleReader ACLRole = "READER"
33 RoleWriter ACLRole = "WRITER"
36 // ACLEntity refers to a user or group.
37 // They are sometimes referred to as grantees.
39 // It could be in the form of:
40 // "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>",
41 // "domain-<domain>" and "project-team-<projectId>".
43 // Or one of the predefined constants: AllUsers, AllAuthenticatedUsers.
47 AllUsers ACLEntity = "allUsers"
48 AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers"
51 // ACLRule represents a grant for a role to an entity (user, group or team) for a
52 // Google Cloud Storage object or bucket.
59 ProjectTeam *ProjectTeam
62 // ProjectTeam is the project team associated with the entity, if any.
63 type ProjectTeam struct {
68 // ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
69 type ACLHandle struct {
74 userProject string // for requester-pays buckets
77 // Delete permanently deletes the ACL entry for the given entity.
78 func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) {
79 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete")
80 defer func() { trace.EndSpan(ctx, err) }()
83 return a.objectDelete(ctx, entity)
86 return a.bucketDefaultDelete(ctx, entity)
88 return a.bucketDelete(ctx, entity)
91 // Set sets the role for the given entity.
92 func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) {
93 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set")
94 defer func() { trace.EndSpan(ctx, err) }()
97 return a.objectSet(ctx, entity, role, false)
100 return a.objectSet(ctx, entity, role, true)
102 return a.bucketSet(ctx, entity, role)
105 // List retrieves ACL entries.
106 func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) {
107 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List")
108 defer func() { trace.EndSpan(ctx, err) }()
111 return a.objectList(ctx)
114 return a.bucketDefaultList(ctx)
116 return a.bucketList(ctx)
119 func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
120 var acls *raw.ObjectAccessControls
122 err = runWithRetry(ctx, func() error {
123 req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
124 a.configureCall(ctx, req)
131 return toObjectACLRules(acls.Items), nil
134 func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
135 return runWithRetry(ctx, func() error {
136 req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
137 a.configureCall(ctx, req)
142 func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
143 var acls *raw.BucketAccessControls
145 err = runWithRetry(ctx, func() error {
146 req := a.c.raw.BucketAccessControls.List(a.bucket)
147 a.configureCall(ctx, req)
154 return toBucketACLRules(acls.Items), nil
157 func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error {
158 acl := &raw.BucketAccessControl{
160 Entity: string(entity),
163 err := runWithRetry(ctx, func() error {
164 req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
165 a.configureCall(ctx, req)
175 func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
176 return runWithRetry(ctx, func() error {
177 req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
178 a.configureCall(ctx, req)
183 func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
184 var acls *raw.ObjectAccessControls
186 err = runWithRetry(ctx, func() error {
187 req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
188 a.configureCall(ctx, req)
195 return toObjectACLRules(acls.Items), nil
198 func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error {
199 type setRequest interface {
200 Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error)
204 acl := &raw.ObjectAccessControl{
206 Entity: string(entity),
211 req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl)
213 req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
215 a.configureCall(ctx, req)
216 return runWithRetry(ctx, func() error {
222 func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
223 return runWithRetry(ctx, func() error {
224 req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
225 a.configureCall(ctx, req)
230 func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
231 vc := reflect.ValueOf(call)
232 vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
233 if a.userProject != "" {
234 vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)})
236 setClientHeader(call.Header())
239 func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule {
241 for _, item := range items {
242 rs = append(rs, toObjectACLRule(item))
247 func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule {
249 for _, item := range items {
250 rs = append(rs, toBucketACLRule(item))
255 func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule {
257 Entity: ACLEntity(a.Entity),
258 EntityID: a.EntityId,
259 Role: ACLRole(a.Role),
262 ProjectTeam: toObjectProjectTeam(a.ProjectTeam),
266 func toBucketACLRule(a *raw.BucketAccessControl) ACLRule {
268 Entity: ACLEntity(a.Entity),
269 EntityID: a.EntityId,
270 Role: ACLRole(a.Role),
273 ProjectTeam: toBucketProjectTeam(a.ProjectTeam),
277 func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl {
281 r := make([]*raw.ObjectAccessControl, 0, len(rules))
282 for _, rule := range rules {
283 r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary
288 func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl {
292 r := make([]*raw.BucketAccessControl, 0, len(rules))
293 for _, rule := range rules {
294 r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary
299 func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl {
300 return &raw.BucketAccessControl{
302 Entity: string(r.Entity),
303 Role: string(r.Role),
304 // The other fields are not settable.
308 func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl {
309 return &raw.ObjectAccessControl{
311 Entity: string(r.Entity),
312 Role: string(r.Role),
313 // The other fields are not settable.
317 func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam {
322 ProjectNumber: p.ProjectNumber,
327 func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam {
332 ProjectNumber: p.ProjectNumber,