From 317a172b77bb76e053d2a5b9050c21d3c9526158 Mon Sep 17 00:00:00 2001 From: Ajit Thakor <49403056+athakor@users.noreply.github.com> Date: Tue, 7 Apr 2020 17:57:08 +0530 Subject: [PATCH] feat: implement testPermission api of organizations (#125) * feat: implement testPermission api of organization * feat: modified java doc * feat: modified java doc * feat: fix review changes * feat: fix javadoc --- clirr-ignored-differences.xml | 14 +++++ pom.xml | 7 +++ .../resourcemanager/ResourceManager.java | 17 ++++++ .../ResourceManagerException.java | 2 +- .../resourcemanager/ResourceManagerImpl.java | 20 ++++++ .../spi/v1beta1/HttpResourceManagerRpc.java | 23 +++++++ .../spi/v1beta1/ResourceManagerRpc.java | 10 ++- .../ResourceManagerImplTest.java | 61 +++++++++++++++++++ 8 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 clirr-ignored-differences.xml diff --git a/clirr-ignored-differences.xml b/clirr-ignored-differences.xml new file mode 100644 index 00000000..da1f3c38 --- /dev/null +++ b/clirr-ignored-differences.xml @@ -0,0 +1,14 @@ + + + + + com/google/cloud/resourcemanager/ResourceManager + java.util.Map testOrgPermissions(java.lang.String, java.util.List) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + java.util.Map testOrgPermissions(java.lang.String, java.util.List) + 7012 + + diff --git a/pom.xml b/pom.xml index ba556b4b..7fa039a7 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,7 @@ 1.93.3 1.30.9 3.6 + 1.10.19 2.6 0.20.0 1.34.2 @@ -205,6 +206,12 @@ + + org.mockito + mockito-all + ${mockito.version} + test + org.objenesis objenesis diff --git a/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java b/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java index 9da15800..b2a46edf 100644 --- a/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java +++ b/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java @@ -24,6 +24,7 @@ import com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc; import com.google.common.collect.ImmutableList; import java.util.List; +import java.util.Map; /** * An interface for Google Cloud Resource Manager. @@ -337,4 +338,20 @@ public static ProjectListOption fields(ProjectField... fields) { * Platform Services */ List testPermissions(String projectId, List permissions); + + /** + * Returns the permissions and their results representing whether the caller has the permissions + * on the specified Organization. + * + * @param resource the organization's resource name, e.g. "organizations/123" + * @param permissions the set of permissions to check for the resource. Permissions with wildcards + * (such as '*' or 'storage.*') are not allowed. + * @return the permissions and their results representing whether the caller has the permissions + * on the specified Organization. + * @throws ResourceManagerException upon failure + * @see + * Resource Manager testIamPermissions + */ + Map testOrgPermissions(String resource, List permissions); } diff --git a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerException.java b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerException.java index e8c7f8d0..cc820ee0 100644 --- a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerException.java +++ b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerException.java @@ -66,7 +66,7 @@ public ResourceManagerException(IOException exception) { * @throws ResourceManagerException when {@code ex} was caused by a {@code * ResourceManagerException} */ - static ResourceManagerException translateAndThrow(RetryHelperException ex) { + public static ResourceManagerException translateAndThrow(RetryHelperException ex) { BaseServiceException.translate(ex); throw new ResourceManagerException(UNKNOWN_CODE, ex.getMessage(), ex.getCause()); } diff --git a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java index 7651e645..557567d9 100644 --- a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java +++ b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java @@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -273,6 +274,25 @@ public List call() { } } + @Override + public Map testOrgPermissions( + final String resource, final List permissions) { + try { + return runWithRetries( + new Callable>() { + @Override + public Map call() throws IOException { + return resourceManagerRpc.testOrgPermissions(resource, permissions); + } + }, + getOptions().getRetrySettings(), + EXCEPTION_HANDLER, + getOptions().getClock()); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + private Map optionMap(Option... options) { Map temp = Maps.newEnumMap(ResourceManagerRpc.Option.class); for (Option option : options) { diff --git a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java index c5b1150c..12e53a91 100644 --- a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java +++ b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java @@ -40,6 +40,7 @@ import com.google.api.services.cloudresourcemanager.model.TestIamPermissionsRequest; import com.google.api.services.cloudresourcemanager.model.TestIamPermissionsResponse; import com.google.api.services.cloudresourcemanager.model.UndeleteProjectRequest; +import com.google.cloud.RetryHelper; import com.google.cloud.Tuple; import com.google.cloud.http.BaseHttpServiceException; import com.google.cloud.http.HttpTransportOptions; @@ -301,4 +302,26 @@ projectId, new TestIamPermissionsRequest().setPermissions(permissions)) throw translate(ex); } } + + @Override + public Map testOrgPermissions(String resource, List permissions) + throws IOException { + try { + TestIamPermissionsResponse response = + resourceManager + .organizations() + .testIamPermissions( + resource, new TestIamPermissionsRequest().setPermissions(permissions)) + .execute(); + Set permissionsOwned = + ImmutableSet.copyOf(firstNonNull(response.getPermissions(), ImmutableList.of())); + ImmutableMap.Builder answer = ImmutableMap.builder(); + for (String permission : permissions) { + answer.put(permission, permissionsOwned.contains(permission)); + } + return answer.build(); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } } diff --git a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java index 937e1a6e..dc45f31d 100644 --- a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java +++ b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java @@ -21,6 +21,7 @@ import com.google.cloud.ServiceRpc; import com.google.cloud.Tuple; import com.google.cloud.resourcemanager.ResourceManagerException; +import java.io.IOException; import java.util.List; import java.util.Map; @@ -124,5 +125,12 @@ Integer getInt(Map options) { */ List testPermissions(String projectId, List permissions); - // TODO(ajaykannan): implement "Organization" functionality when available (issue #319) + /** + * Tests whether the caller has the given permissions on the specified Organization. Returns the + * permissions and their results. + * + * @throws ResourceManagerException upon failure + */ + Map testOrgPermissions(String resource, List permissions) + throws IOException; } diff --git a/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java b/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java index 9d4ae0ff..1fdb954f 100644 --- a/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java +++ b/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java @@ -24,6 +24,9 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import com.google.api.gax.paging.Page; import com.google.cloud.Identity; @@ -38,6 +41,7 @@ import com.google.cloud.resourcemanager.testing.LocalResourceManagerHelper; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -46,7 +50,11 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +@RunWith(MockitoJUnitRunner.class) public class ResourceManagerImplTest { private static final LocalResourceManagerHelper RESOURCE_MANAGER_HELPER = @@ -75,6 +83,9 @@ public class ResourceManagerImplTest { .addIdentity(Role.editor(), Identity.serviceAccount("serviceaccount@gmail.com")) .build(); + private ResourceManagerRpcFactory rpcFactoryMock = Mockito.mock(ResourceManagerRpcFactory.class); + private ResourceManagerRpc resourceManagerRpcMock = Mockito.mock(ResourceManagerRpc.class); + @BeforeClass public static void beforeClass() { RESOURCE_MANAGER_HELPER.start(); @@ -456,4 +467,54 @@ public void testRuntimeException() { assertEquals(exceptionMessage, exception.getCause().getMessage()); } } + + @Test + public void testTestOrgPermissions() throws IOException { + String organization = "organization/12345"; + List permissions = + ImmutableList.of( + "resourcemanager.organizations.get", "resourcemanager.organizations.getIamPolicy"); + Map expected = + ImmutableMap.of( + "resourcemanager.organizations.get", + true, + "resourcemanager.organizations.getIamPolicy", + false); + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + when(resourceManagerRpcMock.testOrgPermissions(organization, permissions)).thenReturn(expected); + Map actual = resourceManager.testOrgPermissions(organization, permissions); + assertEquals(expected, actual); + verify(resourceManagerRpcMock).testOrgPermissions(organization, permissions); + } + + @Test + public void testTestOrgPermissionsWithResourceManagerException() throws IOException { + String organization = "organizations/12345"; + String exceptionMessage = "Not Found"; + List permissions = + ImmutableList.of( + "resourcemanager.organizations.get", "resourcemanager.organizations.getIamPolicy"); + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .testOrgPermissions(organization, permissions); + try { + resourceManager.testOrgPermissions(organization, permissions); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } }