• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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