Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds IAM get/set for binding members and roles #996

Merged
merged 6 commits into from
Feb 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

/**
Expand Down Expand Up @@ -93,15 +93,16 @@ 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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this -- is it required?

// add role -> members binding
Binding binding =
Binding.newBuilder()
.addMembers("serviceAccount:[email protected]")
.setRole(Role.owner().toString())
.build();
// create updated policy
Policy updatedPolicy = Policy.newBuilder(policy).addBindings(binding).build();
com.google.iam.v1.Policy updatedPolicy =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, not a fan.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the code that does not appear in documentation, it's necessary for testing the API and is a convenient helper if someone is using this to automate device provisioning.

com.google.iam.v1.Policy.newBuilder(policy).addBindings(binding).build();
topicAdminClient.setIamPolicy(topicName.toString(), updatedPolicy);

System.out.println("Setup topic / policy for: " + topic.getName());
Expand Down Expand Up @@ -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 =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ugly

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<com.google.api.services.cloudiot.v1.model.Binding> 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<String> 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<String> 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);
Expand Down Expand Up @@ -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<DeviceState> states = getDeviceStates(options.deviceId, options.projectId,
Expand Down Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:[email protected]";
private static final String ROLE = "roles/viewer";


private static Topic topic;

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

@Test
public void testCreateGetRegistry() throws Exception {

topic = DeviceRegistryExample.createIotTopic(
PROJECT_ID,
TOPIC_ID);
Expand All @@ -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
Expand Down