Skip to content

Commit 6e859c9

Browse files
committed
Extend StorageExample to show how to add ACLs to blobs and buckets
1 parent 11f4573 commit 6e859c9

File tree

1 file changed

+242
-3
lines changed

1 file changed

+242
-3
lines changed

gcloud-java-examples/src/main/java/com/google/cloud/examples/storage/StorageExample.java

Lines changed: 242 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.cloud.AuthCredentials.ServiceAccountAuthCredentials;
2121
import com.google.cloud.ReadChannel;
2222
import com.google.cloud.WriteChannel;
23+
import com.google.cloud.storage.Acl;
2324
import com.google.cloud.storage.Blob;
2425
import com.google.cloud.storage.BlobId;
2526
import com.google.cloud.storage.BlobInfo;
@@ -30,7 +31,9 @@
3031
import com.google.cloud.storage.Storage.CopyRequest;
3132
import com.google.cloud.storage.Storage.SignUrlOption;
3233
import com.google.cloud.storage.StorageOptions;
34+
import com.google.cloud.storage.spi.StorageRpc;
3335
import com.google.cloud.storage.spi.StorageRpc.Tuple;
36+
import com.google.common.collect.ImmutableMap;
3437

3538
import java.io.FileOutputStream;
3639
import java.io.IOException;
@@ -51,6 +54,7 @@
5154
import java.util.Arrays;
5255
import java.util.HashMap;
5356
import java.util.Iterator;
57+
import java.util.LinkedList;
5458
import java.util.List;
5559
import java.util.Map;
5660
import java.util.concurrent.TimeUnit;
@@ -75,7 +79,11 @@
7579
* cp <from_bucket> <from_path> <to_bucket> <to_path> |
7680
* compose <bucket> <from_path>+ <to_path> |
7781
* update_metadata <bucket> <file> [key=value]* |
78-
* sign_url <service_account_private_key_file> <service_account_email> <bucket> <path>"}</pre>
82+
* sign_url <service_account_private_key_file> <service_account_email> <bucket> <path> |
83+
* add-acl domain <bucket> <path>? <domain> OWNER|READER|WRITER |
84+
* add-acl project <bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER |
85+
* add-acl user <bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER |
86+
* add-acl group <bucket> <path>? <group> OWNER|READER|WRITER"}</pre>
7987
* </li>
8088
* </ol>
8189
*
@@ -87,6 +95,7 @@
8795
public class StorageExample {
8896

8997
private static final Map<String, StorageAction> ACTIONS = new HashMap<>();
98+
private static final Map<String, StorageAction> ACL_ACTIONS = new HashMap<>();
9099

91100
private abstract static class StorageAction<T> {
92101

@@ -119,6 +128,48 @@ public String params() {
119128
}
120129
}
121130

131+
private static class ParentAction extends StorageAction<StorageRpc.Tuple<StorageAction, Object>> {
132+
133+
private final Map<String, StorageAction> subActions;
134+
135+
ParentAction(Map<String, StorageAction> subActions) {
136+
this.subActions = ImmutableMap.copyOf(subActions);
137+
}
138+
139+
@Override
140+
@SuppressWarnings("unchecked")
141+
void run(Storage storage, StorageRpc.Tuple<StorageAction, Object> subaction) throws Exception {
142+
subaction.x().run(storage, subaction.y());
143+
}
144+
145+
@Override
146+
StorageRpc.Tuple<StorageAction, Object> parse(String... args) throws Exception {
147+
if (args.length >= 1) {
148+
StorageAction action = subActions.get(args[0]);
149+
if (action != null) {
150+
Object actionArguments = action.parse(Arrays.copyOfRange(args, 1, args.length));
151+
return StorageRpc.Tuple.of(action, actionArguments);
152+
} else {
153+
throw new IllegalArgumentException("Unrecognized entity '" + args[0] + "'.");
154+
}
155+
}
156+
throw new IllegalArgumentException("Missing required entity.");
157+
}
158+
159+
@Override
160+
public String params() {
161+
StringBuilder builder = new StringBuilder();
162+
for (Map.Entry<String, StorageAction> entry : subActions.entrySet()) {
163+
builder.append('\n').append(entry.getKey());
164+
String param = entry.getValue().params();
165+
if (param != null && !param.isEmpty()) {
166+
builder.append(' ').append(param);
167+
}
168+
}
169+
return builder.toString();
170+
}
171+
}
172+
122173
/**
123174
* This class demonstrates how to retrieve Bucket or Blob metadata.
124175
* If more than one blob is supplied a Batch operation would be used to get all blobs metadata
@@ -512,6 +563,188 @@ public String params() {
512563
}
513564
}
514565

566+
private abstract static class AclAction extends StorageAction<Tuple<BlobId, Acl>> {
567+
568+
@Override
569+
public void run(Storage storage, Tuple<BlobId, Acl> params) {
570+
BlobId blobId = params.x();
571+
Acl acl = params.y();
572+
if (blobId.name().isEmpty()) {
573+
Bucket bucket = storage.get(blobId.bucket());
574+
if (bucket == null) {
575+
System.out.printf("Bucket %s does not exist%n", blobId.bucket());
576+
return;
577+
}
578+
bucket.toBuilder().acl(addAcl(bucket.acl(), acl)).build().update();
579+
System.out.printf("Added ACL %s to bucket %s%n", acl, blobId.bucket());
580+
} else {
581+
Blob blob = storage.get(blobId);
582+
if (blob == null) {
583+
System.out.printf("Blob %s does not exist%n", blobId);
584+
return;
585+
}
586+
blob.toBuilder().acl(addAcl(blob.acl(), acl)).build().update();
587+
System.out.printf("Added ACL %s to blob %s%n", acl, blobId);
588+
}
589+
}
590+
591+
private static List<Acl> addAcl(List<Acl> acls, Acl newAcl) {
592+
List<Acl> newAcls = new LinkedList<>(acls);
593+
newAcls.add(newAcl);
594+
return newAcls;
595+
}
596+
}
597+
598+
/**
599+
* This class demonstrates how to add an ACL to a blob or a bucket for a group of users
600+
* (identified by the group's email).
601+
*
602+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
603+
* Control Lists (ACLs)</a>
604+
*/
605+
private static class AddGroupAclAction extends AclAction {
606+
607+
@Override
608+
Tuple<BlobId, Acl> parse(String... args) {
609+
if (args.length >= 3) {
610+
BlobId blob;
611+
int nextArg;
612+
if (args.length == 3) {
613+
blob = BlobId.of(args[0], "");
614+
nextArg = 1;
615+
} else if (args.length == 4) {
616+
blob = BlobId.of(args[0], args[1]);
617+
nextArg = 2;
618+
} else {
619+
throw new IllegalArgumentException("Too many arguments.");
620+
}
621+
String group = args[nextArg++];
622+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
623+
return Tuple.of(blob, Acl.of(new Acl.Group(group), role));
624+
}
625+
throw new IllegalArgumentException("Missing required bucket, groupEmail or role arguments.");
626+
}
627+
628+
@Override
629+
public String params() {
630+
return "<bucket> <path>? <group> OWNER|READER|WRITER";
631+
}
632+
}
633+
634+
/**
635+
* This class demonstrates how to add an ACL to a blob or a bucket for a domain.
636+
*
637+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
638+
* Control Lists (ACLs)</a>
639+
*/
640+
private static class AddDomainAclAction extends AclAction {
641+
642+
@Override
643+
Tuple<BlobId, Acl> parse(String... args) {
644+
if (args.length >= 3) {
645+
BlobId blob;
646+
int nextArg;
647+
if (args.length == 3) {
648+
blob = BlobId.of(args[0], "");
649+
nextArg = 1;
650+
} else if (args.length == 4) {
651+
blob = BlobId.of(args[0], args[1]);
652+
nextArg = 2;
653+
} else {
654+
throw new IllegalArgumentException("Too many arguments.");
655+
}
656+
String domain = args[nextArg++];
657+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
658+
return Tuple.of(blob, Acl.of(new Acl.Domain(domain), role));
659+
}
660+
throw new IllegalArgumentException("Missing required bucket, domain or role arguments.");
661+
}
662+
663+
@Override
664+
public String params() {
665+
return "<bucket> <path>? <domain> OWNER|READER|WRITER";
666+
}
667+
}
668+
669+
/**
670+
* This class demonstrates how to add an ACL to a blob or a bucket for either a user (if an email
671+
* is provided), all users (if {@code allUsers} is provided), or all authenticated users (if
672+
* {@code allAuthenticatedUsers} is provided).
673+
*
674+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
675+
* Control Lists (ACLs)</a>
676+
*/
677+
private static class AddUserAclAction extends AclAction {
678+
679+
@Override
680+
Tuple<BlobId, Acl> parse(String... args) {
681+
if (args.length >= 3) {
682+
BlobId blob;
683+
int nextArg;
684+
if (args.length == 3) {
685+
blob = BlobId.of(args[0], "");
686+
nextArg = 1;
687+
} else if (args.length == 4) {
688+
blob = BlobId.of(args[0], args[1]);
689+
nextArg = 2;
690+
} else {
691+
throw new IllegalArgumentException("Too many arguments.");
692+
}
693+
String user = args[nextArg++];
694+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
695+
return Tuple.of(blob, Acl.of(new Acl.User(user), role));
696+
}
697+
throw new IllegalArgumentException("Missing required bucket, userEmail or role arguments.");
698+
}
699+
700+
@Override
701+
public String params() {
702+
return "<bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER";
703+
}
704+
}
705+
706+
/**
707+
* This class demonstrates how to add an ACL to a blob or a bucket for all users that have a
708+
* specific role in a provided project.
709+
*
710+
* @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
711+
* Control Lists (ACLs)</a>
712+
*/
713+
private static class AddProjectAclAction extends AclAction {
714+
715+
@Override
716+
Tuple<BlobId, Acl> parse(String... args) {
717+
if (args.length >= 3) {
718+
BlobId blob;
719+
int nextArg;
720+
if (args.length == 3) {
721+
blob = BlobId.of(args[0], "");
722+
nextArg = 1;
723+
} else if (args.length == 4) {
724+
blob = BlobId.of(args[0], args[1]);
725+
nextArg = 2;
726+
} else {
727+
throw new IllegalArgumentException("Too many arguments.");
728+
}
729+
String[] projectAndRole = args[nextArg++].split(":");
730+
if (projectAndRole.length != 2) {
731+
throw new IllegalArgumentException(
732+
"Project entity must be specified as <projectId>:(OWNERS|READERS|WRITERS)");
733+
} else {
734+
Acl.Project.ProjectRole projectRole = Acl.Project.ProjectRole.valueOf(projectAndRole[1]);
735+
Acl.Role role = Acl.Role.valueOf(args[nextArg]);
736+
return Tuple.of(blob, Acl.of(new Acl.Project(projectRole, projectAndRole[0]), role));
737+
}
738+
}
739+
throw new IllegalArgumentException("Missing required bucket, project or role arguments.");
740+
}
741+
742+
@Override
743+
public String params() {
744+
return "<bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER";
745+
}
746+
}
747+
515748
static {
516749
ACTIONS.put("info", new InfoAction());
517750
ACTIONS.put("delete", new DeleteAction());
@@ -522,6 +755,11 @@ public String params() {
522755
ACTIONS.put("compose", new ComposeAction());
523756
ACTIONS.put("update_metadata", new UpdateMetadataAction());
524757
ACTIONS.put("sign_url", new SignUrlAction());
758+
ACL_ACTIONS.put("group", new AddGroupAclAction());
759+
ACL_ACTIONS.put("domain", new AddDomainAclAction());
760+
ACL_ACTIONS.put("user", new AddUserAclAction());
761+
ACL_ACTIONS.put("project", new AddProjectAclAction());
762+
ACTIONS.put("add-acl", new ParentAction(ACL_ACTIONS));
525763
}
526764

527765
private static void printUsage() {
@@ -531,10 +769,11 @@ private static void printUsage() {
531769

532770
String param = entry.getValue().params();
533771
if (param != null && !param.isEmpty()) {
534-
actionAndParams.append(' ').append(param);
772+
// Add extra padding for multi-line action
773+
actionAndParams.append(' ').append(param.replace("\n", "\n\t\t"));
535774
}
536775
}
537-
System.out.printf("Usage: %s [<project_id>] operation <args>*%s%n",
776+
System.out.printf("Usage: %s [<project_id>] operation [entity] <args>*%s%n",
538777
StorageExample.class.getSimpleName(), actionAndParams);
539778
}
540779

0 commit comments

Comments
 (0)