-
Notifications
You must be signed in to change notification settings - Fork 439
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support iam conditions (#2416)
* support IAM condition * update Storage JSON definition, rev,. 20190913 * throw InvalidOperationException if version is greater than 1 * nit: doc * do not cache Iam instance on bucket; make $version arg a key in $options array * revert version argument from IAM constructor * docs: document optionsRequestedPolicyVersion * revert stored $iam instance on bucket * docs: add example of a policy in PolicyBuilder * more docs * fix link * map requestedPolicyVersion arg to optionsRequestedPolicyVersion in Storage req opts * fix(docs): optionsRequestedPolicyVersion => requestedPolicyVersion * fix * test: validate policy version and conditions * test: assert requestedPolicyVersion arg is mapped to optionsRequestedPolicyVersion * merge Storage definition from master * fix: lint * lint * fix * docs: update inline sample to use prefix condition * add IAM get/set system tests * add conditional policy system test * fix docs Co-Authored-By: David Supplee <[email protected]> * fix @see markdown links * fix ; * add @deprecated tag * use BadMethodCallException * fix style * fix style * add snippet coverage * update bucket->iam snippet tests * fix snippet parsing issue * Update Storage/tests/System/IamTest.php Co-Authored-By: David Supplee <[email protected]> * Update Core/src/Iam/PolicyBuilder.php Co-Authored-By: David Supplee <[email protected]> Co-authored-by: David Supplee <[email protected]>
- Loading branch information
Showing
9 changed files
with
338 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
namespace Google\Cloud\Core\Iam; | ||
|
||
use InvalidArgumentException; | ||
use BadMethodCallException; | ||
|
||
/** | ||
* Helper class for creating valid IAM policies | ||
|
@@ -51,6 +52,38 @@ class PolicyBuilder | |
/** | ||
* Create a PolicyBuilder. | ||
* | ||
* To use conditions in the bindings, the version of the policy must be set | ||
* to 3. | ||
* | ||
* @see https://cloud.google.com/iam/docs/policies#versions Policy versioning | ||
* @see https://cloud-dot-devsite.googleplex.com/storage/docs/access-control/using-iam-permissions#conditions-iam | ||
* Using Cloud IAM Conditions on buckets | ||
* | ||
* Example: | ||
* ``` | ||
* $policy = [ | ||
* 'etag' => 'AgIc==', | ||
* 'version' => 3, | ||
* 'bindings' => [ | ||
* [ | ||
* 'role' => 'roles/admin', | ||
* 'members' => [ | ||
* 'user:[email protected]', | ||
* 'user2:[email protected]' | ||
* ], | ||
* 'condition' => [ | ||
* 'title' => 'match-prefix', | ||
* 'description' => 'Applies to objects matching a prefix', | ||
* 'expression' => | ||
* 'resource.name.startsWith("projects/_/buckets/bucket-name/objects/prefix-a-")' | ||
* ] | ||
* ] | ||
* ], | ||
* ]; | ||
* | ||
* $builder = new PolicyBuilder($policy); | ||
* ``` | ||
* | ||
* @param array $policy A policy array | ||
* @throws InvalidArgumentException | ||
*/ | ||
|
@@ -81,6 +114,10 @@ public function __construct(array $policy = []) | |
* 'role' => 'roles/admin', | ||
* 'members' => [ | ||
* 'user:[email protected]' | ||
* ], | ||
* 'condition' => [ | ||
* 'expression' => | ||
* 'request.time < timestamp("2020-07-01T00:00:00.000Z")' | ||
* ] | ||
* ] | ||
* ]); | ||
|
@@ -92,17 +129,20 @@ public function __construct(array $policy = []) | |
*/ | ||
public function setBindings(array $bindings = []) | ||
{ | ||
$this->bindings = []; | ||
foreach ($bindings as $binding) { | ||
$this->addBinding($binding['role'], $binding['members']); | ||
} | ||
|
||
$this->bindings = $bindings; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Add a new binding to the policy. | ||
* | ||
* This method will fail with an InvalidOpereationException if it is | ||
* called on a Policy with a version greater than 1 as that indicates | ||
* a more complicated policy than this method is prepared to handle. | ||
* Changes to such policies must be made manually by the setBindings() | ||
* method. | ||
* | ||
* | ||
* Example: | ||
* ``` | ||
* $builder->addBinding('roles/admin', [ 'user:[email protected]' ]); | ||
|
@@ -112,9 +152,13 @@ public function setBindings(array $bindings = []) | |
* @param array $members An array of members to assign to the binding | ||
* @return PolicyBuilder | ||
* @throws InvalidArgumentException | ||
* @throws BadMethodCallException if the policy's version is greater than 1. | ||
* @deprecated | ||
*/ | ||
public function addBinding($role, array $members) | ||
{ | ||
$this->validatePolicyVersion(); | ||
|
||
$this->bindings[] = [ | ||
'role' => $role, | ||
'members' => $members | ||
|
@@ -126,6 +170,12 @@ public function addBinding($role, array $members) | |
/** | ||
* Remove a binding from the policy. | ||
* | ||
* This method will fail with a BadMethodCallException if it is | ||
* called on a Policy with a version greater than 1 as that indicates | ||
* a more complicated policy than this method is prepared to handle. | ||
* Changes to such policies must be made manually by the setBindings() | ||
* method. | ||
* | ||
* Example: | ||
* ``` | ||
* $builder->setBindings([ | ||
|
@@ -144,9 +194,13 @@ public function addBinding($role, array $members) | |
* @param array $members An array of members to remove from the role | ||
* @return PolicyBuilder | ||
* @throws InvalidArgumentException | ||
* @throws BadMethodCallException if the policy's version is greater than 1. | ||
* @deprecated | ||
*/ | ||
public function removeBinding($role, array $members) | ||
{ | ||
$this->validatePolicyVersion(); | ||
|
||
$bindings = $this->bindings; | ||
foreach ((array) $bindings as $i => $binding) { | ||
if ($binding['role'] == $role) { | ||
|
@@ -226,4 +280,28 @@ public function result() | |
'version' => $this->version | ||
]); | ||
} | ||
|
||
private function validatePolicyVersion() | ||
{ | ||
if (isset($this->version) && $this->version > 1) { | ||
throw new BadMethodCallException("Helper methods cannot be " . | ||
"invoked on policies with version {$this->version}."); | ||
} | ||
|
||
$this->validateConditions(); | ||
} | ||
|
||
private function validateConditions() | ||
{ | ||
if (!$this->bindings) { | ||
return; | ||
} | ||
|
||
foreach ($this->bindings as $binding) { | ||
if (isset($binding['condition'])) { | ||
throw new BadMethodCallException("Helper methods cannot " . | ||
"be invoked on policies containing conditions."); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ public function testBuilder() | |
|
||
$builder = new PolicyBuilder; | ||
$builder->setEtag($etag); | ||
$builder->setVersion(2); | ||
$builder->setVersion(1); | ||
$builder->addBinding($role, $members); | ||
|
||
$result = $builder->result(); | ||
|
@@ -55,7 +55,7 @@ public function testBuilder() | |
] | ||
], | ||
'etag' => $etag, | ||
'version' => 2 | ||
'version' => 1 | ||
]; | ||
|
||
$this->assertEquals($policy, $result); | ||
|
@@ -139,6 +139,43 @@ public function testConstructWithExistingPolicy() | |
$this->assertEquals($policy, $result); | ||
} | ||
|
||
/** | ||
* @expectedException BadMethodCallException | ||
* @expectedExceptionMessage Helper methods cannot be invoked on policies with version 3. | ||
*/ | ||
public function testAddBindingVersionThrowsException() | ||
{ | ||
$builder = new PolicyBuilder(); | ||
$builder->setVersion(3); | ||
|
||
$builder->addBinding('test', ['user:[email protected]']); | ||
} | ||
|
||
/** | ||
* @expectedException BadMethodCallException | ||
* @expectedExceptionMessage Helper methods cannot be invoked on policies containing conditions. | ||
*/ | ||
public function testAddBindingWithConditionsThrowsException() | ||
{ | ||
$policy = [ | ||
'bindings' => [ | ||
[ | ||
'role' => 'test', | ||
'members' => [ | ||
'user:[email protected]', | ||
], | ||
'condition' => [ | ||
'expression' => 'true', | ||
] | ||
], | ||
], | ||
]; | ||
$builder = new PolicyBuilder($policy); | ||
$builder->setVersion(1); | ||
|
||
$builder->addBinding('test2', ['user:[email protected]']); | ||
} | ||
|
||
public function testRemoveBinding() | ||
{ | ||
$policy = [ | ||
|
@@ -225,4 +262,51 @@ public function testRemoveBindingInvalidRoleThrowsException() | |
$builder = new PolicyBuilder($policy); | ||
$builder->removeBinding('test2', ['user:[email protected]']); | ||
} | ||
|
||
/** | ||
* @expectedException BadMethodCallException | ||
* @expectedExceptionMessage Helper methods cannot be invoked on policies with version 3. | ||
*/ | ||
public function testRemoveBindingVersionThrowsException() | ||
{ | ||
$policy = [ | ||
'version' => 3, | ||
'bindings' => [ | ||
[ | ||
'role' => 'test', | ||
'members' => [ | ||
'user:[email protected]', | ||
] | ||
], | ||
] | ||
]; | ||
|
||
$builder = new PolicyBuilder($policy); | ||
$builder->removeBinding('test', ['user:[email protected]']); | ||
} | ||
|
||
/** | ||
* @expectedException BadMethodCallException | ||
* @expectedExceptionMessage Helper methods cannot be invoked on policies containing conditions. | ||
*/ | ||
public function testRemoveBindingWithConditionsThrowsException() | ||
{ | ||
$policy = [ | ||
'bindings' => [ | ||
[ | ||
'role' => 'test', | ||
'members' => [ | ||
'user:[email protected]', | ||
], | ||
'condition' => [ | ||
'expression' => 'true', | ||
] | ||
], | ||
], | ||
]; | ||
|
||
$builder = new PolicyBuilder($policy); | ||
$builder->setVersion(1); | ||
$builder->removeBinding('test', ['user:[email protected]']); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.