| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.jclouds.s3.domain; |
| |
| import java.net.URI; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Function; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Collections2; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| |
| /** |
| * An Access Control List (ACL) describes the access control settings for a bucket or object in S3. |
| * |
| * ACL settings comprise a set of {@link Grant}s, each of which specifies a {@link Permission} that |
| * has been granted to a specific {@link Grantee}. If an payload tries to access or modify an item |
| * in S3, the operation will be denied unless the item has ACL settings that explicitly permit that |
| * payload to perform that action. |
| */ |
| public class AccessControlList { |
| |
| private CanonicalUser owner; |
| private final List<Grant> grants = Lists.newArrayList(); |
| |
| public void setOwner(CanonicalUser owner) { |
| this.owner = owner; |
| } |
| |
| public CanonicalUser getOwner() { |
| return owner; |
| } |
| |
| /** |
| * @return an unmodifiable set of grants represented by this ACL. |
| */ |
| public List<Grant> getGrants() { |
| return Collections.unmodifiableList(grants); |
| } |
| |
| /** |
| * @return an unmodifiable set of grantees who have been assigned permissions in this ACL. |
| */ |
| public Set<Grantee> getGrantees() { |
| Set<Grantee> grantees = Sets.newTreeSet(); |
| for (Grant grant : getGrants()) { |
| grantees.add(grant.getGrantee()); |
| } |
| return Collections.unmodifiableSet(grantees); |
| } |
| |
| /** |
| * Add a permission for the given grantee. |
| * |
| * @param grantee |
| * @param permission |
| */ |
| public AccessControlList addPermission(Grantee grantee, String permission) { |
| Grant grant = new Grant(grantee, permission); |
| grants.add(grant); |
| return this; |
| } |
| |
| /** |
| * Add a permission for the given group grantee. |
| * |
| * @param groupGranteeURI |
| * @param permission |
| */ |
| public AccessControlList addPermission(URI groupGranteeURI, String permission) { |
| return addPermission(new GroupGrantee(groupGranteeURI), permission); |
| } |
| |
| /** |
| * Revoke a permission for the given grantee, if this specific permission was granted. |
| * |
| * Note that you must be very explicit about the permissions you revoke, you cannot revoke |
| * partial permissions and expect this class to determine the implied remaining permissions. For |
| * example, if you revoke the {@link Permission#READ} permission from a grantee with |
| * {@link Permission#FULL_CONTROL} access, <strong>the revocation will do nothing</strong> and |
| * the grantee will retain full access. To change the access settings for this grantee, you must |
| * first remove the {@link Permission#FULL_CONTROL} permission the add back the |
| * {@link Permission#READ} permission. |
| * |
| * @param grantee |
| * @param permission |
| */ |
| public AccessControlList revokePermission(Grantee grantee, String permission) { |
| for (Iterator<Grant> it = grants.iterator(); it.hasNext();) { |
| Grant grant = it.next(); |
| if (grant.getGrantee().equals(grantee) && grant.getPermission().equals(permission)) { |
| it.remove(); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * Revoke a permission for the given group grantee, if this specific permission was granted. |
| * |
| * Note that you must be very explicit about the permissions you revoke, you cannot revoke |
| * partial permissions and expect this class to determine the implied remaining permissions. For |
| * example, if you revoke the {@link Permission#READ} permission from a grantee with |
| * {@link Permission#FULL_CONTROL} access, <strong>the revocation will do nothing</strong> and |
| * the grantee will retain full access. To change the access settings for this grantee, you must |
| * first remove the {@link Permission#FULL_CONTROL} permission the add back the |
| * {@link Permission#READ} permission. |
| * |
| * @param groupGranteeURI |
| * @param permission |
| */ |
| public AccessControlList revokePermission(URI groupGranteeURI, String permission) { |
| return revokePermission(new GroupGrantee(groupGranteeURI), permission); |
| } |
| |
| /** |
| * Revoke all the permissions granted to the given grantee. |
| * |
| * @param grantee |
| */ |
| public AccessControlList revokeAllPermissions(Grantee grantee) { |
| Collection<Grant> grantsForGrantee = findGrantsForGrantee(grantee.getIdentifier()); |
| grants.removeAll(grantsForGrantee); |
| return this; |
| } |
| |
| /** |
| * @param granteeId |
| * @return the permissions assigned to a grantee, as identified by the given ID. |
| */ |
| public Collection<String> getPermissions(String granteeId) { |
| Collection<Grant> grantsForGrantee = findGrantsForGrantee(granteeId); |
| return Collections2.transform(grantsForGrantee, new Function<Grant, String>() { |
| public String apply(Grant g) { |
| return g.getPermission(); |
| } |
| }); |
| } |
| |
| /** |
| * @param grantee |
| * @return the permissions assigned to a grantee. |
| */ |
| public Collection<String> getPermissions(Grantee grantee) { |
| return getPermissions(grantee.getIdentifier()); |
| } |
| |
| /** |
| * @param granteeURI |
| * @return the permissions assigned to a group grantee. |
| */ |
| public Collection<String> getPermissions(URI granteeURI) { |
| return getPermissions(granteeURI.toASCIIString()); |
| } |
| |
| /** |
| * @param granteeId |
| * @param permission |
| * @return true if the grantee has the given permission. |
| */ |
| public boolean hasPermission(String granteeId, String permission) { |
| return getPermissions(granteeId).contains(permission); |
| } |
| |
| /** |
| * @param grantee |
| * @param permission |
| * @return true if the grantee has the given permission. |
| */ |
| public boolean hasPermission(Grantee grantee, String permission) { |
| return hasPermission(grantee.getIdentifier(), permission); |
| } |
| |
| /** |
| * @param granteeURI |
| * @param permission |
| * @return true if the grantee has the given permission. |
| */ |
| public boolean hasPermission(URI granteeURI, String permission) { |
| return getPermissions(granteeURI).contains(permission); |
| } |
| |
| /** |
| * Find all the grants for a given grantee, identified by an ID which allows all Grantee types to |
| * be searched. |
| * |
| * @param granteeId |
| * identifier of a canonical user, email address user, or group. |
| */ |
| protected Collection<Grant> findGrantsForGrantee(final String granteeId) { |
| return Collections2.filter(grants, new Predicate<Grant>() { |
| public boolean apply(Grant g) { |
| return g.getGrantee().getIdentifier().equals(granteeId); |
| } |
| }); |
| } |
| |
| /** |
| * Converts a canned access control policy into the equivalent access control list. |
| * |
| * @param cannedAP |
| * @param ownerId |
| */ |
| public static AccessControlList fromCannedAccessPolicy(CannedAccessPolicy cannedAP, String ownerId) { |
| AccessControlList acl = new AccessControlList(); |
| acl.setOwner(new CanonicalUser(ownerId)); |
| |
| // Canned access policies always allow full control to the owner. |
| acl.addPermission(new CanonicalUserGrantee(ownerId), Permission.FULL_CONTROL); |
| |
| if (CannedAccessPolicy.PRIVATE == cannedAP) { |
| // No more work to do. |
| } else if (CannedAccessPolicy.AUTHENTICATED_READ == cannedAP) { |
| acl.addPermission(GroupGranteeURI.AUTHENTICATED_USERS, Permission.READ); |
| } else if (CannedAccessPolicy.PUBLIC_READ == cannedAP) { |
| acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ); |
| } else if (CannedAccessPolicy.PUBLIC_READ_WRITE == cannedAP) { |
| acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.READ); |
| acl.addPermission(GroupGranteeURI.ALL_USERS, Permission.WRITE); |
| } |
| return acl; |
| } |
| |
| // ///////////////////////////////////////////////////////////////////////////// |
| // Class and Enum declarations to represent Grants, Grantees and Permissions // |
| // ///////////////////////////////////////////////////////////////////////////// |
| |
| public static final class Permission { |
| public static final String READ = "READ"; |
| public static final String WRITE = "WRITE"; |
| public static final String READ_ACP = "READ_ACP"; |
| public static final String WRITE_ACP = "WRITE_ACP"; |
| public static final String FULL_CONTROL = "FULL_CONTROL"; |
| |
| private Permission() { |
| throw new AssertionError("intentionally unimplemented"); |
| } |
| }; |
| |
| public static class Grant implements Comparable<Grant> { |
| |
| private Grantee grantee; |
| private final String permission; |
| |
| public Grant(Grantee grantee, String permission) { |
| this.grantee = grantee; |
| this.permission = permission; |
| } |
| |
| public Grantee getGrantee() { |
| return grantee; |
| } |
| |
| @VisibleForTesting |
| public void setGrantee(Grantee grantee) { |
| this.grantee = grantee; |
| } |
| |
| public String getPermission() { |
| return permission; |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("Grant"); |
| sb.append("{grantee=").append(grantee); |
| sb.append(", permission=").append(permission); |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| public int compareTo(org.jclouds.s3.domain.AccessControlList.Grant o) { |
| if (this == o) { |
| return 0; |
| } else { |
| String myGranteeAndPermission = grantee.getIdentifier() + "\n" + permission; |
| String otherGranteeAndPermission = o.grantee.getIdentifier() + "\n" + o.permission; |
| return myGranteeAndPermission.compareTo(otherGranteeAndPermission); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((grantee == null) ? 0 : grantee.hashCode()); |
| result = prime * result + ((permission == null) ? 0 : permission.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| Grant other = (Grant) obj; |
| if (grantee == null) { |
| if (other.grantee != null) |
| return false; |
| } else if (!grantee.equals(other.grantee)) |
| return false; |
| if (permission == null) { |
| if (other.permission != null) |
| return false; |
| } else if (!permission.equals(other.permission)) |
| return false; |
| return true; |
| } |
| } |
| |
| public abstract static class Grantee implements Comparable<Grantee> { |
| private final String identifier; |
| |
| protected Grantee(String identifier) { |
| this.identifier = identifier; |
| } |
| |
| public String getIdentifier() { |
| return identifier; |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("Grantee"); |
| sb.append("{identifier='").append(identifier).append('\''); |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| public int compareTo(org.jclouds.s3.domain.AccessControlList.Grantee o) { |
| return (this == o) ? 0 : getIdentifier().compareTo(o.getIdentifier()); |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| Grantee other = (Grantee) obj; |
| if (identifier == null) { |
| if (other.identifier != null) |
| return false; |
| } else if (!identifier.equals(other.identifier)) |
| return false; |
| return true; |
| } |
| } |
| |
| public static class EmailAddressGrantee extends Grantee { |
| public EmailAddressGrantee(String emailAddress) { |
| super(emailAddress); |
| } |
| |
| public String getEmailAddress() { |
| return getIdentifier(); |
| } |
| } |
| |
| public static class CanonicalUserGrantee extends Grantee { |
| private final String displayName; |
| |
| public CanonicalUserGrantee(String id, String displayName) { |
| super(id); |
| this.displayName = displayName; |
| } |
| |
| public CanonicalUserGrantee(String id) { |
| this(id, null); |
| } |
| |
| public String getDisplayName() { |
| return displayName; |
| } |
| |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("CanonicalUserGrantee"); |
| sb.append("{displayName='").append(displayName).append('\''); |
| sb.append(", identifier='").append(getIdentifier()).append('\''); |
| |
| sb.append('}'); |
| return sb.toString(); |
| } |
| } |
| |
| public static final class GroupGranteeURI { |
| public static final URI ALL_USERS = URI.create("http://acs.amazonaws.com/groups/global/AllUsers"); |
| public static final URI AUTHENTICATED_USERS = URI |
| .create("http://acs.amazonaws.com/groups/global/AuthenticatedUsers"); |
| public static final URI LOG_DELIVERY = URI.create("http://acs.amazonaws.com/groups/s3/LogDelivery"); |
| |
| private GroupGranteeURI() { |
| throw new AssertionError("intentionally unimplemented"); |
| } |
| } |
| |
| public static class GroupGrantee extends Grantee { |
| |
| public GroupGrantee(URI groupURI) { |
| super(groupURI.toASCIIString()); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("AccessControlList"); |
| sb.append("{owner=").append(owner); |
| sb.append(", grants=").append(grants); |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((grants == null) ? 0 : grants.hashCode()); |
| result = prime * result + ((owner == null) ? 0 : owner.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| AccessControlList other = (AccessControlList) obj; |
| if (grants == null) { |
| if (other.grants != null) |
| return false; |
| } else if (!grants.equals(other.grants)) |
| return false; |
| if (owner == null) { |
| if (other.owner != null) |
| return false; |
| } else if (!owner.equals(other.owner)) |
| return false; |
| return true; |
| } |
| } |