NIHVIVO-3523 Rewrite the PermissionRegistry to be immutable, and to distribute BrokenPermissions when someone asks for a Permission that doesn't exist.

This commit is contained in:
j2blake 2011-12-19 21:19:58 +00:00
parent 9d89fc291c
commit 7d7503fc22
7 changed files with 153 additions and 41 deletions

View file

@ -0,0 +1,55 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
/**
* This is what the PermissionRegistry hands out if you ask for a Permission
* that it doesn't know about. Nothing is authorized by this Permission.
*/
public class BrokenPermission implements Permission {
private final String uri;
private final String localName;
private final String namespace;
public BrokenPermission(String uri) {
this.uri = uri;
int namespaceBreak = uri.lastIndexOf("#");
if (namespaceBreak == -1) {
namespaceBreak = uri.lastIndexOf("/");
}
int localNameStart = namespaceBreak + 1;
this.namespace = uri.substring(0, localNameStart);
this.localName = uri.substring(localNameStart);
}
@Override
public String getUri() {
return uri;
}
@Override
public String getLocalName() {
return localName;
}
@Override
public String getNamespace() {
return namespace;
}
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
return false;
}
@Override
public String toString() {
return "BrokenPermission[" + uri + "]";
}
}

View file

@ -37,7 +37,7 @@ public interface Permission {
@Override @Override
public String getUri() { public String getUri() {
return "java://" + Permission.class.getName() + "#NOT_AUTHORIZED"; return "java:" + Permission.class.getName() + "#NOT_AUTHORIZED";
} }
@Override @Override
@ -47,7 +47,7 @@ public interface Permission {
@Override @Override
public String getNamespace() { public String getNamespace() {
return "java://" + Permission.class.getName(); return "java:" + Permission.class.getName();
} }
@Override @Override

View file

@ -2,16 +2,24 @@
package edu.cornell.mannlib.vitro.webapp.auth.permissions; package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/** /**
* Holds a map of known Permission objects by URI. Resides in the * An immutable collection of Permission objects, keyed by URI. Resides in the
* ServletContext. * ServletContext.
* *
* This is not thread-safe, so all Permissions should be added during context * This is not thread-safe, so all Permissions should be added during context
@ -24,8 +32,34 @@ public class PermissionRegistry {
.getName(); .getName();
/** /**
* Get the registry from the context. If the context doesn't contain a * Has the registry been created yet?
* registry yet, create one. */
public static boolean isRegistryCreated(ServletContext ctx) {
return ctx.getAttribute(ATTRIBUTE_NAME) instanceof PermissionRegistry;
}
/**
* Create the registry and store it in the context.
*/
public static void createRegistry(ServletContext ctx,
Collection<? extends Permission> permissions) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (permissions == null) {
throw new NullPointerException("permissions may not be null.");
}
if (ctx.getAttribute(ATTRIBUTE_NAME) != null) {
throw new IllegalStateException(
"PermissionRegistry has already been set.");
}
PermissionRegistry registry = new PermissionRegistry(permissions);
ctx.setAttribute(ATTRIBUTE_NAME, registry);
}
/**
* Get the registry from the context. If there isn't one, throw an exception.
*/ */
public static PermissionRegistry getRegistry(ServletContext ctx) { public static PermissionRegistry getRegistry(ServletContext ctx) {
if (ctx == null) { if (ctx == null) {
@ -33,46 +67,34 @@ public class PermissionRegistry {
} }
Object o = ctx.getAttribute(ATTRIBUTE_NAME); Object o = ctx.getAttribute(ATTRIBUTE_NAME);
if (o instanceof PermissionRegistry) { if (o == null) {
return (PermissionRegistry) o; throw new IllegalStateException(
} "PermissionRegistry has not been set.");
if (o != null) { } else if (!(o instanceof PermissionRegistry)) {
log.error("Error: PermissionRegistry was set to an " throw new IllegalStateException("PermissionRegistry was set to an "
+ "invalid object: " + o); + "invalid object: " + o);
} }
PermissionRegistry registry = new PermissionRegistry(); return (PermissionRegistry) o;
ctx.setAttribute(ATTRIBUTE_NAME, registry);
return registry;
} }
private final Map<String, Permission> permissionsMap = new HashMap<String, Permission>(); private final Map<String, Permission> permissionsMap;
private PermissionRegistry() {
// nothing to initialize;
}
/**
* Add a Permission to the registry. If a Permission with the same URI is
* already present, throw an IllegalStateException.
*/
public void addPermission(Permission p) {
if (p == null) {
throw new NullPointerException("p may not be null.");
}
public PermissionRegistry(Collection<? extends Permission> permissions) {
Map<String, Permission> map = new HashMap<String, Permission>();
for (Permission p : permissions) {
String uri = p.getUri(); String uri = p.getUri();
if (isPermission(uri)) { if (map.containsKey(uri)) {
throw new IllegalStateException( throw new IllegalStateException("A Permission is already "
"A Permission is already registered with this URI: '" + uri + "registered with this URI: '" + uri + "'.");
+ "'.");
} }
map.put(uri, p);
permissionsMap.put(uri, p); }
this.permissionsMap = Collections.unmodifiableMap(map);
} }
/** /**
* Is there already a Permission registered with this URI? * Is there a Permission registered with this URI?
*/ */
public boolean isPermission(String uri) { public boolean isPermission(String uri) {
return permissionsMap.containsKey(uri); return permissionsMap.containsKey(uri);
@ -80,14 +102,47 @@ public class PermissionRegistry {
/** /**
* Get the permission that is registered with this URI. If there is no such * Get the permission that is registered with this URI. If there is no such
* Permission, return a dummy Permission that always denies authorization. * Permission, return a BrokenPermission that always denies authorization.
* *
* If you want to know whether an actual Permission has been registered at * If you want to know whether an actual Permission has been registered at
* this URI, call isPermission() instead. * this URI, call isPermission() instead.
*/ */
public Permission getPermission(String uri) { public Permission getPermission(String uri) {
Permission p = permissionsMap.get(uri); Permission p = permissionsMap.get(uri);
return (p == null) ? Permission.NOT_AUTHORIZED : p; if (p == null) {
log.warn("No Permission is registered for '" + uri + "'");
return new BrokenPermission(uri);
} }
return p;
}
// ----------------------------------------------------------------------
// Setup class
// ----------------------------------------------------------------------
public static class Setup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
List<Permission> permissions = new ArrayList<Permission>();
permissions.addAll(SimplePermission.getAllInstances());
PermissionRegistry.createRegistry(ctx, permissions);
ss.info(this, "Created the PermissionRegistry with "
+ permissions.size() + " permissions.");
} catch (Exception e) {
ss.fatal(this, "Failed to initialize the PermissionRegistry.",
e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
sce.getServletContext().removeAttribute(ATTRIBUTE_NAME);
}
}
} }

View file

@ -22,7 +22,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct
public class SimplePermission implements Permission { public class SimplePermission implements Permission {
private static final Log log = LogFactory.getLog(SimplePermission.class); private static final Log log = LogFactory.getLog(SimplePermission.class);
private static final String NAMESPACE = "java://" private static final String NAMESPACE = "java:"
+ SimplePermission.class.getName() + "#"; + SimplePermission.class.getName() + "#";
private static final Map<String, SimplePermission> allInstances = new HashMap<String, SimplePermission>(); private static final Map<String, SimplePermission> allInstances = new HashMap<String, SimplePermission>();

View file

@ -20,7 +20,7 @@ public class SimpleRequestedAction extends RequestedAction {
@Override @Override
public String getURI() { public String getURI() {
return "java://" + this.getClass().getName() + "#" + localName; return "java:" + this.getClass().getName() + "#" + localName;
} }
@Override @Override

View file

@ -3,7 +3,7 @@
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces; package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces;
public class RequestActionConstants { public class RequestActionConstants {
public static String actionNamespace = "java://"; public static String actionNamespace = "java:";
public static String SOME_URI = "?SOME_URI"; public static String SOME_URI = "?SOME_URI";
public static String SOME_LITERAL = "?SOME_LITERAL"; public static String SOME_LITERAL = "?SOME_LITERAL";

View file

@ -34,6 +34,8 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup
# Must run after JenaDataSourceSetup # Must run after JenaDataSourceSetup
edu.cornell.mannlib.vitro.webapp.servlet.setup.ThemeInfoSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.ThemeInfoSetup
edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionRegistry$Setup
edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader
edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper$Setup edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper$Setup