You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

336 lines
8.7 KiB

  1. // Copyright 2014 Google LLC
  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. package storage
  15. import (
  16. "context"
  17. "net/http"
  18. "reflect"
  19. "cloud.google.com/go/internal/trace"
  20. "google.golang.org/api/googleapi"
  21. raw "google.golang.org/api/storage/v1"
  22. )
  23. // ACLRole is the level of access to grant.
  24. type ACLRole string
  25. const (
  26. RoleOwner ACLRole = "OWNER"
  27. RoleReader ACLRole = "READER"
  28. RoleWriter ACLRole = "WRITER"
  29. )
  30. // ACLEntity refers to a user or group.
  31. // They are sometimes referred to as grantees.
  32. //
  33. // It could be in the form of:
  34. // "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>",
  35. // "domain-<domain>" and "project-team-<projectId>".
  36. //
  37. // Or one of the predefined constants: AllUsers, AllAuthenticatedUsers.
  38. type ACLEntity string
  39. const (
  40. AllUsers ACLEntity = "allUsers"
  41. AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers"
  42. )
  43. // ACLRule represents a grant for a role to an entity (user, group or team) for a
  44. // Google Cloud Storage object or bucket.
  45. type ACLRule struct {
  46. Entity ACLEntity
  47. EntityID string
  48. Role ACLRole
  49. Domain string
  50. Email string
  51. ProjectTeam *ProjectTeam
  52. }
  53. // ProjectTeam is the project team associated with the entity, if any.
  54. type ProjectTeam struct {
  55. ProjectNumber string
  56. Team string
  57. }
  58. // ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
  59. type ACLHandle struct {
  60. c *Client
  61. bucket string
  62. object string
  63. isDefault bool
  64. userProject string // for requester-pays buckets
  65. }
  66. // Delete permanently deletes the ACL entry for the given entity.
  67. func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) {
  68. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete")
  69. defer func() { trace.EndSpan(ctx, err) }()
  70. if a.object != "" {
  71. return a.objectDelete(ctx, entity)
  72. }
  73. if a.isDefault {
  74. return a.bucketDefaultDelete(ctx, entity)
  75. }
  76. return a.bucketDelete(ctx, entity)
  77. }
  78. // Set sets the role for the given entity.
  79. func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) {
  80. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set")
  81. defer func() { trace.EndSpan(ctx, err) }()
  82. if a.object != "" {
  83. return a.objectSet(ctx, entity, role, false)
  84. }
  85. if a.isDefault {
  86. return a.objectSet(ctx, entity, role, true)
  87. }
  88. return a.bucketSet(ctx, entity, role)
  89. }
  90. // List retrieves ACL entries.
  91. func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) {
  92. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List")
  93. defer func() { trace.EndSpan(ctx, err) }()
  94. if a.object != "" {
  95. return a.objectList(ctx)
  96. }
  97. if a.isDefault {
  98. return a.bucketDefaultList(ctx)
  99. }
  100. return a.bucketList(ctx)
  101. }
  102. func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
  103. var acls *raw.ObjectAccessControls
  104. var err error
  105. err = runWithRetry(ctx, func() error {
  106. req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
  107. a.configureCall(ctx, req)
  108. acls, err = req.Do()
  109. return err
  110. })
  111. if err != nil {
  112. return nil, err
  113. }
  114. return toObjectACLRules(acls.Items), nil
  115. }
  116. func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
  117. return runWithRetry(ctx, func() error {
  118. req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
  119. a.configureCall(ctx, req)
  120. return req.Do()
  121. })
  122. }
  123. func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
  124. var acls *raw.BucketAccessControls
  125. var err error
  126. err = runWithRetry(ctx, func() error {
  127. req := a.c.raw.BucketAccessControls.List(a.bucket)
  128. a.configureCall(ctx, req)
  129. acls, err = req.Do()
  130. return err
  131. })
  132. if err != nil {
  133. return nil, err
  134. }
  135. return toBucketACLRules(acls.Items), nil
  136. }
  137. func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error {
  138. acl := &raw.BucketAccessControl{
  139. Bucket: a.bucket,
  140. Entity: string(entity),
  141. Role: string(role),
  142. }
  143. err := runWithRetry(ctx, func() error {
  144. req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
  145. a.configureCall(ctx, req)
  146. _, err := req.Do()
  147. return err
  148. })
  149. if err != nil {
  150. return err
  151. }
  152. return nil
  153. }
  154. func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
  155. return runWithRetry(ctx, func() error {
  156. req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
  157. a.configureCall(ctx, req)
  158. return req.Do()
  159. })
  160. }
  161. func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
  162. var acls *raw.ObjectAccessControls
  163. var err error
  164. err = runWithRetry(ctx, func() error {
  165. req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
  166. a.configureCall(ctx, req)
  167. acls, err = req.Do()
  168. return err
  169. })
  170. if err != nil {
  171. return nil, err
  172. }
  173. return toObjectACLRules(acls.Items), nil
  174. }
  175. func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error {
  176. type setRequest interface {
  177. Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error)
  178. Header() http.Header
  179. }
  180. acl := &raw.ObjectAccessControl{
  181. Bucket: a.bucket,
  182. Entity: string(entity),
  183. Role: string(role),
  184. }
  185. var req setRequest
  186. if isBucketDefault {
  187. req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl)
  188. } else {
  189. req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
  190. }
  191. a.configureCall(ctx, req)
  192. return runWithRetry(ctx, func() error {
  193. _, err := req.Do()
  194. return err
  195. })
  196. }
  197. func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
  198. return runWithRetry(ctx, func() error {
  199. req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
  200. a.configureCall(ctx, req)
  201. return req.Do()
  202. })
  203. }
  204. func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
  205. vc := reflect.ValueOf(call)
  206. vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
  207. if a.userProject != "" {
  208. vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)})
  209. }
  210. setClientHeader(call.Header())
  211. }
  212. func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule {
  213. var rs []ACLRule
  214. for _, item := range items {
  215. rs = append(rs, toObjectACLRule(item))
  216. }
  217. return rs
  218. }
  219. func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule {
  220. var rs []ACLRule
  221. for _, item := range items {
  222. rs = append(rs, toBucketACLRule(item))
  223. }
  224. return rs
  225. }
  226. func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule {
  227. return ACLRule{
  228. Entity: ACLEntity(a.Entity),
  229. EntityID: a.EntityId,
  230. Role: ACLRole(a.Role),
  231. Domain: a.Domain,
  232. Email: a.Email,
  233. ProjectTeam: toObjectProjectTeam(a.ProjectTeam),
  234. }
  235. }
  236. func toBucketACLRule(a *raw.BucketAccessControl) ACLRule {
  237. return ACLRule{
  238. Entity: ACLEntity(a.Entity),
  239. EntityID: a.EntityId,
  240. Role: ACLRole(a.Role),
  241. Domain: a.Domain,
  242. Email: a.Email,
  243. ProjectTeam: toBucketProjectTeam(a.ProjectTeam),
  244. }
  245. }
  246. func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl {
  247. if len(rules) == 0 {
  248. return nil
  249. }
  250. r := make([]*raw.ObjectAccessControl, 0, len(rules))
  251. for _, rule := range rules {
  252. r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary
  253. }
  254. return r
  255. }
  256. func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl {
  257. if len(rules) == 0 {
  258. return nil
  259. }
  260. r := make([]*raw.BucketAccessControl, 0, len(rules))
  261. for _, rule := range rules {
  262. r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary
  263. }
  264. return r
  265. }
  266. func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl {
  267. return &raw.BucketAccessControl{
  268. Bucket: bucket,
  269. Entity: string(r.Entity),
  270. Role: string(r.Role),
  271. // The other fields are not settable.
  272. }
  273. }
  274. func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl {
  275. return &raw.ObjectAccessControl{
  276. Bucket: bucket,
  277. Entity: string(r.Entity),
  278. Role: string(r.Role),
  279. // The other fields are not settable.
  280. }
  281. }
  282. func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam {
  283. if p == nil {
  284. return nil
  285. }
  286. return &ProjectTeam{
  287. ProjectNumber: p.ProjectNumber,
  288. Team: p.Team,
  289. }
  290. }
  291. func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam {
  292. if p == nil {
  293. return nil
  294. }
  295. return &ProjectTeam{
  296. ProjectNumber: p.ProjectNumber,
  297. Team: p.Team,
  298. }
  299. }