1// Copyright 2017 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
15package storage
16
17import (
18	"context"
19
20	"cloud.google.com/go/iam"
21	"cloud.google.com/go/internal/trace"
22	raw "google.golang.org/api/storage/v1"
23	iampb "google.golang.org/genproto/googleapis/iam/v1"
24)
25
26// IAM provides access to IAM access control for the bucket.
27func (b *BucketHandle) IAM() *iam.Handle {
28	return iam.InternalNewHandleClient(&iamClient{
29		raw:         b.c.raw,
30		userProject: b.userProject,
31	}, b.name)
32}
33
34// iamClient implements the iam.client interface.
35type iamClient struct {
36	raw         *raw.Service
37	userProject string
38}
39
40func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) {
41	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get")
42	defer func() { trace.EndSpan(ctx, err) }()
43
44	call := c.raw.Buckets.GetIamPolicy(resource)
45	setClientHeader(call.Header())
46	if c.userProject != "" {
47		call.UserProject(c.userProject)
48	}
49	var rp *raw.Policy
50	err = runWithRetry(ctx, func() error {
51		rp, err = call.Context(ctx).Do()
52		return err
53	})
54	if err != nil {
55		return nil, err
56	}
57	return iamFromStoragePolicy(rp), nil
58}
59
60func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) {
61	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Set")
62	defer func() { trace.EndSpan(ctx, err) }()
63
64	rp := iamToStoragePolicy(p)
65	call := c.raw.Buckets.SetIamPolicy(resource, rp)
66	setClientHeader(call.Header())
67	if c.userProject != "" {
68		call.UserProject(c.userProject)
69	}
70	return runWithRetry(ctx, func() error {
71		_, err := call.Context(ctx).Do()
72		return err
73	})
74}
75
76func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) {
77	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test")
78	defer func() { trace.EndSpan(ctx, err) }()
79
80	call := c.raw.Buckets.TestIamPermissions(resource, perms)
81	setClientHeader(call.Header())
82	if c.userProject != "" {
83		call.UserProject(c.userProject)
84	}
85	var res *raw.TestIamPermissionsResponse
86	err = runWithRetry(ctx, func() error {
87		res, err = call.Context(ctx).Do()
88		return err
89	})
90	if err != nil {
91		return nil, err
92	}
93	return res.Permissions, nil
94}
95
96func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy {
97	return &raw.Policy{
98		Bindings: iamToStorageBindings(ip.Bindings),
99		Etag:     string(ip.Etag),
100	}
101}
102
103func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings {
104	var rbs []*raw.PolicyBindings
105	for _, ib := range ibs {
106		rbs = append(rbs, &raw.PolicyBindings{
107			Role:    ib.Role,
108			Members: ib.Members,
109		})
110	}
111	return rbs
112}
113
114func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy {
115	return &iampb.Policy{
116		Bindings: iamFromStorageBindings(rp.Bindings),
117		Etag:     []byte(rp.Etag),
118	}
119}
120
121func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding {
122	var ibs []*iampb.Binding
123	for _, rb := range rbs {
124		ibs = append(ibs, &iampb.Binding{
125			Role:    rb.Role,
126			Members: rb.Members,
127		})
128	}
129	return ibs
130}
131