Home | History | Annotate | Download | only in storage
      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