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:
parent
9d89fc291c
commit
7d7503fc22
7 changed files with 153 additions and 41 deletions
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -37,7 +37,7 @@ public interface Permission {
|
|||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return "java://" + Permission.class.getName() + "#NOT_AUTHORIZED";
|
||||
return "java:" + Permission.class.getName() + "#NOT_AUTHORIZED";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +47,7 @@ public interface Permission {
|
|||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return "java://" + Permission.class.getName();
|
||||
return "java:" + Permission.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,16 +2,24 @@
|
|||
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
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.
|
||||
*
|
||||
* This is not thread-safe, so all Permissions should be added during context
|
||||
|
@ -23,9 +31,35 @@ public class PermissionRegistry {
|
|||
private static final String ATTRIBUTE_NAME = PermissionRegistry.class
|
||||
.getName();
|
||||
|
||||
/**
|
||||
* Has the registry been created yet?
|
||||
*/
|
||||
public static boolean isRegistryCreated(ServletContext ctx) {
|
||||
return ctx.getAttribute(ATTRIBUTE_NAME) instanceof PermissionRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registry from the context. If the context doesn't contain a
|
||||
* registry yet, create one.
|
||||
* 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) {
|
||||
if (ctx == null) {
|
||||
|
@ -33,46 +67,34 @@ public class PermissionRegistry {
|
|||
}
|
||||
|
||||
Object o = ctx.getAttribute(ATTRIBUTE_NAME);
|
||||
if (o instanceof PermissionRegistry) {
|
||||
return (PermissionRegistry) o;
|
||||
}
|
||||
if (o != null) {
|
||||
log.error("Error: PermissionRegistry was set to an "
|
||||
if (o == null) {
|
||||
throw new IllegalStateException(
|
||||
"PermissionRegistry has not been set.");
|
||||
} else if (!(o instanceof PermissionRegistry)) {
|
||||
throw new IllegalStateException("PermissionRegistry was set to an "
|
||||
+ "invalid object: " + o);
|
||||
}
|
||||
|
||||
PermissionRegistry registry = new PermissionRegistry();
|
||||
ctx.setAttribute(ATTRIBUTE_NAME, registry);
|
||||
return registry;
|
||||
return (PermissionRegistry) o;
|
||||
}
|
||||
|
||||
private final Map<String, Permission> permissionsMap = new HashMap<String, Permission>();
|
||||
private final Map<String, Permission> permissionsMap;
|
||||
|
||||
private PermissionRegistry() {
|
||||
// nothing to initialize;
|
||||
public PermissionRegistry(Collection<? extends Permission> permissions) {
|
||||
Map<String, Permission> map = new HashMap<String, Permission>();
|
||||
for (Permission p : permissions) {
|
||||
String uri = p.getUri();
|
||||
if (map.containsKey(uri)) {
|
||||
throw new IllegalStateException("A Permission is already "
|
||||
+ "registered with this URI: '" + uri + "'.");
|
||||
}
|
||||
map.put(uri, p);
|
||||
}
|
||||
this.permissionsMap = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.");
|
||||
}
|
||||
|
||||
String uri = p.getUri();
|
||||
if (isPermission(uri)) {
|
||||
throw new IllegalStateException(
|
||||
"A Permission is already registered with this URI: '" + uri
|
||||
+ "'.");
|
||||
}
|
||||
|
||||
permissionsMap.put(uri, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there already a Permission registered with this URI?
|
||||
* Is there a Permission registered with this URI?
|
||||
*/
|
||||
public boolean isPermission(String 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
|
||||
* 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
|
||||
* this URI, call isPermission() instead.
|
||||
*/
|
||||
public Permission getPermission(String 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct
|
|||
public class SimplePermission implements Permission {
|
||||
private static final Log log = LogFactory.getLog(SimplePermission.class);
|
||||
|
||||
private static final String NAMESPACE = "java://"
|
||||
private static final String NAMESPACE = "java:"
|
||||
+ SimplePermission.class.getName() + "#";
|
||||
|
||||
private static final Map<String, SimplePermission> allInstances = new HashMap<String, SimplePermission>();
|
||||
|
|
|
@ -20,7 +20,7 @@ public class SimpleRequestedAction extends RequestedAction {
|
|||
|
||||
@Override
|
||||
public String getURI() {
|
||||
return "java://" + this.getClass().getName() + "#" + localName;
|
||||
return "java:" + this.getClass().getName() + "#" + localName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces;
|
||||
|
||||
public class RequestActionConstants {
|
||||
public static String actionNamespace = "java://";
|
||||
public static String actionNamespace = "java:";
|
||||
|
||||
public static String SOME_URI = "?SOME_URI";
|
||||
public static String SOME_LITERAL = "?SOME_LITERAL";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue