Skip to content

Commit 34cb3b4

Browse files
authored
feat: add remove conditional iam binding (GoogleCloudPlatform#1045)
1 parent ca02763 commit 34cb3b4

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

storage/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"src/release_event_based_hold.php",
6262
"src/release_temporary_hold.php",
6363
"src/remove_bucket_iam_member.php",
64+
"src/remove_bucket_conditional_iam_binding.php",
6465
"src/remove_bucket_label.php",
6566
"src/remove_retention_policy.php",
6667
"src/rotate_encryption_key.php",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
/**
3+
* Copyright 2020 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* For instructions on how to run the full sample:
20+
*
21+
* @see https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/storage/README.md
22+
*/
23+
24+
namespace Google\Cloud\Samples\Storage;
25+
26+
# [START storage_remove_bucket_conditional_iam_binding]
27+
use Google\Cloud\Storage\StorageClient;
28+
29+
/**
30+
* Removes a conditional IAM binding from a bucket's IAM policy.
31+
*
32+
* @param string $bucketName the name of your Cloud Storage bucket.
33+
* @param string $role the role that will be given to members in this binding.
34+
* @param string $title condition's title
35+
* @param string $description condition's description
36+
* @param string $expression the condition specified in CEL expression language.
37+
*
38+
* To see how to express a condition in CEL, visit:
39+
* @see https://cloud.google.com/storage/docs/access-control/iam#conditions.
40+
*
41+
* @return void
42+
*/
43+
function remove_bucket_conditional_iam_binding($bucketName, $role, $members, $title, $description, $expression)
44+
{
45+
$storage = new StorageClient();
46+
$bucket = $storage->bucket($bucketName);
47+
48+
$policy = $bucket->iam()->policy(['requestedPolicyVersion' => 3]);
49+
50+
$policy['version'] = 3;
51+
52+
$key_of_conditional_binding = null;
53+
foreach ($policy['bindings'] as $key => $binding) {
54+
if ($binding['role'] == $role && $binding['condition'] != null) {
55+
$condition = $binding['condition'];
56+
if ($condition['title'] == $title
57+
&& $condition['description'] == description
58+
&& $condition['expression'] == expression) {
59+
$key_of_conditional_binding = $key;
60+
break;
61+
}
62+
}
63+
}
64+
65+
if ($key_of_conditional_binding != null) {
66+
unset($policy['bindings'][$key_of_conditional_binding]);
67+
$bucket->iam()->setPolicy($policy);
68+
print('Conditional Binding was removed.' . PHP_EOL);
69+
} else {
70+
print('No matching conditional binding found.' . PHP_EOL);
71+
}
72+
}
73+
# [END storage_remove_bucket_conditional_iam_binding]

storage/storage.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,15 @@
269269
270270
php %command.full_name% my-bucket --role my-role --remove-member user:[email protected]
271271
272+
php %command.full_name% my-bucket --role my-role --remove-binding --title cond-title --description cond-description --expression cond-expression
273+
272274
EOF
273275
)
274276
->addArgument('bucket', InputArgument::REQUIRED, 'The bucket that you want to change IAM for. ')
275277
->addOption('role', null, InputOption::VALUE_REQUIRED, 'The new role to add to a bucket. ')
276278
->addOption('add-member', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, "The new member(s) to add with the new role to the bucket. ")
277279
->addOption('remove-member', null, InputOption::VALUE_REQUIRED, 'The member to remove from a role for a bucket. ')
280+
->addOption('remove-binding', null, InputOption::VALUE_NONE, 'Remove conditional policy')
278281
->addOption('title', null, InputOption::VALUE_REQUIRED, 'Optional. A title for the condition, if --expression is used. ')
279282
->addOption('description', null, InputOption::VALUE_REQUIRED, 'Optional. A description for the condition, if --expression is used. ')
280283
->addOption('expression', null, InputOption::VALUE_REQUIRED, 'Add the role/members pair with an IAM condition expression. ')
@@ -283,6 +286,7 @@
283286
$role = $input->getOption('role');
284287
$members = $input->getOption('add-member');
285288
$removeMember = $input->getOption('remove-member');
289+
$removeBinding = $input->getOption('remove-binding');
286290
$expression = $input->getOption('expression');
287291
$title = $input->getOption('title');
288292
$description = $input->getOption('description');
@@ -301,6 +305,20 @@
301305
throw new InvalidArgumentException('Must provide role as an option.');
302306
}
303307
remove_bucket_iam_member($bucketName, $role, $removeMember);
308+
} elseif ($removeBinding) {
309+
if (!$role) {
310+
throw new InvalidArgumentException('Must provide role as an option.');
311+
}
312+
if (!$title) {
313+
throw new InvalidArgumentException('Must provide title as an option.');
314+
}
315+
if (!$description) {
316+
throw new InvalidArgumentException('Must provide description as an option.');
317+
}
318+
if (!$expression) {
319+
throw new InvalidArgumentException('Must provide expression as an option.');
320+
}
321+
remove_bucket_conditional_iam_binding($bucket_name, $role, $title, $description, $expression);
304322
} else {
305323
view_bucket_iam_members($bucketName);
306324
}

storage/test/IamCommandTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,45 @@ public function testRemoveBucketIamMember()
214214
}
215215
$this->assertFalse($foundRoleMember);
216216
}
217+
218+
/**
219+
* @depends testAddBucketConditionalIamBinding
220+
* @depends testListIamMembers
221+
*/
222+
public function testRemoveBucketConditionalIamBinding()
223+
{
224+
$role = 'roles/storage.objectViewer';
225+
$title = 'always true';
226+
$description = 'this condition is always true';
227+
$expression = '1 < 2';
228+
$output = $this->runCommand('iam', [
229+
'bucket' => self::$bucket,
230+
'--role' => 'roles/storage.objectViewer',
231+
'--remove-binding' => true,
232+
'--title' => $title,
233+
'--description' => $description,
234+
'--expression' => $expression
235+
]);
236+
237+
$outputString = sprintf('Conditional Binding was removed.');
238+
239+
$this->assertStringContainsString($outputString, $output);
240+
241+
$foundBinding = false;
242+
$policy = self::$storage->bucket(self::$bucket)->iam()->policy([
243+
'requestedPolicyVersion' => 3
244+
]);
245+
foreach ($policy['bindings'] as $binding) {
246+
if ($binding['role'] == $role && $binding['condition'] != null) {
247+
$condition = $binding['condition'];
248+
if ($condition['title'] == $title
249+
&& $condition['description'] == $description
250+
&& $condition['expression'] == $expression) {
251+
$foundRoleMember = true;
252+
break;
253+
}
254+
}
255+
}
256+
$this->assertFalse($foundBinding);
257+
}
217258
}

0 commit comments

Comments
 (0)