From a37902def5c677a5caaf182c8ae1b14fe48666be Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Wed, 23 Nov 2022 16:27:30 +0530 Subject: [PATCH 01/11] feat(spanner): add samples for fine grained access control --- .../spanner/AddAndDropDatabaseRole.java | 66 ++++++++++ .../spanner/EnableFineGrainedAccess.java | 78 ++++++++++++ .../example/spanner/ListDatabaseRoles.java | 45 +++++++ .../spanner/ReadDataWithDatabaseRole.java | 48 ++++++++ .../com/example/spanner/DatabaseRolesIT.java | 115 ++++++++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java create mode 100644 samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java create mode 100644 samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java diff --git a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java new file mode 100644 index 00000000000..29468bb2416 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java @@ -0,0 +1,66 @@ +package com.example.spanner; + +// [START spanner_add_and_drop_database_role] +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.common.collect.ImmutableList; +import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import java.util.concurrent.ExecutionException; + +public class AddAndDropDatabaseRole { + + static void addAndDropDatabaseRole() throws InterruptedException, ExecutionException { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + String parentRole = "new-parent"; + String childRole = "new-child"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + addAndDropDatabaseRole(adminClient, instanceId, databaseId, parentRole, childRole); + } + } + + static void addAndDropDatabaseRole( + DatabaseAdminClient adminClient, + String instanceId, + String databaseId, + String parentRole, + String childRole) + throws InterruptedException, ExecutionException { + OperationFuture operation = + adminClient.updateDatabaseDdl( + instanceId, + databaseId, + ImmutableList.of( + "CREATE ROLE " + parentRole, + "GRANT SELECT ON TABLE Albums TO ROLE " + parentRole, + "CREATE ROLE " + childRole, + "GRANT ROLE " + parentRole + " TO ROLE " + childRole), + null); + + // Wait for the operation to finish. + // This will throw an ExecutionException if the operation fails. + operation.get(); + System.out.printf("Created roles %s and %s and granted privileges%n", parentRole, childRole); + + // Delete role and membership. + operation = + adminClient.updateDatabaseDdl( + instanceId, + databaseId, + ImmutableList.of( + "REVOKE ROLE " + parentRole + " FROM ROLE " + childRole, "DROP ROLE " + childRole), + null); + // Wait for the operation to finish. + // This will throw an ExecutionException if the operation fails. + operation.get(); + System.out.printf("Revoked privileges and dropped role %s%n", childRole); + } +} +// [END spanner_add_and_drop_database_role] diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java new file mode 100644 index 00000000000..ad5407cad4f --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -0,0 +1,78 @@ +package com.example.spanner; + +// [START spanner_enable_fine_grained_access] +import com.google.cloud.Binding; +import com.google.cloud.Condition; +import com.google.cloud.Policy; +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import java.util.ArrayList; +import java.util.List; + +public class EnableFineGrainedAccess { + + static void enableFineGrainedAccess() { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + String iamMember = "user:alice@example.com"; + String role = "new-parent"; + String title = "my condition title"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + enableFineGrainedAccess(adminClient, instanceId, databaseId, iamMember, title, role); + } + } + + static void enableFineGrainedAccess( + DatabaseAdminClient adminClient, + String instanceId, + String databaseId, + String iamMember, + String title, + String role) { + Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3); + int policyVersion = policy.getVersion(); + if (policy.getVersion() < 3) { + policyVersion = 3; + } + List members = new ArrayList<>(); + members.add(iamMember); + List bindings = new ArrayList<>(policy.getBindingsList()); + + bindings.add( + Binding.newBuilder() + .setRole("roles/spanner.fineGrainedAccessUser") + .setMembers(members) + .build()); + + bindings.add( + Binding.newBuilder() + .setRole("roles/spanner.databaseRoleUser") + .setCondition( + Condition.newBuilder() + .setDescription(title) + .setExpression( + String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) + .setTitle(title) + .build()) + .setMembers(members) + .build()); + + Policy policyWithConditions = + Policy.newBuilder() + .setVersion(policyVersion) + .setEtag(policy.getEtag()) + .setBindings(bindings) + .build(); + Policy response = + adminClient.setDatabaseIAMPolicy(instanceId, databaseId, policyWithConditions); + System.out.printf( + "Enabled fine-grained access in IAM with version %d%n", response.getVersion()); + } +} +// [END spanner_enable_fine_grained_access] diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java new file mode 100644 index 00000000000..74c7b0193f4 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java @@ -0,0 +1,45 @@ +package com.example.spanner; + +// [START spanner_list_database_roles] +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.DatabaseRole; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import java.util.concurrent.ExecutionException; + +public class ListDatabaseRoles { + + static void listDatabaseRoles() throws InterruptedException, ExecutionException { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + listDatabaseRoles(adminClient, projectId, instanceId, databaseId); + } + } + + static void listDatabaseRoles( + DatabaseAdminClient adminClient, String projectId, String instanceId, String databaseId) + throws InterruptedException, ExecutionException { + String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName(); + System.out.println("List of Database roles"); + for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) { + if (!role.getName().startsWith(databasePath + "/databaseRoles/")) { + throw new RuntimeException( + "Role +" + + role.getName() + + "does not have prefix [" + + databasePath + + "/databaseRoles/" + + "]"); + } + System.out.printf("%s%n", role.getName()); + } + } +} +// [END spanner_list_database_roles] diff --git a/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java new file mode 100644 index 00000000000..5f77ec0a164 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java @@ -0,0 +1,48 @@ +package com.example.spanner; + +// [START spanner_read_data_with_database_role] +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import java.util.Arrays; + +public class ReadDataWithDatabaseRole { + + static void readDataWithDatabaseRole() { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + String role = "new-parent"; + readDataWithDatabaseRole(projectId, instanceId, databaseId, role); + } + + static void readDataWithDatabaseRole( + String projectId, String instanceId, String databaseId, String role) { + try (Spanner spannerWithRole = + SpannerOptions.newBuilder() + .setProjectId(projectId) + .setDatabaseRole(role) + .build() + .getService()) { + DatabaseClient dbClient = + spannerWithRole.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); + ResultSet resultSet = + dbClient + .singleUse() + .read( + "Singers", + KeySet.all(), // Read all rows in a table. + Arrays.asList("SingerId", "FirstName", "LastName")); + while (resultSet.next()) { + System.out.printf("SingerId: %d\n", resultSet.getLong(0)); + System.out.printf("FirstName: %s\n", resultSet.getString(1)); + System.out.printf("LastName: %s\n", resultSet.getString(2)); + } + } + } +} +// [END spanner_read_data_with_database_role] diff --git a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java new file mode 100644 index 00000000000..7f4bffc78df --- /dev/null +++ b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java @@ -0,0 +1,115 @@ +package com.example.spanner; + +import static org.junit.Assert.assertTrue; + +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.Mutation; +import com.google.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class DatabaseRolesIT extends SampleTestBase { + private static DatabaseId databaseId; + + @BeforeClass + public static void createTestDatabase() throws Exception { + final String database = idGenerator.generateDatabaseId(); + databaseAdminClient + .createDatabase( + instanceId, + database, + ImmutableList.of( + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo BYTES(MAX)," + + " FullName STRING(2048) AS " + + " (ARRAY_TO_STRING([FirstName, LastName], \" \")) STORED" + + ") PRIMARY KEY (SingerId)", + "CREATE TABLE Albums (" + + " SingerId INT64 NOT NULL," + + " AlbumId INT64 NOT NULL," + + " AlbumTitle STRING(MAX)," + + " MarketingBudget INT64" + + ") PRIMARY KEY (SingerId, AlbumId)," + + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE")) + .get(10, TimeUnit.MINUTES); + databaseId = DatabaseId.of(projectId, instanceId, database); + } + + @Before + public void insertTestData() { + final DatabaseClient client = spanner.getDatabaseClient(databaseId); + client.write( + Arrays.asList( + Mutation.newInsertOrUpdateBuilder("Singers") + .set("SingerId") + .to(1L) + .set("FirstName") + .to("Melissa") + .set("LastName") + .to("Garcia") + .build(), + Mutation.newInsertOrUpdateBuilder("Albums") + .set("SingerId") + .to(1L) + .set("AlbumId") + .to(1L) + .set("AlbumTitle") + .to("title 1") + .set("MarketingBudget") + .to(20000L) + .build())); + } + + @After + public void removeTestData() { + final DatabaseClient client = spanner.getDatabaseClient(databaseId); + client.write(Collections.singletonList(Mutation.delete("Singers", KeySet.all()))); + } + + @Test + public void testAddAndDropDatabaseRole() throws Exception { + final String out = + SampleRunner.runSample( + () -> + AddAndDropDatabaseRole.addAndDropDatabaseRole( + databaseAdminClient, + instanceId, + databaseId.getDatabase(), + "new-parent", + "new-child")); + assertTrue(out.contains("Created roles new_parent and new_child and granted privileges")); + assertTrue(out.contains("Revoked privileges and dropped role new_child")); + } + + @Test + public void testListDatabaseRoles() throws Exception { + final String out = + SampleRunner.runSample( + () -> + ListDatabaseRoles.listDatabaseRoles( + databaseAdminClient, projectId, instanceId, databaseId.getDatabase())); + assertTrue(out.contains("new_parent")); + } + + @Test + public void testReadDataWithDatabaseRole() throws Exception { + final String out = + SampleRunner.runSample( + () -> + ReadDataWithDatabaseRole.readDataWithDatabaseRole( + projectId, instanceId, databaseId.getDatabase(), "new_parent")); + assertTrue(out.contains("SingerId: 1")); + assertTrue(out.contains("FirstName: Melissa")); + assertTrue(out.contains("LastName: Garcia")); + } +} From 75b2c74e4f276cd86fef85109408463e476a37ff Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 23 Nov 2022 11:03:00 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3e782b61cae..a074ee044e9 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Database Operations | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/native-image/src/main/java/com/example/spanner/DatabaseOperations.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/native-image/src/main/java/com/example/spanner/DatabaseOperations.java) | | Instance Operations | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/native-image/src/main/java/com/example/spanner/InstanceOperations.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/native-image/src/main/java/com/example/spanner/InstanceOperations.java) | | Native Image Spanner Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/native-image/src/main/java/com/example/spanner/NativeImageSpannerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/native-image/src/main/java/com/example/spanner/NativeImageSpannerSample.java) | +| Add And Drop Database Role | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java) | | Add Json Column Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java) | | Add Jsonb Column Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java) | | Add Numeric Column Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java) | @@ -267,10 +268,12 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Custom Timeout And Retry Settings Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CustomTimeoutAndRetrySettingsExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CustomTimeoutAndRetrySettingsExample.java) | | Delete Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java) | | Delete Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DeleteUsingDmlReturningSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/DeleteUsingDmlReturningSample.java) | +| Enable Fine Grained Access | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java) | | Get Commit Stats Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/GetCommitStatsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/GetCommitStatsSample.java) | | Get Database Ddl Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java) | | Get Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java) | | Insert Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/InsertUsingDmlReturningSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/InsertUsingDmlReturningSample.java) | +| List Database Roles | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java) | | List Databases Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java) | | List Instance Config Operations Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java) | | List Instance Configs Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java) | @@ -291,6 +294,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Query With Jsonb Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryWithJsonbParameterSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryWithJsonbParameterSample.java) | | Query With Numeric Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryWithNumericParameterSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryWithNumericParameterSample.java) | | Quickstart Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QuickstartSample.java) | +| Read Data With Database Role | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java) | | Restore Backup With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java) | | Spanner Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/SpannerSample.java) | | Statement Timeout Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/StatementTimeoutExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/StatementTimeoutExample.java) | From 033375cfed741fc3473648e2626fe2996526c855 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Wed, 23 Nov 2022 16:36:15 +0530 Subject: [PATCH 03/11] fix sample checkstyles --- .../example/spanner/AddAndDropDatabaseRole.java | 16 ++++++++++++++++ .../example/spanner/EnableFineGrainedAccess.java | 16 ++++++++++++++++ .../com/example/spanner/ListDatabaseRoles.java | 16 ++++++++++++++++ .../spanner/ReadDataWithDatabaseRole.java | 16 ++++++++++++++++ .../com/example/spanner/DatabaseRolesIT.java | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java index 29468bb2416..5987619a3f1 100644 --- a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java +++ b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.spanner; // [START spanner_add_and_drop_database_role] diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index ad5407cad4f..569a3b9858c 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.spanner; // [START spanner_enable_fine_grained_access] diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java index 74c7b0193f4..a4d605b94a8 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java +++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.spanner; // [START spanner_list_database_roles] diff --git a/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java index 5f77ec0a164..f7187eb4672 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java +++ b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.spanner; // [START spanner_read_data_with_database_role] diff --git a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java index 7f4bffc78df..6ebca603537 100644 --- a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java +++ b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.example.spanner; import static org.junit.Assert.assertTrue; From 51c8726276b5ce8d3219349c1ec9d3277ad4ec26 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Mon, 28 Nov 2022 13:53:58 +0530 Subject: [PATCH 04/11] incorporate review comment --- .../src/test/java/com/example/spanner/DatabaseRolesIT.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java index 6ebca603537..7449284cf55 100644 --- a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java +++ b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java @@ -30,8 +30,13 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +/** Integration tests for FGAC samples for GoogleStandardSql dialect. */ +@RunWith(JUnit4.class) public class DatabaseRolesIT extends SampleTestBase { + private static DatabaseId databaseId; @BeforeClass From d92aae62b61ecd1fa55cb695a09ef5e82981375d Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Wed, 30 Nov 2022 11:22:38 +0530 Subject: [PATCH 05/11] incorporate requested changes --- .../spanner/AddAndDropDatabaseRole.java | 83 +++++++++-------- .../spanner/EnableFineGrainedAccess.java | 91 ++++++++++--------- .../example/spanner/ListDatabaseRoles.java | 37 ++++---- .../com/example/spanner/DatabaseRolesIT.java | 8 +- 4 files changed, 111 insertions(+), 108 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java index 5987619a3f1..a70442fab31 100644 --- a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java +++ b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java @@ -24,59 +24,62 @@ import com.google.common.collect.ImmutableList; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class AddAndDropDatabaseRole { - static void addAndDropDatabaseRole() throws InterruptedException, ExecutionException { + static void addAndDropDatabaseRole() { // TODO(developer): Replace these variables before running the sample. String projectId = "my-project"; String instanceId = "my-instance"; String databaseId = "my-database"; String parentRole = "new-parent"; String childRole = "new-child"; + addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole); + } + static void addAndDropDatabaseRole( + String projectId, String instanceId, String databaseId, String parentRole, String childRole) { try (Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { - DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); - addAndDropDatabaseRole(adminClient, instanceId, databaseId, parentRole, childRole); + final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + OperationFuture operation = + adminClient.updateDatabaseDdl( + instanceId, + databaseId, + ImmutableList.of( + "CREATE ROLE " + parentRole, + "GRANT SELECT ON TABLE Albums TO ROLE " + parentRole, + "CREATE ROLE " + childRole, + "GRANT ROLE " + parentRole + " TO ROLE " + childRole), + null); + try { + System.out.println("Waiting for role create operation to complete..."); + operation.get(5, TimeUnit.MINUTES); + System.out.printf( + "Created roles %s and %s and granted privileges%n", parentRole, childRole); + // Delete role and membership. + operation = + adminClient.updateDatabaseDdl( + instanceId, + databaseId, + ImmutableList.of( + "REVOKE ROLE " + parentRole + " FROM ROLE " + childRole, + "DROP ROLE " + childRole), + null); + System.out.println("Waiting for role revoke & drop operation to complete..."); + operation.get(5, TimeUnit.MINUTES); + System.out.printf("Revoked privileges and dropped role %s%n", childRole); + } catch (ExecutionException | TimeoutException e) { + System.out.printf( + "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage()); + e.printStackTrace(); + } catch (InterruptedException e) { + System.out.println( + "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted"); + } } } - - static void addAndDropDatabaseRole( - DatabaseAdminClient adminClient, - String instanceId, - String databaseId, - String parentRole, - String childRole) - throws InterruptedException, ExecutionException { - OperationFuture operation = - adminClient.updateDatabaseDdl( - instanceId, - databaseId, - ImmutableList.of( - "CREATE ROLE " + parentRole, - "GRANT SELECT ON TABLE Albums TO ROLE " + parentRole, - "CREATE ROLE " + childRole, - "GRANT ROLE " + parentRole + " TO ROLE " + childRole), - null); - - // Wait for the operation to finish. - // This will throw an ExecutionException if the operation fails. - operation.get(); - System.out.printf("Created roles %s and %s and granted privileges%n", parentRole, childRole); - - // Delete role and membership. - operation = - adminClient.updateDatabaseDdl( - instanceId, - databaseId, - ImmutableList.of( - "REVOKE ROLE " + parentRole + " FROM ROLE " + childRole, "DROP ROLE " + childRole), - null); - // Wait for the operation to finish. - // This will throw an ExecutionException if the operation fails. - operation.get(); - System.out.printf("Revoked privileges and dropped role %s%n", childRole); - } } // [END spanner_add_and_drop_database_role] diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index 569a3b9858c..b9778706bd7 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -36,59 +36,66 @@ static void enableFineGrainedAccess() { String iamMember = "user:alice@example.com"; String role = "new-parent"; String title = "my condition title"; - - try (Spanner spanner = - SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { - DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); - enableFineGrainedAccess(adminClient, instanceId, databaseId, iamMember, title, role); - } + enableFineGrainedAccess(projectId, instanceId, databaseId, iamMember, title, role); } static void enableFineGrainedAccess( - DatabaseAdminClient adminClient, + String projectId, String instanceId, String databaseId, String iamMember, String title, String role) { - Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3); - int policyVersion = policy.getVersion(); - if (policy.getVersion() < 3) { - policyVersion = 3; - } - List members = new ArrayList<>(); - members.add(iamMember); - List bindings = new ArrayList<>(policy.getBindingsList()); + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3); + int policyVersion = policy.getVersion(); + /* getDatabaseIAMPolicy returns the IAM policy for the given database + * + * The policy in the response might use the policy version that you specified, or it might use + * a lower policy version. For example, if you specify version 3, but the policy has no + * conditional role bindings, the response uses version 1. Valid values are 0, 1, and 3. + * + */ + if (policy.getVersion() < 3) { + // conditional role bindings work with policy version 3 + policyVersion = 3; + } + List members = new ArrayList<>(); + members.add(iamMember); + List bindings = new ArrayList<>(policy.getBindingsList()); - bindings.add( - Binding.newBuilder() - .setRole("roles/spanner.fineGrainedAccessUser") - .setMembers(members) - .build()); + bindings.add( + Binding.newBuilder() + .setRole("roles/spanner.fineGrainedAccessUser") + .setMembers(members) + .build()); - bindings.add( - Binding.newBuilder() - .setRole("roles/spanner.databaseRoleUser") - .setCondition( - Condition.newBuilder() - .setDescription(title) - .setExpression( - String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) - .setTitle(title) - .build()) - .setMembers(members) - .build()); + bindings.add( + Binding.newBuilder() + .setRole("roles/spanner.databaseRoleUser") + .setCondition( + Condition.newBuilder() + .setDescription(title) + .setExpression( + String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) + .setTitle(title) + .build()) + .setMembers(members) + .build()); - Policy policyWithConditions = - Policy.newBuilder() - .setVersion(policyVersion) - .setEtag(policy.getEtag()) - .setBindings(bindings) - .build(); - Policy response = - adminClient.setDatabaseIAMPolicy(instanceId, databaseId, policyWithConditions); - System.out.printf( - "Enabled fine-grained access in IAM with version %d%n", response.getVersion()); + Policy policyWithConditions = + Policy.newBuilder() + .setVersion(policyVersion) + .setEtag(policy.getEtag()) + .setBindings(bindings) + .build(); + Policy response = + adminClient.setDatabaseIAMPolicy(instanceId, databaseId, policyWithConditions); + System.out.printf( + "Enabled fine-grained access in IAM with version %d%n", response.getVersion()); + } } } // [END spanner_enable_fine_grained_access] diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java index a4d605b94a8..3249c11b70a 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java +++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java @@ -31,30 +31,27 @@ static void listDatabaseRoles() throws InterruptedException, ExecutionException String projectId = "my-project"; String instanceId = "my-instance"; String databaseId = "my-database"; + listDatabaseRoles(projectId, instanceId, databaseId); + } + static void listDatabaseRoles(String projectId, String instanceId, String databaseId) { try (Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { - DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); - listDatabaseRoles(adminClient, projectId, instanceId, databaseId); - } - } - - static void listDatabaseRoles( - DatabaseAdminClient adminClient, String projectId, String instanceId, String databaseId) - throws InterruptedException, ExecutionException { - String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName(); - System.out.println("List of Database roles"); - for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) { - if (!role.getName().startsWith(databasePath + "/databaseRoles/")) { - throw new RuntimeException( - "Role +" - + role.getName() - + "does not have prefix [" - + databasePath - + "/databaseRoles/" - + "]"); + final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); + String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName(); + System.out.println("List of Database roles"); + for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) { + if (!role.getName().startsWith(databasePath + "/databaseRoles/")) { + throw new RuntimeException( + "Role +" + + role.getName() + + "does not have prefix [" + + databasePath + + "/databaseRoles/" + + "]"); + } + System.out.printf("%s%n", role.getName()); } - System.out.printf("%s%n", role.getName()); } } } diff --git a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java index 7449284cf55..b0a506430ae 100644 --- a/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java +++ b/samples/snippets/src/test/java/com/example/spanner/DatabaseRolesIT.java @@ -103,11 +103,7 @@ public void testAddAndDropDatabaseRole() throws Exception { SampleRunner.runSample( () -> AddAndDropDatabaseRole.addAndDropDatabaseRole( - databaseAdminClient, - instanceId, - databaseId.getDatabase(), - "new-parent", - "new-child")); + projectId, instanceId, databaseId.getDatabase(), "new-parent", "new-child")); assertTrue(out.contains("Created roles new_parent and new_child and granted privileges")); assertTrue(out.contains("Revoked privileges and dropped role new_child")); } @@ -118,7 +114,7 @@ public void testListDatabaseRoles() throws Exception { SampleRunner.runSample( () -> ListDatabaseRoles.listDatabaseRoles( - databaseAdminClient, projectId, instanceId, databaseId.getDatabase())); + projectId, instanceId, databaseId.getDatabase())); assertTrue(out.contains("new_parent")); } From aaa7a9d641bd3cbe9c75da04b20a4553f14ddb46 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Tue, 13 Dec 2022 09:32:13 +0530 Subject: [PATCH 06/11] incorporate requested changes --- .../spanner/AddAndDropDatabaseRole.java | 9 ++-- .../spanner/EnableFineGrainedAccess.java | 44 +++++++++++-------- .../example/spanner/ListDatabaseRoles.java | 5 ++- .../spanner/ReadDataWithDatabaseRole.java | 4 +- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java index a70442fab31..2d65974099d 100644 --- a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java +++ b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java @@ -34,15 +34,18 @@ static void addAndDropDatabaseRole() { String projectId = "my-project"; String instanceId = "my-instance"; String databaseId = "my-database"; - String parentRole = "new-parent"; - String childRole = "new-child"; + String parentRole = "my-new-parent-role"; + String childRole = "my-new-child-role"; addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole); } static void addAndDropDatabaseRole( String projectId, String instanceId, String databaseId, String parentRole, String childRole) { try (Spanner spanner = - SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + SpannerOptions.newBuilder() + .setProjectId(projectId) + .build() + .getService()) { final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); OperationFuture operation = adminClient.updateDatabaseDdl( diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index b9778706bd7..e360051540b 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -23,6 +23,8 @@ import com.google.cloud.spanner.DatabaseAdminClient; import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; +import com.google.common.collect.ImmutableList; + import java.util.ArrayList; import java.util.List; @@ -34,8 +36,8 @@ static void enableFineGrainedAccess() { String instanceId = "my-instance"; String databaseId = "my-database"; String iamMember = "user:alice@example.com"; - String role = "new-parent"; - String title = "my condition title"; + String role = "my-role"; + String title = "my-condition-title"; enableFineGrainedAccess(projectId, instanceId, databaseId, iamMember, title, role); } @@ -47,44 +49,50 @@ static void enableFineGrainedAccess( String title, String role) { try (Spanner spanner = - SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + SpannerOptions.newBuilder() + .setProjectId(projectId) + .build() + .getService()) { final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3); int policyVersion = policy.getVersion(); - /* getDatabaseIAMPolicy returns the IAM policy for the given database - * - * The policy in the response might use the policy version that you specified, or it might use - * a lower policy version. For example, if you specify version 3, but the policy has no - * conditional role bindings, the response uses version 1. Valid values are 0, 1, and 3. - * - */ + // The policy in the response from getDatabaseIAMPolicy might use the policy version + // that you specified, or it might use a lower policy version. For example, if you + // specify version 3, but the policy has no conditional role bindings, the response + // uses version 1. Valid values are 0, 1, and 3. if (policy.getVersion() < 3) { // conditional role bindings work with policy version 3 policyVersion = 3; } + List members = new ArrayList<>(); members.add(iamMember); - List bindings = new ArrayList<>(policy.getBindingsList()); - - bindings.add( + Binding binding1 = Binding.newBuilder() .setRole("roles/spanner.fineGrainedAccessUser") .setMembers(members) - .build()); + .build(); - bindings.add( + Binding binding2 = Binding.newBuilder() .setRole("roles/spanner.databaseRoleUser") .setCondition( Condition.newBuilder() .setDescription(title) .setExpression( - String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) + String.format( + "resource.type == \"spanner.googleapis.com/DatabaseRole\" && resource.name.endsWith(\"/databaseRoles/%s\")", + role)) .setTitle(title) .build()) .setMembers(members) - .build()); - + .build(); + ImmutableList bindings = + ImmutableList.builder() + .addAll(policy.getBindingsList()) + .add(binding1) + .add(binding2) + .build(); Policy policyWithConditions = Policy.newBuilder() .setVersion(policyVersion) diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java index 3249c11b70a..e2b6e908661 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java +++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java @@ -36,7 +36,10 @@ static void listDatabaseRoles() throws InterruptedException, ExecutionException static void listDatabaseRoles(String projectId, String instanceId, String databaseId) { try (Spanner spanner = - SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + SpannerOptions.newBuilder() + .setProjectId(projectId) + .build() + .getService()) { final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient(); String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName(); System.out.println("List of Database roles"); diff --git a/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java index f7187eb4672..a746d54e0e4 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java +++ b/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java @@ -32,7 +32,7 @@ static void readDataWithDatabaseRole() { String projectId = "my-project"; String instanceId = "my-instance"; String databaseId = "my-database"; - String role = "new-parent"; + String role = "my-role"; readDataWithDatabaseRole(projectId, instanceId, databaseId, role); } @@ -51,7 +51,7 @@ static void readDataWithDatabaseRole( .singleUse() .read( "Singers", - KeySet.all(), // Read all rows in a table. + KeySet.all(), Arrays.asList("SingerId", "FirstName", "LastName")); while (resultSet.next()) { System.out.printf("SingerId: %d\n", resultSet.getLong(0)); From d4ad45f4b26691e4d3ce253ecd53293adb22131e Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Tue, 13 Dec 2022 09:39:28 +0530 Subject: [PATCH 07/11] fix checkstyle --- .../java/com/example/spanner/EnableFineGrainedAccess.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index e360051540b..22f1ef540a6 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -24,7 +24,6 @@ import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; import com.google.common.collect.ImmutableList; - import java.util.ArrayList; import java.util.List; @@ -80,9 +79,7 @@ static void enableFineGrainedAccess( Condition.newBuilder() .setDescription(title) .setExpression( - String.format( - "resource.type == \"spanner.googleapis.com/DatabaseRole\" && resource.name.endsWith(\"/databaseRoles/%s\")", - role)) + String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) .setTitle(title) .build()) .setMembers(members) From 49a3b0d1b1b138914d584df063a66e235527dca3 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 15 Dec 2022 12:19:25 +0530 Subject: [PATCH 08/11] incorporate review comments --- .../java/com/example/spanner/EnableFineGrainedAccess.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index 22f1ef540a6..b58ad7d8e6e 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -24,8 +24,6 @@ import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerOptions; import com.google.common.collect.ImmutableList; -import java.util.ArrayList; -import java.util.List; public class EnableFineGrainedAccess { @@ -64,8 +62,10 @@ static void enableFineGrainedAccess( policyVersion = 3; } - List members = new ArrayList<>(); - members.add(iamMember); + ImmutableList members = + ImmutableList.builder() + .add(iamMember) + .build(); Binding binding1 = Binding.newBuilder() .setRole("roles/spanner.fineGrainedAccessUser") From 339c232f1b342bb62842f23d6f24236d9818c389 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 15 Dec 2022 06:54:37 +0000 Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a074ee044e9..2834381011d 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,13 @@ implementation 'com.google.cloud:google-cloud-spanner' If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-spanner:6.33.0' +implementation 'com.google.cloud:google-cloud-spanner:6.34.1' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.33.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.34.1" ``` ## Authentication From 99cad7155b574c0f150532ea353b203e86117f85 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 15 Dec 2022 12:26:35 +0530 Subject: [PATCH 10/11] refactoring --- .../java/com/example/spanner/EnableFineGrainedAccess.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java index b58ad7d8e6e..c4c17645b68 100644 --- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java +++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java @@ -62,14 +62,10 @@ static void enableFineGrainedAccess( policyVersion = 3; } - ImmutableList members = - ImmutableList.builder() - .add(iamMember) - .build(); Binding binding1 = Binding.newBuilder() .setRole("roles/spanner.fineGrainedAccessUser") - .setMembers(members) + .setMembers(ImmutableList.of(iamMember)) .build(); Binding binding2 = @@ -82,7 +78,7 @@ static void enableFineGrainedAccess( String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)) .setTitle(title) .build()) - .setMembers(members) + .setMembers(ImmutableList.of(iamMember)) .build(); ImmutableList bindings = ImmutableList.builder() From abb9713ff53b1f26cd4a8a5833bcf071c6067370 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 15 Dec 2022 12:43:51 +0530 Subject: [PATCH 11/11] remove role check & exceptions --- .../main/java/com/example/spanner/ListDatabaseRoles.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java index e2b6e908661..92924050544 100644 --- a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java +++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java @@ -44,15 +44,6 @@ static void listDatabaseRoles(String projectId, String instanceId, String databa String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName(); System.out.println("List of Database roles"); for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) { - if (!role.getName().startsWith(databasePath + "/databaseRoles/")) { - throw new RuntimeException( - "Role +" - + role.getName() - + "does not have prefix [" - + databasePath - + "/databaseRoles/" - + "]"); - } System.out.printf("%s%n", role.getName()); } }