/*
* $Id$
*
* Copyright 2007 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.security.basic;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import ome.annotations.PermitAll;
import ome.annotations.RolesAllowed;
import ome.conditions.SecurityViolation;
import ome.security.MethodSecurity;
import ome.security.SecuritySystem;
import ome.services.sessions.SessionManager;
import ome.system.Principal;
import org.springframework.aop.framework.Advised;
/**
* Implementation of {@link MethodSecurity} which checks method security based
* on the {@link RolesAllowed} annotations of our implementation methods. To do
* this, it is necessary to "unwrap" proxies via the {@link Advised} interface.
*
* @author Josh Moore, josh at glencoesoftware.com
* @see SecuritySystem
* @since 3.0-Beta2
*/
public class BasicMethodSecurity implements MethodSecurity {
private final boolean active;
class Info {
RolesAllowed rolesAllowed;
boolean permitAll;
}
private SessionManager sessionManager;
public BasicMethodSecurity() {
this(true);
}
public BasicMethodSecurity(boolean active) {
this.active = active;
}
public void setSessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
/**
* See {@link MethodSecurity#isActive()}
*/
public boolean isActive() {
return active;
}
/**
* @see MethodSecurity#checkMethod(Object, Method, Principal, boolean)
*/
public void checkMethod(Object o, Method m, Principal p, boolean hasPassword) {
String[] allowedRoles = null;
Annotation[] anns;
//
// Map<Method, Info> map = info.get(o.getClass());
// if (map == null) {
// map = new MapMaker().makeMap();
// map.put(o.getClass(), map);
// }
// Info i = map.get(m);
// if (i == null) {
// i.
// }
//
try {
Class<?> c = o.getClass(); // Getting runtime class
while (Advised.class.isAssignableFrom(c)) {
Advised advised = (Advised) o;
o = advised.getTargetSource().getTarget();
c = o.getClass();
}
Method mthd = c.getMethod(m.getName(), m.getParameterTypes());
anns = mthd.getDeclaredAnnotations();
} catch (Exception e) {
throw new SecurityViolation("Invalid method accessed.");
}
for (Annotation annotation : anns) {
if (annotation instanceof RolesAllowed) {
RolesAllowed ra = (RolesAllowed) annotation;
allowedRoles = ra.value();
break; // Can only be one annotation of a type
} else if (annotation instanceof PermitAll) {
return; // EARLY EXIT
}
}
// TODO add exception subclass
if (allowedRoles == null) {
throw new SecurityViolation("This method allows no remote access.");
}
boolean allow = false;
boolean block = false;
List<String> actualRoles = sessionManager.getUserRoles(p.getName());
for (String allowed : allowedRoles) {
//ticket:665
if (actualRoles.contains(allowed)) {
allow = true;
}
// ticket:911
if ("HasPassword".equals(allowed)) {
block = !hasPassword;
}
}
if (block) {
throw new SecurityViolation(
"Bad authentication credentials for this action.\n" +
"See setSecurityPassword for more information");
}
if (!allow) {
throw new SecurityViolation(String.format(
"No matching roles found in %s for session %s (allowed: %s)",
actualRoles, p, Arrays.asList(allowedRoles)));
}
}
}