package com.intridea.io.vfs.operations.acl; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; /** * ACL for S3. * Usage samples: * Allow everyone to read: * <code> * acl.allow(Acl.Group.GUEST, Acl.Permission.READ); * </code> * Allow all authorized users to read and write: * <code> * Acl.Permission[] rights = {Acl.Permission.READ, Acl.Permission.WRITE}; * acl.allow(Acl.Group.AUTHORIZED, rights); * </code> * Deny all (owner still has access to overwrite ACL): * <code> * acl.denyAll(); * </code> * * @author Marat Komarov * @author Alex Kovalyov <alex@intridea.com> * */ public class Acl { public static enum Permission { READ, WRITE } public static enum Group { OWNER, AUTHORIZED, EVERYONE }; /** * Number of available groups */ private int groupsCount = Group.values().length; /** * Number of available rules */ private int rulesCount = Permission.values().length; /** * Internal rights holder */ private byte[][] rulesTable; /** * @see {@link #getRules()} */ private Hashtable<Group, Permission[]> rules; /** * Will be True if rules were changed since last {@link #getRules()} call. */ private boolean changed = true; /** * Create new empty ACL. */ public Acl () { this(null); } /** * Create ACL and load rules. * @param rules A set of predefined rules. */ public Acl (Hashtable<Group, Permission[]> rules) { rulesTable = new byte[groupsCount][rulesCount]; if (rules != null) { setRules(rules); } else { denyAll(); } } /** * Allow access for a group * @param group * @param permission */ public void allow (Group group, Permission permission) { setRule(group, permission, (byte) 1); } /** * Set a list of permissions for a group. * @param group * @param permission_list */ public void allow (Group group, Permission[] permission_list) { setRule(group, permission_list, (byte) 1); } /** * Allow all permissions for a group * @param group */ public void allow (Group group) { setRule(group, (byte) 1); } /** * Allow specific permission for all * @param right */ public void allow (Permission permission) { setRule(permission, (byte) 1); } /** * Allow access for all * @param access_list */ public void allow (Permission[] permission_list) { setRule(permission_list, (byte) 1); } /** * Allow all to all */ public void allowAll () { setRule((byte) 1); } /** * Deny right to group * @param group * @param access */ public void deny (Group group, Permission permission) { setRule(group, permission, (byte) 0); } /** * Deny access for a group * @param group * @param right */ public void deny (Group group, Permission[] permission_list) { setRule(group, permission_list, (byte) 0); } /** * Deny all to for a group * @param group */ public void deny (Group group) { setRule(group, (byte) 0); } /** * Deny access for all * @param access */ public void deny (Permission permission) { setRule(permission, (byte) 0); } /** * Deny access for all * @param access */ public void deny (Permission[] permission) { setRule(permission, (byte) 0); } /** * Completely deny. */ public void denyAll () { setRule((byte) 0); } /** * Returns true when a group has specific access. * * @param group * @param access * @return */ public boolean isAllowed (Group group, Permission permission) { return rulesTable[group.ordinal()][permission.ordinal()] == 1; } /** * Returns true when specific access is denied for a group * * @param group * @param access * @return */ public boolean isDenied (Group group, Permission permission) { return rulesTable[group.ordinal()][permission.ordinal()] == 0; } /** * Sets a list of allowed rules. Calls {@link #denyAll()} and then applies rules. * * @param rules Access rule to apply. */ public void setRules (Hashtable<Group, Permission[]> rules) { // Deny all by default denyAll(); // Set allow rules Enumeration<Group> en = rules.keys(); while (en.hasMoreElements()) { Group group = en.nextElement(); Permission[] permissions = rules.get(group); allow(group, permissions); } } /** * Returns a list of allowed rules. * * @return */ public Hashtable<Group, Permission[]> getRules () { if (changed) { rules = new Hashtable<Group, Permission[]>(groupsCount); Permission[] rightValues = Permission.values(); for (Group group : Group.values()) { int groupIndex = group.ordinal(); Vector<Permission> permissions = new Vector<Permission>(); for (int i=0; i<rulesCount; i++) { if (rulesTable[groupIndex][i] == 1) { permissions.add(rightValues[i]); } } rules.put(group, permissions.toArray(new Permission[0])); } } return rules; } /* * Helper methods * */ private void setRule (Group group, Permission permission, byte allow) { rulesTable[group.ordinal()][permission.ordinal()] = allow; changed = true; } private void setRule (Group group, Permission[] permissions, byte allow) { int groupIndex = group.ordinal(); for (Permission permission : permissions) { rulesTable[groupIndex][permission.ordinal()] = allow; } changed = true; } private void setRule (Group group, byte allow) { int groupIndex = group.ordinal(); for (int i=0; i<rulesCount; i++) { rulesTable[groupIndex][i] = allow; } changed = true; } private void setRule (Permission permission, byte allow) { int i = permission.ordinal(); for (int j=0; j<groupsCount; j++) { rulesTable[j][i] = allow; } } private void setRule (Permission[] permissions, byte allow) { for (Permission permission : permissions) { int i = permission.ordinal(); for (int j=0; j<groupsCount; j++) { rulesTable[j][i] = allow; } } } private void setRule (byte allow) { for (int j=0; j<groupsCount; j++) { for (int i=0; i<rulesCount; i++) { rulesTable[j][i] = allow; } } changed = true; } }