Skip to content

Commit c81ff3e

Browse files
Bigtable: add resource level IAM (#3624)
1 parent c715fc6 commit c81ff3e

File tree

2 files changed

+403
-0
lines changed

2 files changed

+403
-0
lines changed

google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClient.java

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.api.core.ApiFunction;
2020
import com.google.api.core.ApiFuture;
2121
import com.google.api.core.ApiFutures;
22+
import com.google.api.resourcenames.ResourceName;
2223
import com.google.bigtable.admin.v2.AppProfileName;
2324
import com.google.bigtable.admin.v2.ClusterName;
2425
import com.google.bigtable.admin.v2.DeleteAppProfileRequest;
@@ -27,6 +28,8 @@
2728
import com.google.bigtable.admin.v2.ListAppProfilesRequest;
2829
import com.google.bigtable.admin.v2.LocationName;
2930
import com.google.bigtable.admin.v2.ProjectName;
31+
import com.google.cloud.Policy;
32+
import com.google.cloud.Policy.DefaultMarshaller;
3033
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListAppProfilesPage;
3134
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListAppProfilesPagedResponse;
3235
import com.google.cloud.bigtable.admin.v2.models.AppProfile;
@@ -46,8 +49,13 @@
4649
import com.google.common.util.concurrent.Futures;
4750
import com.google.common.util.concurrent.MoreExecutors;
4851
import com.google.common.util.concurrent.UncheckedExecutionException;
52+
import com.google.iam.v1.GetIamPolicyRequest;
53+
import com.google.iam.v1.SetIamPolicyRequest;
54+
import com.google.iam.v1.TestIamPermissionsRequest;
55+
import com.google.iam.v1.TestIamPermissionsResponse;
4956
import com.google.protobuf.Empty;
5057
import java.io.IOException;
58+
import java.util.Arrays;
5159
import java.util.List;
5260
import java.util.Objects;
5361
import javax.annotation.Nonnull;
@@ -992,6 +1000,284 @@ public Void apply(Empty input) {
9921000
);
9931001
}
9941002

1003+
/**
1004+
* Gets the IAM access control policy for the specified instance.
1005+
*
1006+
* <p>Sample code:
1007+
*
1008+
* <pre>{@code
1009+
* Policy policy = client.getIamPolicy("my-instance");
1010+
* for(Map.Entry<Role, Set<Identity>> entry : policy.getBindings().entrySet()) {
1011+
* System.out.printf("Role: %s Identities: %s\n", entry.getKey(), entry.getValue());
1012+
* }
1013+
* }</pre>
1014+
*
1015+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#iam-management-instance">Instance-level
1016+
* IAM management</a>
1017+
*/
1018+
@SuppressWarnings("WeakerAccess")
1019+
public Policy getIamPolicy(String instanceId) {
1020+
return awaitFuture(getIamPolicyAsync(instanceId));
1021+
}
1022+
1023+
/**
1024+
* Asynchronously gets the IAM access control policy for the specified instance.
1025+
*
1026+
* <p>Sample code:
1027+
*
1028+
* <pre>{@code
1029+
* ApiFuture<Policy> policyFuture = client.getIamPolicyAsync("my-instance");
1030+
*
1031+
* ApiFutures.addCallback(policyFuture,
1032+
* new ApiFutureCallback<Policy>() {
1033+
* public void onSuccess(Policy policy) {
1034+
* for (Entry<Role, Set<Identity>> entry : policy.getBindings().entrySet()) {
1035+
* System.out.printf("Role: %s Identities: %s\n", entry.getKey(), entry.getValue());
1036+
* }
1037+
* }
1038+
*
1039+
* public void onFailure(Throwable t) {
1040+
* t.printStackTrace();
1041+
* }
1042+
* },
1043+
* MoreExecutors.directExecutor());
1044+
* }</pre>
1045+
*
1046+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#iam-management-instance">Instance-level IAM management</a>
1047+
*/
1048+
@SuppressWarnings("WeakerAccess")
1049+
public ApiFuture<Policy> getIamPolicyAsync(String instanceId) {
1050+
InstanceName name = InstanceName.of(projectName.getProject(), instanceId);
1051+
1052+
GetIamPolicyRequest request = GetIamPolicyRequest.newBuilder()
1053+
.setResource(name.toString())
1054+
.build();
1055+
1056+
final IamPolicyMarshaller marshaller = new IamPolicyMarshaller();
1057+
1058+
return ApiFutures.transform(
1059+
stub.getIamPolicyCallable().futureCall(request),
1060+
new ApiFunction<com.google.iam.v1.Policy, Policy>() {
1061+
@Override
1062+
public Policy apply(com.google.iam.v1.Policy proto) {
1063+
return marshaller.fromPb(proto);
1064+
}
1065+
},
1066+
MoreExecutors.directExecutor()
1067+
);
1068+
}
1069+
1070+
/**
1071+
* Replaces the IAM policy associated with the specified instance.
1072+
*
1073+
* <p>Sample code:
1074+
*
1075+
* <pre>{@code
1076+
* Policy newPolicy = client.setIamPolicy("my-instance",
1077+
* Policy.newBuilder()
1078+
* .addIdentity(Role.of("bigtable.user"), Identity.user("someone@example.com"))
1079+
* .addIdentity(Role.of("bigtable.admin"), Identity.group("admins@example.com"))
1080+
* .build());
1081+
* }</pre>
1082+
*
1083+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#iam-management-instance">Instance-level IAM management</a>
1084+
*/
1085+
@SuppressWarnings("WeakerAccess")
1086+
public Policy setIamPolicy(String instanceId, Policy policy) {
1087+
return awaitFuture(setIamPolicyAsync(instanceId, policy));
1088+
}
1089+
1090+
/**
1091+
* Asynchronously replaces the IAM policy associated with the specified instance.
1092+
*
1093+
* <p>Sample code:
1094+
*
1095+
* <pre>{@code
1096+
* ApiFuture<Policy> newPolicyFuture = client.setIamPolicyAsync("my-instance",
1097+
* Policy.newBuilder()
1098+
* .addIdentity(Role.of("bigtable.user"), Identity.user("someone@example.com"))
1099+
* .addIdentity(Role.of("bigtable.admin"), Identity.group("admins@example.com"))
1100+
* .build());
1101+
*
1102+
* ApiFutures.addCallback(policyFuture,
1103+
* new ApiFutureCallback<Policy>() {
1104+
* public void onSuccess(Policy policy) {
1105+
* for (Entry<Role, Set<Identity>> entry : policy.getBindings().entrySet()) {
1106+
* System.out.printf("Role: %s Identities: %s\n", entry.getKey(), entry.getValue());
1107+
* }
1108+
* }
1109+
*
1110+
* public void onFailure(Throwable t) {
1111+
* t.printStackTrace();
1112+
* }
1113+
* },
1114+
* MoreExecutors.directExecutor());
1115+
* }</pre>
1116+
*
1117+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#iam-management-instance">Instance-level IAM management</a>
1118+
*/
1119+
@SuppressWarnings("WeakerAccess")
1120+
public ApiFuture<Policy> setIamPolicyAsync(String instanceId, Policy policy) {
1121+
InstanceName name = InstanceName.of(projectName.getProject(), instanceId);
1122+
final IamPolicyMarshaller marshaller = new IamPolicyMarshaller();
1123+
1124+
SetIamPolicyRequest request = SetIamPolicyRequest.newBuilder()
1125+
.setResource(name.toString())
1126+
.setPolicy(marshaller.toPb(policy))
1127+
.build();
1128+
1129+
return ApiFutures.transform(
1130+
stub.setIamPolicyCallable().futureCall(request),
1131+
new ApiFunction<com.google.iam.v1.Policy, Policy>() {
1132+
@Override
1133+
public Policy apply(com.google.iam.v1.Policy proto) {
1134+
return marshaller.fromPb(proto);
1135+
}
1136+
},
1137+
MoreExecutors.directExecutor()
1138+
);
1139+
}
1140+
1141+
/**
1142+
* Tests whether the caller has the given permissions for the specified instance.
1143+
* Returns a subset of the specified permissions that the caller has.
1144+
*
1145+
* <p>Sample code:
1146+
*
1147+
* <pre>{@code
1148+
* List<String> grantedPermissions = client.testIamPermission("my-instance",
1149+
* "bigtable.tables.readRows", "bigtable.tables.mutateRows");
1150+
* }</pre>
1151+
*
1152+
* System.out.println("Has read access: " + grantedPermissions.contains("bigtable.tables.readRows"));
1153+
* System.out.println("Has write access: " + grantedPermissions.contains("bigtable.tables.mutateRows"));
1154+
*
1155+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#permissions">Cloud Bigtable permissions</a>
1156+
*/
1157+
@SuppressWarnings("WeakerAccess")
1158+
public List<String> testIamPermission(String instanceId, String... permissions) {
1159+
return testIamPermission(InstanceName.of(projectName.getProject(), instanceId), permissions);
1160+
}
1161+
1162+
/**
1163+
* Asynchronously tests whether the caller has the given permissions for the specified instance.
1164+
* Returns a subset of the specified permissions that the caller has.
1165+
*
1166+
* <p>Sample code:
1167+
*
1168+
* <pre>{@code
1169+
* ApiFuture<List<String>> grantedPermissionsFuture = client.testIamPermission("my-instance",
1170+
* "bigtable.tables.readRows", "bigtable.tables.mutateRows");
1171+
*
1172+
* ApiFutures.addCallback(grantedPermissionsFuture,
1173+
* new ApiFutureCallback<List<String>>() {
1174+
* public void onSuccess(List<String> grantedPermissions) {
1175+
* System.out.println("Has read access: " + grantedPermissions.contains("bigtable.tables.readRows"));
1176+
* System.out.println("Has write access: " + grantedPermissions.contains("bigtable.tables.mutateRows"));
1177+
* }
1178+
*
1179+
* public void onFailure(Throwable t) {
1180+
* t.printStackTrace();
1181+
* }
1182+
* },
1183+
* MoreExecutors.directExecutor());
1184+
* }</pre>
1185+
*
1186+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#permissions">Cloud Bigtable permissions</a>
1187+
*/
1188+
@SuppressWarnings("WeakerAccess")
1189+
public ApiFuture<List<String>> testIamPermissionAsync(String instanceId, String... permissions) {
1190+
return testIamPermissionAsync(InstanceName.of(projectName.getProject(), instanceId), permissions);
1191+
}
1192+
1193+
/**
1194+
* Tests whether the caller has the given permissions for the specified absolute resource name
1195+
* (note that the current project of the client is ignored).
1196+
*
1197+
* Returns a subset of the specified permissions that the caller has.
1198+
*
1199+
* <p>Sample code:
1200+
*
1201+
* <pre>{@code
1202+
* List<String> grantedPermissions = client.testIamPermission(
1203+
* TableName.of("my-project", "my-instance", "my-table"),
1204+
* "bigtable.tables.readRows", "bigtable.tables.mutateRows");
1205+
*
1206+
* System.out.println("Has read access: " + grantedPermissions.contains("bigtable.tables.readRows"));
1207+
* System.out.println("Has write access: " + grantedPermissions.contains("bigtable.tables.mutateRows"));
1208+
* }</pre>
1209+
*
1210+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#permissions">Cloud Bigtable permissions</a>
1211+
*/
1212+
@SuppressWarnings("WeakerAccess")
1213+
public List<String> testIamPermission(ResourceName resourceName, String... permissions) {
1214+
return awaitFuture(testIamPermissionAsync(resourceName, permissions));
1215+
}
1216+
1217+
1218+
/**
1219+
* Asynchronously tests whether the caller has the given permissions for the the specified
1220+
* absolute resource name (note that the current project of the client is ignored).
1221+
* Returns a subset of the specified permissions that the caller has.
1222+
*
1223+
* <p>Sample code:
1224+
*
1225+
* <pre>{@code
1226+
* ApiFuture<List<String>> grantedPermissionsFuture = client.testIamPermission(
1227+
* TableName.of("my-project", "my-instance", "my-table"),
1228+
* "bigtable.tables.readRows", "bigtable.tables.mutateRows");
1229+
*
1230+
* ApiFutures.addCallback(grantedPermissionsFuture,
1231+
* new ApiFutureCallback<List<String>>() {
1232+
* public void onSuccess(List<String> grantedPermissions) {
1233+
* System.out.println("Has read access: " + grantedPermissions.contains("bigtable.tables.readRows"));
1234+
* System.out.println("Has write access: " + grantedPermissions.contains("bigtable.tables.mutateRows"));
1235+
* }
1236+
*
1237+
* public void onFailure(Throwable t) {
1238+
* t.printStackTrace();
1239+
* }
1240+
* },
1241+
* MoreExecutors.directExecutor());
1242+
* }</pre>
1243+
*
1244+
* @see <a href="https://cloud.google.com/bigtable/docs/access-control#permissions">Cloud Bigtable permissions</a>
1245+
*/
1246+
@SuppressWarnings("WeakerAccess")
1247+
public ApiFuture<List<String>> testIamPermissionAsync(ResourceName resourceName, String... permissions) {
1248+
TestIamPermissionsRequest request = TestIamPermissionsRequest.newBuilder()
1249+
.setResource(resourceName.toString())
1250+
.addAllPermissions(Arrays.asList(permissions))
1251+
.build();
1252+
1253+
return ApiFutures.transform(
1254+
stub.testIamPermissionsCallable().futureCall(request),
1255+
new ApiFunction<TestIamPermissionsResponse, List<String>>() {
1256+
@Override
1257+
public List<String> apply(TestIamPermissionsResponse input) {
1258+
return input.getPermissionsList();
1259+
}
1260+
},
1261+
MoreExecutors.directExecutor()
1262+
);
1263+
}
1264+
1265+
/**
1266+
* Simple adapter to expose {@link DefaultMarshaller} to this class. It enables this client to
1267+
* convert to/from IAM wrappers and protobufs.
1268+
*/
1269+
private static class IamPolicyMarshaller extends DefaultMarshaller {
1270+
@Override
1271+
public Policy fromPb(com.google.iam.v1.Policy policyPb) {
1272+
return super.fromPb(policyPb);
1273+
}
1274+
1275+
@Override
1276+
public com.google.iam.v1.Policy toPb(Policy policy) {
1277+
return super.toPb(policy);
1278+
}
1279+
}
1280+
9951281
/**
9961282
* Awaits the result of a future, taking care to propagate errors while maintaining the call site
9971283
* in a suppressed exception. This allows semantic errors to be caught across threads, while

0 commit comments

Comments
 (0)