Skip to content

Commit 76bcb8b

Browse files
authored
Adds IAM get/set for binding members and roles (#996)
1 parent 9d4d636 commit 76bcb8b

File tree

3 files changed

+189
-6
lines changed

3 files changed

+189
-6
lines changed

iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExample.java

+126-4
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030
import com.google.api.services.cloudiot.v1.model.DeviceRegistry;
3131
import com.google.api.services.cloudiot.v1.model.DeviceState;
3232
import com.google.api.services.cloudiot.v1.model.EventNotificationConfig;
33+
import com.google.api.services.cloudiot.v1.model.GetIamPolicyRequest;
3334
import com.google.api.services.cloudiot.v1.model.ListDeviceStatesResponse;
3435
import com.google.api.services.cloudiot.v1.model.ModifyCloudToDeviceConfigRequest;
3536
import com.google.api.services.cloudiot.v1.model.PublicKeyCredential;
37+
import com.google.api.services.cloudiot.v1.model.SetIamPolicyRequest;
3638
import com.google.cloud.Role;
3739
import com.google.cloud.pubsub.v1.TopicAdminClient;
3840
import com.google.common.io.Files;
3941
import com.google.iam.v1.Binding;
40-
import com.google.iam.v1.Policy;
4142
import com.google.pubsub.v1.Topic;
4243
import com.google.pubsub.v1.TopicName;
4344

@@ -48,7 +49,6 @@
4849
import java.util.Arrays;
4950
import java.util.Base64;
5051
import java.util.List;
51-
import javax.xml.bind.DatatypeConverter;
5252
import org.apache.commons.cli.HelpFormatter;
5353

5454
/**
@@ -93,15 +93,16 @@ public static Topic createIotTopic(String projectId, String topicId) throws Exce
9393

9494
try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) {
9595
final Topic topic = topicAdminClient.createTopic(topicName);
96-
Policy policy = topicAdminClient.getIamPolicy(topicName.toString());
96+
com.google.iam.v1.Policy policy = topicAdminClient.getIamPolicy(topicName.toString());
9797
// add role -> members binding
9898
Binding binding =
9999
Binding.newBuilder()
100100
.addMembers("serviceAccount:[email protected]")
101101
.setRole(Role.owner().toString())
102102
.build();
103103
// create updated policy
104-
Policy updatedPolicy = Policy.newBuilder(policy).addBindings(binding).build();
104+
com.google.iam.v1.Policy updatedPolicy =
105+
com.google.iam.v1.Policy.newBuilder(policy).addBindings(binding).build();
105106
topicAdminClient.setIamPolicy(topicName.toString(), updatedPolicy);
106107

107108
System.out.println("Setup topic / policy for: " + topic.getName());
@@ -578,6 +579,114 @@ public static void setDeviceConfiguration(
578579
System.out.println("Updated: " + config.getVersion());
579580
}
580581

582+
/** Retrieves IAM permissions for the given registry. */
583+
public static void getIamPermissions(
584+
String projectId, String cloudRegion, String registryName)
585+
throws GeneralSecurityException, IOException {
586+
GoogleCredential credential =
587+
GoogleCredential.getApplicationDefault().createScoped(CloudIotScopes.all());
588+
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
589+
HttpRequestInitializer init = new RetryHttpInitializerWrapper(credential);
590+
final CloudIot service = new CloudIot.Builder(
591+
GoogleNetHttpTransport.newTrustedTransport(),jsonFactory, init)
592+
.setApplicationName(APP_NAME).build();
593+
594+
final String registryPath = String.format("projects/%s/locations/%s/registries/%s",
595+
projectId, cloudRegion, registryName);
596+
597+
com.google.api.services.cloudiot.v1.model.Policy policy =
598+
service
599+
.projects()
600+
.locations()
601+
.registries()
602+
.getIamPolicy(registryPath, new GetIamPolicyRequest()).execute();
603+
604+
System.out.println("Policy ETAG: " + policy.getEtag());
605+
606+
if (policy.getBindings() != null) {
607+
for (com.google.api.services.cloudiot.v1.model.Binding binding : policy.getBindings()) {
608+
System.out.println(String.format("Role: %s", binding.getRole()));
609+
System.out.println("Binding members: ");
610+
for (String member : binding.getMembers()) {
611+
System.out.println(String.format("\t%s", member));
612+
}
613+
}
614+
} else {
615+
System.out.println(String.format("No policy bindings for %s", registryName));
616+
}
617+
}
618+
619+
/** Sets IAM permissions for the given registry. */
620+
public static void setIamPermissions(
621+
String projectId, String cloudRegion, String registryName,
622+
String member, String role)
623+
throws GeneralSecurityException, IOException {
624+
GoogleCredential credential =
625+
GoogleCredential.getApplicationDefault().createScoped(CloudIotScopes.all());
626+
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
627+
HttpRequestInitializer init = new RetryHttpInitializerWrapper(credential);
628+
final CloudIot service = new CloudIot.Builder(
629+
GoogleNetHttpTransport.newTrustedTransport(),jsonFactory, init)
630+
.setApplicationName(APP_NAME).build();
631+
632+
final String registryPath = String.format("projects/%s/locations/%s/registries/%s",
633+
projectId, cloudRegion, registryName);
634+
635+
com.google.api.services.cloudiot.v1.model.Policy policy =
636+
service
637+
.projects()
638+
.locations()
639+
.registries()
640+
.getIamPolicy(registryPath, new GetIamPolicyRequest()).execute();
641+
642+
List<com.google.api.services.cloudiot.v1.model.Binding> bindings =
643+
policy.getBindings();
644+
645+
boolean addNewRole = true;
646+
if (bindings != null) {
647+
for (com.google.api.services.cloudiot.v1.model.Binding binding : bindings) {
648+
if (binding.getRole().equals(role)) {
649+
List<String> members = binding.getMembers();
650+
members.add(member);
651+
binding.setMembers(members);
652+
addNewRole = false;
653+
}
654+
}
655+
} else {
656+
bindings = new ArrayList<>();
657+
}
658+
659+
if (addNewRole) {
660+
com.google.api.services.cloudiot.v1.model.Binding bind =
661+
new com.google.api.services.cloudiot.v1.model.Binding();
662+
bind.setRole(role);
663+
List<String> members = new ArrayList<>();
664+
members.add(member);
665+
bind.setMembers(members);
666+
667+
bindings.add(bind);
668+
}
669+
670+
policy.setBindings(bindings);
671+
SetIamPolicyRequest req = new SetIamPolicyRequest().setPolicy(policy);
672+
673+
policy =
674+
service
675+
.projects()
676+
.locations()
677+
.registries()
678+
.setIamPolicy(registryPath, req).execute();
679+
680+
System.out.println("Policy ETAG: " + policy.getEtag());
681+
for (com.google.api.services.cloudiot.v1.model.Binding binding: policy.getBindings()) {
682+
System.out.println(String.format("Role: %s", binding.getRole()));
683+
System.out.println("Binding members: ");
684+
for (String mem : binding.getMembers()) {
685+
System.out.println(String.format("\t%s", mem));
686+
}
687+
}
688+
}
689+
581690
/** Entry poit for CLI. */
582691
public static void main(String[] args) throws Exception {
583692
DeviceRegistryExampleOptions options = DeviceRegistryExampleOptions.fromFlags(args);
@@ -626,6 +735,10 @@ public static void main(String[] args) throws Exception {
626735
options.registryName)
627736
.toPrettyString());
628737
break;
738+
case "get-iam-permissions":
739+
System.out.println("Get iam permissions");
740+
getIamPermissions(options.projectId, options.cloudRegion, options.registryName);
741+
break;
629742
case "get-device-state":
630743
System.out.println("Get device state");
631744
List<DeviceState> states = getDeviceStates(options.deviceId, options.projectId,
@@ -666,6 +779,15 @@ public static void main(String[] args) throws Exception {
666779
options.registryName, options.configuration, options.version);
667780
}
668781
break;
782+
case "set-iam-permissions":
783+
if (options.member == null || options.role == null) {
784+
System.out.println("Specify member and role for the policy you are updating.");
785+
} else {
786+
System.out.println("Setting iam permissions");
787+
setIamPermissions(options.projectId, options.cloudRegion, options.registryName,
788+
options.member, options.role);
789+
}
790+
break;
669791
default:
670792
String header = "Cloud IoT Core Commandline Example (Device / Registry management): \n\n";
671793
String footer = "\nhttps://cloud.google.com/iot-core";

iot/api-client/manager/src/main/java/com/example/cloud/iot/examples/DeviceRegistryExampleOptions.java

+25-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public class DeviceRegistryExampleOptions {
3535
String deviceId; // Default to UUID?
3636
String pubsubTopic;
3737
String registryName;
38+
String member;
39+
String role;
3840
long version = 0;
3941
static final Options options = new Options();
4042

@@ -65,12 +67,14 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) {
6567
+ "\n\tdelete-registry"
6668
+ "\n\tget-device"
6769
+ "\n\tget-device-state"
70+
+ "\n\tget-iam-permissions"
6871
+ "\n\tget-registry"
6972
+ "\n\tlist-devices"
7073
+ "\n\tlist-registries"
7174
+ "\n\tpatch-device-es"
7275
+ "\n\tpatch-device-rsa"
73-
+ "\n\tset-config")
76+
+ "\n\tset-config"
77+
+ "\n\tset-iam-permissions")
7478
.required()
7579
.build());
7680

@@ -131,6 +135,20 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) {
131135
.hasArg()
132136
.desc("The configuration version to send on the device (0 is latest).")
133137
.build());
138+
options.addOption(
139+
Option.builder()
140+
.type(String.class)
141+
.longOpt("member")
142+
.hasArg()
143+
.desc("The member used for setting IAM permissions.")
144+
.build());
145+
options.addOption(
146+
Option.builder()
147+
.type(String.class)
148+
.longOpt("role")
149+
.hasArg()
150+
.desc("The role (e.g. 'roles/viewer') used when setting IAM permissions.")
151+
.build());
134152

135153
CommandLineParser parser = new DefaultParser();
136154
CommandLine commandLine;
@@ -181,6 +199,12 @@ public static DeviceRegistryExampleOptions fromFlags(String[] args) {
181199
if (commandLine.hasOption("version")) {
182200
res.version = new Long(commandLine.getOptionValue("version")).longValue();
183201
}
202+
if (commandLine.hasOption("member")) {
203+
res.member = commandLine.getOptionValue("member");
204+
}
205+
if (commandLine.hasOption("role")) {
206+
res.role = commandLine.getOptionValue("role");
207+
}
184208

185209
return res;
186210
} catch (ParseException e) {

iot/api-client/manager/src/test/java/com/example/cloud/iot/examples/ManagerIT.java

+38-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public class ManagerIT {
4545
private static final String RSA_PATH = "resources/rsa_cert.pem";
4646
private static final String PKCS_PATH = "resources/rsa_private_pkcs8";
4747
private static final String TOPIC_ID = "java-pst-" + (System.currentTimeMillis() / 1000L);
48+
private static final String MEMBER = "group:[email protected]";
49+
private static final String ROLE = "roles/viewer";
50+
4851

4952
private static Topic topic;
5053

@@ -242,7 +245,6 @@ public void testCreateListDevices() throws Exception {
242245

243246
@Test
244247
public void testCreateGetRegistry() throws Exception {
245-
246248
topic = DeviceRegistryExample.createIotTopic(
247249
PROJECT_ID,
248250
TOPIC_ID);
@@ -258,6 +260,41 @@ public void testCreateGetRegistry() throws Exception {
258260
}
259261
}
260262

263+
@Test
264+
public void testGetIam() throws Exception {
265+
topic = DeviceRegistryExample.createIotTopic(
266+
PROJECT_ID,
267+
TOPIC_ID);
268+
DeviceRegistryExample.createRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID, TOPIC_ID);
269+
DeviceRegistryExample.getIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID);
270+
271+
String got = bout.toString();
272+
Assert.assertTrue(got.contains("ETAG"));
273+
274+
DeviceRegistryExample.deleteRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID);
275+
try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) {
276+
topicAdminClient.deleteTopic(topic.getNameAsTopicName());
277+
}
278+
}
279+
280+
@Test
281+
public void testSetIam() throws Exception {
282+
topic = DeviceRegistryExample.createIotTopic(
283+
PROJECT_ID,
284+
TOPIC_ID);
285+
DeviceRegistryExample.createRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID, TOPIC_ID);
286+
DeviceRegistryExample.setIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID, MEMBER, ROLE);
287+
DeviceRegistryExample.getIamPermissions(PROJECT_ID, CLOUD_REGION, REGISTRY_ID);
288+
289+
String got = bout.toString();
290+
Assert.assertTrue(got.contains("ETAG"));
291+
292+
DeviceRegistryExample.deleteRegistry(CLOUD_REGION, PROJECT_ID, REGISTRY_ID);
293+
try (TopicAdminClient topicAdminClient = TopicAdminClient.create()) {
294+
topicAdminClient.deleteTopic(topic.getNameAsTopicName());
295+
}
296+
}
297+
261298
// HTTP device tests
262299

263300
@Test

0 commit comments

Comments
 (0)