From 33aa2b972558993d4a0f9ad32faedb614a84cd5a Mon Sep 17 00:00:00 2001 From: Gus Class Date: Wed, 17 Jan 2018 16:14:44 -0800 Subject: [PATCH] Adds IAM get/set for binding members and roles --- .../iot/examples/DeviceRegistryExample.java | 130 +++++++++++++++++- .../DeviceRegistryExampleOptions.java | 26 +++- .../example/cloud/iot/examples/ManagerIT.java | 39 +++++- 3 files changed, 189 insertions(+), 6 deletions(-) diff --git a/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExample.java b/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExample.java index c7578aad795..fb8d6a4ad09 100644 --- a/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExample.java +++ b/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExample.java @@ -30,14 +30,15 @@ import com.google.api.services.cloudiot.v1.model.DeviceRegistry; import com.google.api.services.cloudiot.v1.model.DeviceState; import com.google.api.services.cloudiot.v1.model.EventNotificationConfig; +import com.google.api.services.cloudiot.v1.model.GetIamPolicyRequest; import com.google.api.services.cloudiot.v1.model.ListDeviceStatesResponse; import com.google.api.services.cloudiot.v1.model.ModifyCloudToDeviceConfigRequest; import com.google.api.services.cloudiot.v1.model.PublicKeyCredential; +import com.google.api.services.cloudiot.v1.model.SetIamPolicyRequest; import com.google.cloud.Role; import com.google.cloud.pubsub.v1.TopicAdminClient; import com.google.common.io.Files; import com.google.iam.v1.Binding; -import com.google.iam.v1.Policy; import com.google.pubsub.v1.Topic; import com.google.pubsub.v1.TopicName; @@ -48,7 +49,6 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; -import javax.xml.bind.DatatypeConverter; import org.apache.commons.cli.HelpFormatter; /** @@ -93,7 +93,7 @@ public static Topic createIotTopic(String projectId, String topicId) throws Exce try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) { final Topic topic = topicAdminClient.createTopic(topicName); - Policy policy = topicAdminClient.getIamPolicy(topicName.toString()); + com.google.iam.v1.Policy policy = topicAdminClient.getIamPolicy(topicName.toString()); // add role -> members binding Binding binding = Binding.newBuilder() @@ -101,7 +101,8 @@ public static Topic createIotTopic(String projectId, String topicId) throws Exce .setRole(Role.owner().toString()) .build(); // create updated policy - Policy updatedPolicy = Policy.newBuilder(policy).addBindings(binding).build(); + com.google.iam.v1.Policy updatedPolicy = + com.google.iam.v1.Policy.newBuilder(policy).addBindings(binding).build(); topicAdminClient.setIamPolicy(topicName.toString(), updatedPolicy); System.out.println("Setup topic / policy for: " + topic.getName()); @@ -578,6 +579,114 @@ public static void setDeviceConfiguration( System.out.println("Updated: " + config.getVersion()); } + /** Retrieves IAM permissions for the given registry. */ + public static void getIamPermissions( + String projectId, String cloudRegion, String registryName) + throws GeneralSecurityException, IOException { + GoogleCredential credential = + GoogleCredential.getApplicationDefault().createScoped(CloudIotScopes.all()); + JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); + HttpRequestInitializer init = new RetryHttpInitializerWrapper(credential); + final CloudIot service = new CloudIot.Builder( + GoogleNetHttpTransport.newTrustedTransport(),jsonFactory, init) + .setApplicationName(APP_NAME).build(); + + final String registryPath = String.format("projects/%s/locations/%s/registries/%s", + projectId, cloudRegion, registryName); + + com.google.api.services.cloudiot.v1.model.Policy policy = + service + .projects() + .locations() + .registries() + .getIamPolicy(registryPath, new GetIamPolicyRequest()).execute(); + + System.out.println("Policy ETAG: " + policy.getEtag()); + + if (policy.getBindings() != null) { + for (com.google.api.services.cloudiot.v1.model.Binding binding : policy.getBindings()) { + System.out.println(String.format("Role: %s", binding.getRole())); + System.out.println("Binding members: "); + for (String member : binding.getMembers()) { + System.out.println(String.format("\t%s", member)); + } + } + } else { + System.out.println(String.format("No policy bindings for %s", registryName)); + } + } + + /** Sets IAM permissions for the given registry. */ + public static void setIamPermissions( + String projectId, String cloudRegion, String registryName, + String member, String role) + throws GeneralSecurityException, IOException { + GoogleCredential credential = + GoogleCredential.getApplicationDefault().createScoped(CloudIotScopes.all()); + JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); + HttpRequestInitializer init = new RetryHttpInitializerWrapper(credential); + final CloudIot service = new CloudIot.Builder( + GoogleNetHttpTransport.newTrustedTransport(),jsonFactory, init) + .setApplicationName(APP_NAME).build(); + + final String registryPath = String.format("projects/%s/locations/%s/registries/%s", + projectId, cloudRegion, registryName); + + com.google.api.services.cloudiot.v1.model.Policy policy = + service + .projects() + .locations() + .registries() + .getIamPolicy(registryPath, new GetIamPolicyRequest()).execute(); + + List bindings = + policy.getBindings(); + + boolean addNewRole = true; + if (bindings != null) { + for (com.google.api.services.cloudiot.v1.model.Binding binding : bindings) { + if (binding.getRole().equals(role)) { + List members = binding.getMembers(); + members.add(member); + binding.setMembers(members); + addNewRole = false; + } + } + } else { + bindings = new ArrayList<>(); + } + + if (addNewRole) { + com.google.api.services.cloudiot.v1.model.Binding bind = + new com.google.api.services.cloudiot.v1.model.Binding(); + bind.setRole(role); + List members = new ArrayList<>(); + members.add(member); + bind.setMembers(members); + + bindings.add(bind); + } + + policy.setBindings(bindings); + SetIamPolicyRequest req = new SetIamPolicyRequest().setPolicy(policy); + + policy = + service + .projects() + .locations() + .registries() + .setIamPolicy(registryPath, req).execute(); + + System.out.println("Policy ETAG: " + policy.getEtag()); + for (com.google.api.services.cloudiot.v1.model.Binding binding: policy.getBindings()) { + System.out.println(String.format("Role: %s", binding.getRole())); + System.out.println("Binding members: "); + for (String mem : binding.getMembers()) { + System.out.println(String.format("\t%s", mem)); + } + } + } + /** Entry poit for CLI. */ public static void main(String[] args) throws Exception { DeviceRegistryExampleOptions options = DeviceRegistryExampleOptions.fromFlags(args); @@ -626,6 +735,10 @@ public static void main(String[] args) throws Exception { options.registryName) .toPrettyString()); break; + case "get-iam-permissions": + System.out.println("Get iam permissions"); + getIamPermissions(options.projectId, options.cloudRegion, options.registryName); + break; case "get-device-state": System.out.println("Get device state"); List states = getDeviceStates(options.deviceId, options.projectId, @@ -666,6 +779,15 @@ public static void main(String[] args) throws Exception { options.registryName, options.configuration, options.version); } break; + case "set-iam-permissions": + if (options.member == null || options.role == null) { + System.out.println("Specify member and role for the policy you are updating."); + } else { + System.out.println("Setting iam permissions"); + setIamPermissions(options.projectId, options.cloudRegion, options.registryName, + options.member, options.role); + } + break; default: String header = "Cloud IoT Core Commandline Example (Device / Registry management): \n\n"; String footer = "\nhttps://cloud.google.com/iot-core"; diff --git a/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExampleOptions.java b/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExampleOptions.java index 2e22904afb6..94b80153fd4 100644 --- a/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExampleOptions.java +++ b/iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExampleOptions.java @@ -35,6 +35,8 @@ public class DeviceRegistryExampleOptions { String deviceId; // Default to UUID? String pubsubTopic; String registryName; + String member; + String role; long version = 0; static final Options options = new Options(); @@ -65,12 +67,14 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) { + "\n\tdelete-registry" + "\n\tget-device" + "\n\tget-device-state" + + "\n\tget-iam-permissions" + "\n\tget-registry" + "\n\tlist-devices" + "\n\tlist-registries" + "\n\tpatch-device-es" + "\n\tpatch-device-rsa" - + "\n\tset-config") + + "\n\tset-config" + + "\n\tset-iam-permissions") .required() .build()); @@ -131,6 +135,20 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) { .hasArg() .desc("The configuration version to send on the device (0 is latest).") .build()); + options.addOption( + Option.builder() + .type(String.class) + .longOpt("member") + .hasArg() + .desc("The member used for setting IAM permissions.") + .build()); + options.addOption( + Option.builder() + .type(String.class) + .longOpt("role") + .hasArg() + .desc("The role (e.g. 'roles/viewer') used when setting IAM permissions.") + .build()); CommandLineParser parser = new DefaultParser(); CommandLine commandLine; @@ -181,6 +199,12 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) { if (commandLine.hasOption("version")) { res.version = new Long(commandLine.getOptionValue("version")).longValue(); } + if (commandLine.hasOption("member")) { + res.member = commandLine.getOptionValue("member"); + } + if (commandLine.hasOption("role")) { + res.role = commandLine.getOptionValue("role"); + } return res; } catch (ParseException e) { diff --git a/iot/api-client/manager/src/test/java/com/example/cloud/iot/examples/ManagerIT.java b/iot/api-client/manager/src/test/java/com/example/cloud/iot/examples/ManagerIT.java index a96fda923c0..281d199442f 100644 --- a/iot/api-client/manager/src/test/java/com/example/cloud/iot/examples/ManagerIT.java +++ b/iot/api-client/manager/src/test/java/com/example/cloud/iot/examples/ManagerIT.java @@ -45,6 +45,9 @@ public class ManagerIT { private static final String RSA_PATH = "resources/rsa_cert.pem"; private static final String PKCS_PATH = "resources/rsa_private_pkcs8"; private static final String TOPIC_ID = "java-pst-" + (System.currentTimeMillis() / 1000L); + private static final String MEMBER = "group:dpebot@google.com"; + private static final String ROLE = "roles/viewer"; + private static Topic topic; @@ -242,7 +245,6 @@ public void testCreateListDevices() throws Exception { @Test public void testCreateGetRegistry() throws Exception { - topic = DeviceRegistryExample.createIotTopic( PROJECT_ID, TOPIC_ID); @@ -258,6 +260,41 @@ public void testCreateGetRegistry() throws Exception { } } + @Test + public void testGetIam() throws Exception { + topic = DeviceRegistryExample.createIotTopic( + PROJECT_ID, + TOPIC_ID); + DeviceRegistryExample.createRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID, TOPIC_ID); + DeviceRegistryExample.getIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID); + + String got = bout.toString(); + Assert.assertTrue(got.contains("ETAG")); + + DeviceRegistryExample.deleteRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID); + try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) { + topicAdminClient.deleteTopic(topic.getNameAsTopicName()); + } + } + + @Test + public void testSetIam() throws Exception { + topic = DeviceRegistryExample.createIotTopic( + PROJECT_ID, + TOPIC_ID); + DeviceRegistryExample.createRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID, TOPIC_ID); + DeviceRegistryExample.setIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID, MEMBER, ROLE); + DeviceRegistryExample.getIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID); + + String got = bout.toString(); + Assert.assertTrue(got.contains("ETAG")); + + DeviceRegistryExample.deleteRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID); + try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) { + topicAdminClient.deleteTopic(topic.getNameAsTopicName()); + } + } + // HTTP device tests @Test