Initial commit.

This commit is contained in:
Ben Alex
2004-03-16 23:57:17 +00:00
commit 35fe1e7b73
267 changed files with 17812 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.aopalliance.intercept.MethodInvocation;
/**
* Makes a final access control (authorization) decision.
*
* @author Ben Alex
* @version $Id$
*/
public interface AccessDecisionManager {
//~ Methods ================================================================
/**
* Resolves an access control decision for the passed parameters.
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @throws AccessDeniedException if access is denied
*/
public void decide(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config)
throws AccessDeniedException;
/**
* Indicates whether this <code>AccessDecisionManager</code> is able to
* process authorization requests presented with the passed
* <code>ConfigAttribute</code>.
*
* <p>
* This allows the <code>SecurityInterceptor</code> to check every
* configuration attribute can be consumed by the configured
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code>.
* </p>
*
* @param attribute a configuration attribute that has been configured
* against the <code>SecurityInterceptor</code>
*
* @return true if this <code>AccessDecisionManager</code> can support the
* passed configuration attribute
*/
public boolean supports(ConfigAttribute attribute);
}

View File

@@ -0,0 +1,40 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an {@link Authentication} object does not hold a required
* authority.
*
* @author Ben Alex
* @version $Id$
*/
public class AccessDeniedException extends AcegiSecurityException {
//~ Constructors ===========================================================
/**
* Constructs an <code>AccessDeniedException</code> with the specified
* message.
*
* @param msg the detail message
*/
public AccessDeniedException(String msg) {
super(msg);
}
/**
* Constructs an <code>AccessDeniedException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public AccessDeniedException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,48 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.springframework.core.NestedRuntimeException;
/**
* Abstract superclass for all exceptions thrown in the security package and
* subpackages.
*
* <p>
* Note that this is a runtime (unchecked) exception. Security exceptions are
* usually fatal; there is no reason for them to be checked.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AcegiSecurityException extends NestedRuntimeException {
//~ Constructors ===========================================================
/**
* Constructs an <code>AcegiSecurityException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t the root cause
*/
public AcegiSecurityException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an <code>AcegiSecurityException</code> with the specified
* message and no root cause.
*
* @param msg the detail message
*/
public AcegiSecurityException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,69 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Represents an authentication request.
*
* <p>
* An <code>Authentication</code> object is not considered authenticated until
* it is processed by an {@link AuthenticationManager}.
* </p>
*
* <p>
* Stored in a request {@link net.sf.acegisecurity.context.SecureContext}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface Authentication {
//~ Methods ================================================================
public void setAuthenticated(boolean isAuthenticated);
/**
* Indicates whether or not authentication was attempted by the {@link
* net.sf.acegisecurity.SecurityInterceptor}. Note that classes should
* not rely on this value as being valid unless it has been set by a
* trusted <code>SecurityInterceptor</code>.
*
* @return true if authenticated by the <code>SecurityInterceptor</code>
*/
public boolean isAuthenticated();
/**
* Set by an <code>AuthenticationManager</code> to indicate the authorities
* that the principal has been granted. Note that classes should not rely
* on this value as being valid unless it has been set by a trusted
* <code>AuthenticationManager</code>.
*
* @return the authorities granted to the principal, or <code>null</code>
* if authentication has not been completed
*/
public GrantedAuthority[] getAuthorities();
/**
* The credentials that prove the principal is correct. This is usually a
* password, but could be anything relevant to the
* <code>AuthenticationManager</code>. Callers are expected to populate
* the credentials.
*
* @return the credentials that prove the identity of the
* <code>Principal</code>
*/
public Object getCredentials();
/**
* The identity of the principal being authenticated. This is usually a
* username. Callers are expected to populate the principal.
*
* @return the <code>Principal</code> being authenticated
*/
public Object getPrincipal();
}

View File

@@ -0,0 +1,42 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an authentication request is rejected because there is no {@link
* Authentication} object in the {@link
* net.sf.acegisecurity.context.SecureContext}.
*
* @author Ben Alex
* @version $Id$
*/
public class AuthenticationCredentialsNotFoundException
extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs an <code>AuthenticationCredentialsNotFoundException</code>
* with the specified message.
*
* @param msg the detail message
*/
public AuthenticationCredentialsNotFoundException(String msg) {
super(msg);
}
/**
* Constructs an <code>AuthenticationCredentialsNotFoundException</code>
* with the specified message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public AuthenticationCredentialsNotFoundException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,41 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Abstract superclass for all exceptions related to the {@link
* AuthenticationManager} being unable to authenticate an {@link
* Authentication} object.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AuthenticationException extends AcegiSecurityException {
//~ Constructors ===========================================================
/**
* Constructs an <code>AuthenticationException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t the root cause
*/
public AuthenticationException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an <code>AuthenticationException</code> with the specified
* message and no root cause.
*
* @param msg the detail message
*/
public AuthenticationException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,61 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Processes an {@link Authentication} request.
*
* @author Ben Alex
* @version $Id$
*/
public interface AuthenticationManager {
//~ Methods ================================================================
/**
* Attempts to authenticate the passed {@link Authentication} object,
* returning a fully populated <code>Authentication</code> object
* (including granted authorities) if successful.
*
* <p>
* An <code>AuthenticationManager</code> must honour the following contract
* concerning exceptions:
* </p>
*
* <p>
* A {@link DisabledException} must be thrown if an account is disabled and
* the <code>AuthenticationManager</code> can test for this state.
* </p>
*
* <p>
* A {@link LockedException} must be thrown if an account is locked and the
* <code>AuthenticationManager</code> can test for account locking.
* </p>
*
* <p>
* A {@link BadCredentialsException} must be thrown if incorrect
* credentials are presented. Whilst the above exceptions are optional, an
* <code>AuthenticationManager</code> must <B>always</B> test credentials.
* </p>
*
* <p>
* Exceptions should be tested for and if applicable thrown in the order
* expressed above (ie if an account is disabled or locked, the
* authentication request is immediately rejected and the credentials
* testing process is not performed). This prevents credentials being
* tested against disabled or locked accounts.
* </p>
*
* @param authentication the authentication request object
*
* @return a fully authenticated object including credentials
*
* @throws AuthenticationException if authentication fails
*/
public Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}

View File

@@ -0,0 +1,44 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an authentication request could not be processed due to a system
* problem.
*
* <p>
* This might be thrown if a backend authentication repository is unavailable.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AuthenticationServiceException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs an <code>AuthenticationServiceException</code> with the
* specified message.
*
* @param msg the detail message
*/
public AuthenticationServiceException(String msg) {
super(msg);
}
/**
* Constructs an <code>AuthenticationServiceException</code> with the
* specified message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public AuthenticationServiceException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,41 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an authentication request is rejected because the credentials are
* invalid. For this exception to be thrown, it means the account is neither
* locked nor disabled.
*
* @author Ben Alex
* @version $Id$
*/
public class BadCredentialsException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message.
*
* @param msg the detail message
*/
public BadCredentialsException(String msg) {
super(msg);
}
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public BadCredentialsException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,53 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Stores a security system related configuration attribute.
*
* <p>
* When the {@link SecurityInterceptor} is setup, a list of configuration
* attributes is defined for secure method patterns. These configuration
* attributes have special meaning to a {@link RunAsManager}, {@link
* AccessDecisionManager} or <code>AccessDecisionManager</code> delegate.
* </p>
*
* <P>
* Stored at runtime with other <code>ConfigAttribute</code>s for the same
* method within a {@link ConfigAttributeDefinition}.
* </p>
*
* @author <A HREF="mailto:ben.alex@fremerx.com">Ben Alex</A>
* @version $Id$
*/
public interface ConfigAttribute {
//~ Methods ================================================================
/**
* If the <code>ConfigAttribute</code> can be represented as a
* <code>String</code> and that <code>String</code> is sufficient in
* precision to be relied upon as a configuration parameter by a {@link
* RunAsManager}, {@link AccessDecisionManager} or
* <code>AccessDecisionManager</code> delegate, this method should return
* such a <code>String</code>.
*
* <p>
* If the <code>ConfigAttribute</code> cannot be expressed with sufficient
* precision as a <code>String</code>, <code>null</code> should be
* returned. Returning <code>null</code> will require an relying classes
* to specifically support the <code>ConfigAttribute</code>
* implementation, so returning <code>null</code> should be avoided
* unless actually required.
* </p>
*
* @return a representation of the configuration attribute (or
* <code>null</code> if the configuration attribute cannot be
* expressed as a <code>String</code> with sufficient precision).
*/
public String getAttribute();
}

View File

@@ -0,0 +1,62 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Holds a group of {@link ConfigAttribute}s that are associated with a given
* method.
*
* <p>
* All the <code>ConfigAttributeDefinition</code>s associated with a given
* <code>SecurityInterceptor</code> are stored in a {@link
* MethodDefinitionMap}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class ConfigAttributeDefinition {
//~ Instance fields ========================================================
private Set configAttributes = new HashSet();
//~ Constructors ===========================================================
public ConfigAttributeDefinition() {
super();
}
//~ Methods ================================================================
/**
* DOCUMENT ME!
*
* @return all the configuration attributes related to the method.
*/
public Iterator getConfigAttributes() {
return this.configAttributes.iterator();
}
/**
* Adds a <code>ConfigAttribute</code> that is related to the method.
*
* @param newConfigAttribute DOCUMENT ME!
*/
public void addConfigAttribute(ConfigAttribute newConfigAttribute) {
this.configAttributes.add(newConfigAttribute);
}
public String toString() {
return this.configAttributes.toString();
}
}

View File

@@ -0,0 +1,39 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
/**
* A property editor that can create a populated {@link
* ConfigAttributeDefinition} from a comma separated list of values.
*
* @author Ben Alex
* @version $Id$
*/
public class ConfigAttributeEditor extends PropertyEditorSupport {
//~ Methods ================================================================
public void setAsText(String s) throws IllegalArgumentException {
if ((s == null) || "".equals(s)) {
setValue(null);
} else {
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
for (int i = 0; i < tokens.length; i++) {
configDefinition.addConfigAttribute(new SecurityConfig(tokens[i]));
}
setValue(configDefinition);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an authentication request is rejected because the account is
* disabled. Makes no assertion as to whether or not the credentials were
* valid.
*
* @author Ben Alex
* @version $Id$
*/
public class DisabledException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>DisabledException</code> with the specified message.
*
* @param msg the detail message
*/
public DisabledException(String msg) {
super(msg);
}
/**
* Constructs a <code>DisabledException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public DisabledException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,46 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Represents an authority granted to an {@link Authentication} object.
*
* <p>
* A <code>GrantedAuthority</code> must either represent itself as a
* <code>String</code> or be specifically supported by an {@link
* AccessDecisionManager}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface GrantedAuthority {
//~ Methods ================================================================
/**
* If the <code>GrantedAuthority</code> can be represented as a
* <code>String</code> and that <code>String</code> is sufficient in
* precision to be relied upon for an access control decision by an {@link
* AccessDecisionManager} (or delegate), this method should return such a
* <code>String</code>.
*
* <p>
* If the <code>GrantedAuthority</code> cannot be expressed with sufficient
* precision as a <code>String</code>, <code>null</code> should be
* returned. Returning <code>null</code> will require an
* <code>AccessDecisionManager</code> (or delegate) to specifically
* support the <code>GrantedAuthority</code> implementation, so returning
* <code>null</code> should be avoided unless actually required.
* </p>
*
* @return a representation of the granted authority (or <code>null</code>
* if the granted authority cannot be expressed as a
* <code>String</code> with sufficient precision).
*/
public String getAuthority();
}

View File

@@ -0,0 +1,64 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Basic concrete implementation of a {@link GrantedAuthority}.
*
* <p>
* Stores a <code>String</code> representation of an authority granted to the
* {@link Authentication} object.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class GrantedAuthorityImpl implements GrantedAuthority {
//~ Instance fields ========================================================
private String role;
//~ Constructors ===========================================================
public GrantedAuthorityImpl(String role) {
super();
this.role = role;
}
private GrantedAuthorityImpl() {
super();
}
//~ Methods ================================================================
public String getAuthority() {
return this.role;
}
public boolean equals(Object obj) {
if (obj instanceof String) {
return obj.equals(this.role);
}
if (obj instanceof GrantedAuthority) {
GrantedAuthority attr = (GrantedAuthority) obj;
return this.role.equals(attr.getAuthority());
}
return false;
}
public int hashCode() {
return this.role.hashCode();
}
public String toString() {
return this.role;
}
}

View File

@@ -0,0 +1,39 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Thrown if an authentication request is rejected because the account is
* locked. Makes no assertion as to whether or not the credentials were valid.
*
* @author Ben Alex
* @version $Id$
*/
public class LockedException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>LockedException</code> with the specified message.
*
* @param msg the detail message.
*/
public LockedException(String msg) {
super(msg);
}
/**
* Constructs a <code>LockedException</code> with the specified message and
* root cause.
*
* @param msg the detail message.
* @param t root cause
*/
public LockedException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,116 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.metadata.Attributes;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
/**
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
* by Commons Attributes.
*
* @author Cameron Braid
* @author Ben Alex
* @version $Id$
*/
public class MethodDefinitionAttributes implements MethodDefinitionSource {
//~ Instance fields ========================================================
private Attributes attributes;
//~ Methods ================================================================
public void setAttributes(Attributes attributes) {
this.attributes = attributes;
}
public ConfigAttributeDefinition getAttributes(MethodInvocation invocation) {
ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
Class interceptedClass = invocation.getMethod().getDeclaringClass();
// add the class level attributes for the implementing class
addClassAttributes(definition, interceptedClass);
// add the class level attributes for the implemented interfaces
addClassAttributes(definition, interceptedClass.getInterfaces());
// add the method level attributes for the implemented method
addMethodAttributes(definition, invocation.getMethod());
// add the method level attributes for the implemented intreface methods
addInterfaceMethodAttributes(definition, invocation.getMethod());
return definition;
}
public Iterator getConfigAttributeDefinitions() {
return null;
}
private void add(ConfigAttributeDefinition definition, Collection attribs) {
for (Iterator iter = attribs.iterator(); iter.hasNext();) {
Object o = (Object) iter.next();
if (o instanceof ConfigAttribute) {
definition.addConfigAttribute((ConfigAttribute) o);
}
}
}
private void addClassAttributes(ConfigAttributeDefinition definition,
Class clazz) {
addClassAttributes(definition, new Class[] {clazz});
}
private void addClassAttributes(ConfigAttributeDefinition definition,
Class[] clazz) {
for (int i = 0; i < clazz.length; i++) {
Collection classAttributes = attributes.getAttributes(clazz[i]);
if (classAttributes != null) {
add(definition, classAttributes);
}
}
}
private void addInterfaceMethodAttributes(ConfigAttributeDefinition definition,
Method method) {
Class[] interfaces = method.getDeclaringClass().getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Class clazz = interfaces[i];
try {
Method m = clazz.getDeclaredMethod(method.getName(),
method.getParameterTypes());
addMethodAttributes(definition, m);
} catch (Exception e) {
// this won't happen since we are getting a method from an interface that
// the declaring class implements
}
}
}
private void addMethodAttributes(ConfigAttributeDefinition definition,
Method method) {
// add the method level attributes
Collection methodAttributes = attributes.getAttributes(method);
if (methodAttributes != null) {
add(definition, methodAttributes);
}
}
}

View File

@@ -0,0 +1,181 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
* in a bean context.
*
* @author Ben Alex
* @version $Id$
*/
public class MethodDefinitionMap implements MethodDefinitionSource {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(MethodDefinitionMap.class);
//~ Instance fields ========================================================
/** Map from Method to ApplicationDefinition */
protected Map methodMap = new HashMap();
/** Map from Method to name pattern used for registration */
private Map nameMap = new HashMap();
//~ Methods ================================================================
public ConfigAttributeDefinition getAttributes(MethodInvocation invocation) {
return (ConfigAttributeDefinition) this.methodMap.get(invocation
.getMethod());
}
public Iterator getConfigAttributeDefinitions() {
return methodMap.values().iterator();
}
/**
* Add required authorities for a secure method. Method names can end or
* start with "" for matching multiple methods.
*
* @param method the method to be secured
* @param attr required authorities associated with the method
*/
public void addSecureMethod(Method method, ConfigAttributeDefinition attr) {
logger.info("Adding secure method [" + method + "] with attributes ["
+ attr + "]");
this.methodMap.put(method, attr);
}
/**
* Add required authorities for a secure method. Method names can end or
* start with "" for matching multiple methods.
*
* @param name class and method name, separated by a dot
* @param attr required authorities associated with the method
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
int lastDotIndex = name.lastIndexOf(".");
if (lastDotIndex == -1) {
throw new IllegalArgumentException("'" + name
+ "' is not a valid method name: format is FQN.methodName");
}
String className = name.substring(0, lastDotIndex);
String methodName = name.substring(lastDotIndex + 1);
try {
Class clazz = Class.forName(className, true,
Thread.currentThread()
.getContextClassLoader());
addSecureMethod(clazz, methodName, attr);
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Class '" + className
+ "' not found");
}
}
/**
* Add required authorities for a secure method. Method names can end or
* start with "" for matching multiple methods.
*
* @param clazz target interface or class
* @param mappedName mapped method name
* @param attr required authorities associated with the method
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public void addSecureMethod(Class clazz, String mappedName,
ConfigAttributeDefinition attr) {
String name = clazz.getName() + '.' + mappedName;
if (logger.isDebugEnabled()) {
logger.debug("Adding secure method [" + name
+ "] with attributes [" + attr + "]");
}
Method[] methods = clazz.getDeclaredMethods();
List matchingMethods = new ArrayList();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(mappedName)
|| isMatch(methods[i].getName(), mappedName)) {
matchingMethods.add(methods[i]);
}
}
if (matchingMethods.isEmpty()) {
throw new IllegalArgumentException("Couldn't find method '"
+ mappedName + "' on " + clazz);
}
// register all matching methods
for (Iterator it = matchingMethods.iterator(); it.hasNext();) {
Method method = (Method) it.next();
String regMethodName = (String) this.nameMap.get(method);
if ((regMethodName == null)
|| (!regMethodName.equals(name)
&& (regMethodName.length() <= name.length()))) {
// no already registered method name, or more specific
// method name specification now -> (re-)register method
if (logger.isDebugEnabled() && (regMethodName != null)) {
logger.debug("Replacing attributes for secure method ["
+ method + "]: current name [" + name
+ "] is more specific than [" + regMethodName
+ "]");
}
this.nameMap.put(method, name);
addSecureMethod(method, attr);
} else {
if (logger.isDebugEnabled() && (regMethodName != null)) {
logger.debug("Keeping attributes for secure method ["
+ method + "]: current name [" + name
+ "] is not more specific than ["
+ regMethodName + "]");
}
}
}
}
/**
* Return if the given method name matches the mapped name. The default
* implementation checks for "xxx" and "xxx" matches.
*
* @param methodName the method name of the class
* @param mappedName the name in the descriptor
*
* @return if the names match
*/
private boolean isMatch(String methodName, String mappedName) {
return (mappedName.endsWith("*")
&& methodName.startsWith(mappedName.substring(0,
mappedName.length()
- 1)))
|| (mappedName.startsWith("*")
&& methodName.endsWith(mappedName.substring(1,
mappedName.length())));
}
}

View File

@@ -0,0 +1,44 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.aopalliance.intercept.MethodInvocation;
import java.util.Iterator;
/**
* Implemented by classes that store {@link ConfigAttributeDefinition}s and can
* identify the appropriate <code>ConfigAttributeDefinition</code> that
* applies for the current method call.
*
* @author Ben Alex
* @version $Id$
*/
public interface MethodDefinitionSource {
//~ Methods ================================================================
/**
* DOCUMENT ME!
*
* @param invocation the method being called
*
* @return the <code>ConfigAttributeDefinition</code> that applies to the
* passed method call
*/
public ConfigAttributeDefinition getAttributes(MethodInvocation invocation);
/**
* If available, all of the <code>ConfigAttributeDefinition</code>s defined
* by the implementing class.
*
* @return an iterator over all the <code>ConfigAttributeDefinition</code>s
* or <code>null</code> if unsupported
*/
public Iterator getConfigAttributeDefinitions();
}

View File

@@ -0,0 +1,70 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import java.beans.PropertyEditorSupport;
import java.util.Iterator;
import java.util.Properties;
/**
* Property editor to assist with the setup of {@link MethodDefinitionSource}.
*
* <p>
* The class creates and populates an {@link MethodDefinitionMap}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class MethodDefinitionSourceEditor extends PropertyEditorSupport {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(MethodDefinitionSourceEditor.class);
//~ Methods ================================================================
public void setAsText(String s) throws IllegalArgumentException {
MethodDefinitionMap source = new MethodDefinitionMap();
if ((s == null) || "".equals(s)) {
// Leave value in property editor null
} else {
// Use properties editor to tokenize the string
PropertiesEditor propertiesEditor = new PropertiesEditor();
propertiesEditor.setAsText(s);
Properties props = (Properties) propertiesEditor.getValue();
// Now we have properties, process each one individually
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String value = props.getProperty(name);
// Convert value to series of security configuration attributes
configAttribEd.setAsText(value);
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd
.getValue();
// Register name and attribute
source.addSecureMethod(name, attr);
}
}
setValue(source);
}
}

View File

@@ -0,0 +1,90 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import org.aopalliance.intercept.MethodInvocation;
/**
* Creates a new temporary {@link Authentication} object for the current method
* invocation only.
*
* <P>
* This interface permits implementations to replace the
* <code>Authentication</code> object that applies to the current method
* invocation only. The {@link SecurityInterceptor} will replace the
* <code>Authentication</code> object held in the {@link
* net.sf.acegisecurity.context.SecureContext} for the duration of the method
* invocation only, returning it to the original <code>Authentication</code>
* object when the method invocation completes.
* </p>
*
* <P>
* This is provided so that systems with two layers of objects can be
* established. One layer is public facing and has normal secure methods with
* the granted authorities expected to be held by external callers. The other
* layer is private, and is only expected to be called by objects within the
* public facing layer. The objects in this private layer still need security
* (otherwise they would be public methods) and they also need security in
* such a manner that prevents them being called directly by external callers.
* The objects in the private layer would be configured to require granted
* authorities never granted to external callers. The
* <code>RunAsManager</code> interface provides a mechanism to elevate
* security in this manner.
* </p>
*
* <p>
* It is expected implementations will provide a corresponding concrete
* <code>Authentication</code> and <code>AuthenticationProvider</code> so that
* the replacement <code>Authentication</code> object can be authenticated.
* Some form of security will need to be implemented to prevent to ensure the
* <code>AuthenticationProvider</code> only accepts
* <code>Authentication</code> objects created by an authorized concrete
* implementation of <code>RunAsManager</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface RunAsManager {
//~ Methods ================================================================
/**
* Returns a replacement <code>Authentication</code> object for the current
* method invocation, or <code>null</code> if replacement not required.
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @return a replacement object to be used for duration of the method
* invocation
*/
public Authentication buildRunAs(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config);
/**
* Indicates whether this <code>RunAsManager</code> is able to process the
* passed <code>ConfigAttribute</code>.
*
* <p>
* This allows the <code>SecurityInterceptor</code> to check every
* configuration attribute can be consumed by the configured
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code>.
* </p>
*
* @param attribute a configuration attribute that has been configured
* against the <code>SecurityInterceptor</code>
*
* @return true if this <code>RunAsManager</code> can support the passed
* configuration attribute
*/
public boolean supports(ConfigAttribute attribute);
}

View File

@@ -0,0 +1,58 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
/**
* Stores a {@link ConfigAttribute} as a <code>String</code>.
*
* @author <A HREF="mailto:ben.alex@fremerx.com">Ben Alex</A>
* @version $Id$
*/
public class SecurityConfig implements ConfigAttribute {
//~ Instance fields ========================================================
private String attrib;
//~ Constructors ===========================================================
public SecurityConfig(String config) {
this.attrib = config;
}
private SecurityConfig() {
super();
}
//~ Methods ================================================================
public String getAttribute() {
return this.attrib;
}
public boolean equals(Object obj) {
if (obj instanceof String) {
return obj.equals(this.attrib);
}
if (obj instanceof ConfigAttribute) {
ConfigAttribute attr = (ConfigAttribute) obj;
return this.attrib.equals(attr.getAttribute());
}
return false;
}
public int hashCode() {
return this.attrib.hashCode();
}
public String toString() {
return this.attrib;
}
}

View File

@@ -0,0 +1,303 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity;
import net.sf.acegisecurity.context.Context;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Intercepts calls to an object and applies security.
*
* <p>
* A method is treated as public unless it has one or more configuration
* attributes defined via {@link
* #setMethodDefinitionSource(MethodDefinitionSource)}. If public, no
* authentication will be attempted, which means an unauthenticated {@link
* Authentication} object may be present in the {@link ContextHolder} (if any
* such an unauthenticated <code>Authentication</code> object exists, its
* {@link Authentication#isAuthenticated()} method will return
* <code>false</code> once the <code>SecurityInterceptor</code> has
* intercepted the public method).
* </p>
*
* <p>
* For those methods to be secured by the interceptor, one or more
* configuration attributes must be defined. These attributes are stored as
* {@link ConfigAttribute} objects.
* </p>
*
* <p>
* The presence of a configuration attribute for a given method will force
* authentication to be attempted via the {@link AuthenticationManager}
* configured against the interceptor. If successfully authenticated, the
* configured {@link AccessDecisionManager} will be passed the {@link
* ConfigAttributeDefinition} applicable for the method invocation, the
* method invocation itself, and the <code>Authentication</code> object. The
* <code>AccessDecisionManager</code> which will then make the authorization
* decision.
* </p>
*
* <p>
* There shouldn't be any requirement to customise the behaviour of the
* <code>SecurityInterceptor</code>, as all security decisions are made by the
* <code>AuthenticationProvider</code> and <code>AccessDecisionManager</code>
* interfaces, which can of course be replaced with different concrete
* implementations.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class SecurityInterceptor implements MethodInterceptor, InitializingBean {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(SecurityInterceptor.class);
//~ Instance fields ========================================================
private AccessDecisionManager accessDecisionManager;
private AuthenticationManager authenticationManager;
private MethodDefinitionSource methodDefinitionSource;
private RunAsManager runAsManager;
private boolean validateConfigAttributes = true;
//~ Methods ================================================================
public void setAccessDecisionManager(
AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
}
public AccessDecisionManager getAccessDecisionManager() {
return accessDecisionManager;
}
public void setAuthenticationManager(AuthenticationManager newManager) {
this.authenticationManager = newManager;
}
public AuthenticationManager getAuthenticationManager() {
return this.authenticationManager;
}
public void setMethodDefinitionSource(MethodDefinitionSource newSource) {
this.methodDefinitionSource = newSource;
}
public MethodDefinitionSource getMethodDefinitionSource() {
return this.methodDefinitionSource;
}
public void setRunAsManager(RunAsManager runAsManager) {
this.runAsManager = runAsManager;
}
public RunAsManager getRunAsManager() {
return runAsManager;
}
public void setValidateConfigAttributes(boolean validateConfigAttributes) {
this.validateConfigAttributes = validateConfigAttributes;
}
public boolean isValidateConfigAttributes() {
return validateConfigAttributes;
}
public void afterPropertiesSet() {
if (this.authenticationManager == null) {
throw new IllegalArgumentException(
"An AuthenticationManager is required");
}
if (this.accessDecisionManager == null) {
throw new IllegalArgumentException(
"An AccessDecisionManager is required");
}
if (this.runAsManager == null) {
throw new IllegalArgumentException("A RunAsManager is required");
}
if (this.methodDefinitionSource == null) {
throw new IllegalArgumentException(
"A MethodDefinitionSource is required");
}
if (this.validateConfigAttributes) {
Iterator iter = this.methodDefinitionSource
.getConfigAttributeDefinitions();
if (iter == null) {
if (logger.isWarnEnabled()) {
logger.warn(
"Could not validate configuration attributes as the MethodDefinitionSource did not return a ConfigAttributeDefinition Iterator");
}
return;
}
Set set = new HashSet();
while (iter.hasNext()) {
ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter
.next();
Iterator attributes = def.getConfigAttributes();
while (attributes.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) attributes.next();
if (!this.runAsManager.supports(attr)
&& !this.accessDecisionManager.supports(attr)) {
set.add(attr);
}
}
}
if (set.size() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Validated configuration attributes");
}
} else {
throw new IllegalArgumentException(
"Unsupported configuration attributes: " + set.toString());
}
}
}
/**
* Does the work of authenticating and authorizing the request. Throws
* {@link AcegiSecurityException} and its subclasses.
*
* @param mi The method being invoked which requires a security decision
*
* @return The returned value from the method invocation
*
* @throws Throwable if any error occurs
* @throws AuthenticationCredentialsNotFoundException if the
* <code>ContextHolder</code> does not contain a valid
* <code>SecureContext</code> which in turn contains an
* <code>Authentication</code> object
*/
public Object invoke(MethodInvocation mi) throws Throwable {
ConfigAttributeDefinition attr = this.methodDefinitionSource
.getAttributes(mi);
if (attr != null) {
if (logger.isDebugEnabled()) {
logger.debug("Secure method configuration "
+ attr.getConfigAttributes().toString());
}
// Ensure ContextHolder presents a populated SecureContext
if ((ContextHolder.getContext() == null)
|| !(ContextHolder.getContext() instanceof SecureContext)) {
throw new AuthenticationCredentialsNotFoundException(
"A valid SecureContext was not provided in the RequestContext");
}
SecureContext context = (SecureContext) ContextHolder.getContext();
if (context.getAuthentication() == null) {
throw new AuthenticationCredentialsNotFoundException(
"Authentication credentials were not found in the SecureContext");
}
// Attempt authentication
Authentication authenticated = this.authenticationManager
.authenticate(context.getAuthentication());
authenticated.setAuthenticated(true);
logger.debug("Authenticated: " + authenticated.toString());
context.setAuthentication(authenticated);
ContextHolder.setContext((Context) context);
// Attempt authorization
this.accessDecisionManager.decide(authenticated, mi, attr);
if (logger.isDebugEnabled()) {
logger.debug("Authorization successful");
}
// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated,
mi, attr);
if (runAs == null) {
if (logger.isDebugEnabled()) {
logger.debug(
"RunAsManager did not change Authentication object");
}
Object ret = mi.proceed();
return ret;
} else {
if (logger.isDebugEnabled()) {
logger.debug("Switching to RunAs Authentication: "
+ runAs.toString());
}
context.setAuthentication(runAs);
ContextHolder.setContext((Context) context);
Object ret = mi.proceed();
if (logger.isDebugEnabled()) {
logger.debug("Reverting to original Authentication: "
+ authenticated.toString());
}
context.setAuthentication(authenticated);
ContextHolder.setContext((Context) context);
return ret;
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Public method - authentication not attempted");
}
// Set Authentication object (if it exists) to be unauthenticated
if ((ContextHolder.getContext() != null)
&& ContextHolder.getContext() instanceof SecureContext) {
SecureContext context = (SecureContext) ContextHolder
.getContext();
if (context.getAuthentication() != null) {
if (logger.isDebugEnabled()) {
logger.debug(
"Authentication object detected and tagged as unauthenticated");
}
Authentication authenticated = context.getAuthentication();
authenticated.setAuthenticated(false);
context.setAuthentication(authenticated);
ContextHolder.setContext((Context) context);
}
}
Object ret = mi.proceed();
return ret;
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
/**
* Convenience superclass for {@link AuthByAdapter} implementations.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractAdapterAuthenticationToken
extends AbstractAuthenticationToken implements AuthByAdapter {
//~ Instance fields ========================================================
private GrantedAuthority[] authorities;
private int keyHash;
//~ Constructors ===========================================================
protected AbstractAdapterAuthenticationToken() {
super();
}
/**
* The only way an <code>AbstractAdapterAuthentication</code> should be
* constructed.
*
* @param key the key that is hashed and made available via {@link
* #getKeyHash()}
* @param authorities the authorities granted to this principal
*/
protected AbstractAdapterAuthenticationToken(String key,
GrantedAuthority[] authorities) {
super();
this.keyHash = key.hashCode();
this.authorities = authorities;
}
//~ Methods ================================================================
/**
* Setting is ignored. Always considered authenticated.
*
* @param ignored DOCUMENT ME!
*/
public void setAuthenticated(boolean ignored) {
// ignored
}
/**
* Always returns <code>true</code>.
*
* @return DOCUMENT ME!
*/
public boolean isAuthenticated() {
return true;
}
public GrantedAuthority[] getAuthorities() {
return authorities;
}
public int getKeyHash() {
return this.keyHash;
}
/**
* Iterates the granted authorities and indicates whether or not the
* specified role is held.
*
* <p>
* Comparison is based on the <code>String</code> returned by {@link
* GrantedAuthority#getAuthority}.
* </p>
*
* @param role the role being searched for in this object's granted
* authorities list
*
* @return <code>true</code> if the granted authority is held, or
* <code>false</code> otherwise
*/
public boolean isUserInRole(String role) {
for (int i = 0; i < this.authorities.length; i++) {
if (role.equals(this.authorities[i].getAuthority())) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,146 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.context.Context;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import net.sf.acegisecurity.context.SecureContextImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Automatically populates a {@link net.sf.acegisecurity.context.SecureContext}
* from a subclass-provided container source.
*
* <p>
* The container is expected to expose an {@link Authentication} object in a
* well-known location. The <code>Authentication</code> object will have been
* created by the container-specific Acegi Security System for Spring adapter.
* </p>
*
* <P>
* Once the <code>Authentication</code> object has been extracted from the
* well-known location, the interceptor handles putting it into the {@link
* ContextHolder}. It then removes it once the filter chain has completed.
* </p>
*
* <p>
* This interceptor will not operate if the container does not provide an
* <code>Authentication</code> object from its well-known location.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractIntegrationFilter implements Filter {
//~ Static fields/initializers =============================================
protected static final Log logger = LogFactory.getLog(AbstractIntegrationFilter.class);
//~ Methods ================================================================
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// Populate authentication information
Object extracted = this.extractFromContainer(request);
if (extracted instanceof Authentication) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication added to ContextHolder from container");
}
Authentication auth = (Authentication) extracted;
// Get or create existing SecureContext
SecureContext secureContext = null;
if ((ContextHolder.getContext() == null)
|| !(ContextHolder.getContext() instanceof SecureContext)) {
secureContext = new SecureContextImpl();
} else {
secureContext = (SecureContext) ContextHolder.getContext();
}
// Add Authentication to SecureContext, and save
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Authentication not added to ContextHolder (could not extract an authentication object from the container which is an instance of Authentication)");
}
}
// Proceed with chain
chain.doFilter(request, response);
// Remove authentication information
if ((ContextHolder.getContext() != null)
&& ContextHolder.getContext() instanceof SecureContext) {
if (logger.isDebugEnabled()) {
logger.debug("Removing Authentication from ContextHolder");
}
// Get context holder and remove authentication information
SecureContext secureContext = (SecureContext) ContextHolder
.getContext();
secureContext.setAuthentication(null);
ContextHolder.setContext((Context) secureContext);
} else {
if (logger.isDebugEnabled()) {
logger.debug("ContextHolder does not contain any authentication information");
}
}
}
/**
* Subclasses must override this method to provide the <code>Object</code>
* that contains the <code>Authentication</code> interface.
*
* <p>
* For convenience we have allowed any <code>Object</code> to be returned
* by subclasses, as the abstract class will ensure class casting safety
* and ignore objects that do not implement <code>Authentication</code>.
* </p>
*
* <p>
* If no authentication object is available, subclasses should return
* <code>null</code>.
* </p>
*
* <p>
* If the container can locate multiple authentication objects, subclasses
* should return the object that was created by the Acegi Security System
* for Spring adapter (ie that implements <code>Authentication</code>).
* </p>
*
* @param request the request, which may be of use in extracting the
* authentication object
*
* @return <code>null</code> or an object that implements
* <code>Authentication</code>
*/
public abstract Object extractFromContainer(ServletRequest request);
public void init(FilterConfig filterConfig) throws ServletException {}
}

View File

@@ -0,0 +1,35 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.Authentication;
/**
* Indicates a specialized, immutable, server-side only {@link Authentication}
* class.
*
* <P>
* Automatically considered valid by the {@link AuthByAdapterProvider},
* provided the hash code presented by the implementation objects matches that
* expected by the <code>AuthByAdapterProvider</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface AuthByAdapter extends Authentication {
//~ Methods ================================================================
/**
* DOCUMENT ME!
*
* @return the hash code of the key used when the object was created.
*/
public int getKeyHash();
}

View File

@@ -0,0 +1,77 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import org.springframework.beans.factory.InitializingBean;
/**
* An {@link AuthenticationProvider} implementation that can authenticate an
* {@link AuthByAdapter}.
*
* <P>
* Configured in the bean context with a key that should match the key used by
* adapters to generate <code>AuthByAdapter</code> instances. It treats as
* valid any such instance presenting a hash code that matches the
* <code>AuthByAdapterProvider</code>-configured key.
* </p>
*
* <P>
* If the key does not match, a <code>BadCredentialsException</code> is
* thrown.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AuthByAdapterProvider implements InitializingBean,
AuthenticationProvider {
//~ Instance fields ========================================================
private String key;
//~ Methods ================================================================
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void afterPropertiesSet() throws Exception {
if (key == null) {
throw new IllegalArgumentException("A Key is required and should match that configured for the adapters");
}
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
AuthByAdapter token = (AuthByAdapter) authentication;
if (token.getKeyHash() == key.hashCode()) {
return authentication;
} else {
throw new BadCredentialsException("The presented AuthByAdapter implementation does not contain the expected key");
}
}
public boolean supports(Class authentication) {
if (AuthByAdapter.class.isAssignableFrom(authentication)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.adapters.jboss.JbossIntegrationFilter;
import org.jboss.security.SimplePrincipal;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Detects the container and delegates to the appropriate {@link
* AbstractIntegrationFilter}.
*
* <p>
* This eases the creation of portable secured Spring applications, as the
* <code>web.xml</code> will not need to refer to a specific container
* integration filter.
* </p>
*
* <p>
* See {@link AbstractIntegrationFilter} for further information.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AutoIntegrationFilter extends AbstractIntegrationFilter {
//~ Methods ================================================================
public Object extractFromContainer(ServletRequest request) {
if (request instanceof HttpServletRequest) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (httpRequest.getUserPrincipal() instanceof Authentication) {
return new HttpRequestIntegrationFilter().extractFromContainer(request);
}
if (httpRequest.getUserPrincipal() instanceof SimplePrincipal) {
return new JbossIntegrationFilter().extractFromContainer(request);
}
}
return null;
}
}

View File

@@ -0,0 +1,42 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Populates a {@link net.sf.acegisecurity.context.SecureContext} from the
* container's <code>HttpServletRequest.getUserPrincipal()</code>.
*
* <p>
* See {@link AbstractIntegrationFilter} for further information.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class HttpRequestIntegrationFilter extends AbstractIntegrationFilter {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(HttpRequestIntegrationFilter.class);
//~ Methods ================================================================
public Object extractFromContainer(ServletRequest request) {
if (request instanceof HttpServletRequest) {
return ((HttpServletRequest) request).getUserPrincipal();
} else {
return null;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.adapters;
import net.sf.acegisecurity.GrantedAuthority;
import java.security.Principal;
/**
* A {@link Principal} compatible {@link net.sf.acegisecurity.Authentication}
* object.
*
* @author Ben Alex
* @version $Id$
*/
public class PrincipalAcegiUserToken extends AbstractAdapterAuthenticationToken
implements Principal {
//~ Instance fields ========================================================
private String password;
private String username;
//~ Constructors ===========================================================
public PrincipalAcegiUserToken(String key, String username,
String password, GrantedAuthority[] authorities) {
super(key, authorities);
this.username = username;
this.password = password;
}
private PrincipalAcegiUserToken() {
super();
}
//~ Methods ================================================================
public Object getCredentials() {
return this.password;
}
public String getName() {
return this.username;
}
public Object getPrincipal() {
return this.username;
}
}

View File

@@ -0,0 +1,8 @@
<html>
<body>
Provides "adapters" so that containers can authenticate with the
Acegi Security System for Spring.
<p>
</body>
</html>

View File

@@ -0,0 +1,38 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
import java.io.Serializable;
/**
* Holds objects that are needed on every request.
*
* <P>
* A <code>Context</code> will be sent between application tiers via a {@link
* ContextHolder}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface Context extends Serializable {
//~ Methods ================================================================
/**
* Check the <code>Context</code> is properly configured.
*
* <P>
* This allows implementations to confirm they are valid, as this method
* is automatically called by the {@link ContextInterceptor}.
* </p>
*
* @throws ContextInvalidException if the <code>Context</code> is invalid.
*/
public void validate() throws ContextInvalidException;
}

View File

@@ -0,0 +1,47 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
import org.springframework.core.NestedRuntimeException;
/**
* Abstract superclass for all exceptions thrown in the context package and
* subpackages.
*
* <p>
* Note that this is a runtime (unchecked) exception.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public abstract class ContextException extends NestedRuntimeException {
//~ Constructors ===========================================================
/**
* Constructs a <code>ContextException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t the root cause
*/
public ContextException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs a <code>ContextException</code> with the specified message
* and no root cause.
*
* @param msg the detail message
*/
public ContextException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,30 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
/**
* Associates a given {@link Context} with the current execution thread.
*
* @author Ben Alex
* @version $Id$
*/
public class ContextHolder {
//~ Static fields/initializers =============================================
private static ThreadLocal contextHolder = new ThreadLocal();
//~ Methods ================================================================
public static void setContext(Context context) {
contextHolder.set(context);
}
public static Context getContext() {
return (Context) contextHolder.get();
}
}

View File

@@ -0,0 +1,40 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
/**
* Thrown if a {@link ContextHolder} object does not contain a valid {@link
* Context}.
*
* @author Ben Alex
* @version $Id$
*/
public class ContextHolderEmptyException extends ContextException {
//~ Constructors ===========================================================
/**
* Constructs a <code>ContextHolderEmptyException</code> with the specified
* message.
*
* @param msg the detail message
*/
public ContextHolderEmptyException(String msg) {
super(msg);
}
/**
* Constructs a <code>ContextHolderEmptyException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public ContextHolderEmptyException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,22 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
/**
* Basic concrete implementation of a {@link Context}.
*
* @author Ben Alex
* @version $Id$
*/
public class ContextImpl implements Context {
//~ Methods ================================================================
public void validate() throws ContextInvalidException {
// Nothing to validate.
}
}

View File

@@ -0,0 +1,50 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Ensures the {@link ContextHolder} contains a valid {@link Context}.
*
* <p>
* This interceptor works by calling {@link Context#validate()} before
* proceeding with method invocations. It is configured in the bean context
* with a <code>ProxyFactoryBean</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*
* @see Context#validate()
*/
public class ContextInterceptor implements MethodInterceptor {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(ContextInterceptor.class);
//~ Methods ================================================================
public Object invoke(MethodInvocation mi) throws Throwable {
if (ContextHolder.getContext() == null) {
throw new ContextHolderEmptyException("ContextHolder does not contain a Context",
null);
}
ContextHolder.getContext().validate();
Object ret = mi.proceed();
return ret;
}
}

View File

@@ -0,0 +1,42 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
/**
* Thrown if a {@link Context} is not valid, according to {@link
* Context#validate()}.
*
* @author Ben Alex
* @version $Id$
*
* @see Context#validate()
*/
public class ContextInvalidException extends ContextException {
//~ Constructors ===========================================================
/**
* Constructs a <code>ContextInvalidException</code> with the specified
* message.
*
* @param msg the detail message.
*/
public ContextInvalidException(String msg) {
super(msg);
}
/**
* Constructs a <code>ContextInvalidException</code> with the specified
* message and root cause.
*
* @param msg the detail message.
* @param t root cause
*/
public ContextInvalidException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,31 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
import net.sf.acegisecurity.Authentication;
/**
* A {@link Context} that also stores {@link Authentication} information.
*
* <p>
* This interface must be implemented on contexts that will be presented to the
* Acegi Security System for Spring, as it is required by the {@link
* net.sf.acegisecurity.SecurityInterceptor}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface SecureContext {
//~ Methods ================================================================
public void setAuthentication(Authentication newAuthentication);
public Authentication getAuthentication();
}

View File

@@ -0,0 +1,41 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.context;
import net.sf.acegisecurity.Authentication;
/**
* Basic concrete implementation of a {@link SecureContext}.
*
* @author Ben Alex
* @version $Id$
*/
public class SecureContextImpl extends ContextImpl implements SecureContext {
//~ Instance fields ========================================================
private Authentication authentication;
//~ Methods ================================================================
public void setAuthentication(Authentication newAuthentication) {
this.authentication = newAuthentication;
}
public Authentication getAuthentication() {
return this.authentication;
}
public void validate() throws ContextInvalidException {
super.validate();
if (authentication == null) {
throw new ContextInvalidException("Authentication not set");
}
}
}

View File

@@ -0,0 +1,10 @@
<html>
<body>
Provides a "request context".
<p>
A request context is associated with the current execution thread. It holds
objects that would otherwise need to be included in many method signatures,
such as for authentication.
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<body>
Provides core security classes of the Acegi Security System for Spring.
<p>
The {@link net.sf.acegisecurity.SecurityInterceptor} is the main class.
It delegates to two interfaces,
{@link net.sf.acegisecurity.AuthenticationManager} and
{@link net.sf.acegisecurity.AccessDecisionManager} for authentication and
authorization respectively.
<p>
When configuring <code>SecurityInterceptor</code> in the bean context, each
method to be secured is provided a comma separated list of configuration
attributes ({@link net.sf.acegisecurity.ConfigAttribute}).
These configuration attributes are relevant only to
<Code>AccessDecisionManager</code>s.
<p>
Read the JavaDocs of the key classes listed above to learn more about how
the security classes operate.
</body>
</html>

View File

@@ -0,0 +1,45 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
/**
* Provides a <code>String</code> representation of the Authentication token.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractAuthenticationToken implements Authentication {
//~ Methods ================================================================
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(super.toString() + ": ");
sb.append("Username: " + this.getPrincipal() + "; ");
sb.append("Password: [PROTECTED]; ");
sb.append("Authenticated: " + this.isAuthenticated() + "; ");
if (this.getAuthorities() != null) {
sb.append("Granted Authorities: ");
for (int i = 0; i < this.getAuthorities().length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(this.getAuthorities()[i].toString());
}
} else {
sb.append("Not granted any authorities");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,50 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
/**
* Indicates a class can process a specific {@link
* net.sf.acegisecurity.Authentication} implementation.
*
* @author Ben Alex
* @version $Id$
*/
public interface AuthenticationProvider {
//~ Methods ================================================================
/**
* Performs authentication with the same contract as {@link
* net.sf.acegisecurity.AuthenticationManager#authenticate(Authentication)}.
*
* @param authentication the authentication request object.
*
* @return a fully authenticated object including credentials.
*
* @throws AuthenticationException if authentication fails.
*/
public Authentication authenticate(Authentication authentication)
throws AuthenticationException;
/**
* Returns true if this <Code>AuthenticationProvider</code> supports the
* indicated <Code>Authentication</code> object.
*
* <P>
* Selection of an <code>AuthenticationProvider</code> capable of
* performing authentication is conducted at runtime the
* <code>ProviderManager</code>.
* </p>
*
* @return DOCUMENT ME!
*/
public boolean supports(Class authentication);
}

View File

@@ -0,0 +1,132 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.Iterator;
import java.util.List;
/**
* Iterates an {@link Authentication} request through a list of {@link
* AuthenticationProvider}s.
*
* @author Ben Alex
* @version $Id$
*/
public class ProviderManager implements InitializingBean, AuthenticationManager {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(ProviderManager.class);
//~ Instance fields ========================================================
private List providers;
//~ Methods ================================================================
/**
* Sets the {@link AuthenticationProvider} objects to be used for
* authentication.
*
* @param newList
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public void setProviders(List newList) {
checkIfValidList(newList);
Iterator iter = newList.iterator();
while (iter.hasNext()) {
Object currentObject = null;
try {
currentObject = iter.next();
AuthenticationProvider attemptToCast = (AuthenticationProvider) currentObject;
} catch (ClassCastException cce) {
throw new IllegalArgumentException("AuthenticationProvider "
+ currentObject.getClass()
.getName()
+ " must implement AuthenticationProvider");
}
}
this.providers = newList;
}
public List getProviders() {
return this.providers;
}
public void afterPropertiesSet() throws Exception {
checkIfValidList(this.providers);
}
/**
* Attempts to authenticate the passed {@link Authentication} object.
*
* <p>
* The list of {@link AuthenticationProvider}s will be successively tried
* until an <code>AuthenticationProvider</code> indicates it is capable
* of authenticating the type of <code>Authentication</code> object
* passed. Authentication will then be attempted with that
* <code>AuthenticationProvider</code>.
* </p>
*
* <p>
* If more than one <code>AuthenticationProvider</code> supports the passed
* <code>Authentication</code> object, only the first
* <code>AuthenticationProvider</code> tried will determine the result. No
* subsequent <code>AuthenticationProvider</code>s will be tried.
* </p>
*
* @param authentication the authentication request object.
*
* @return a fully authenticated object including credentials.
*
* @throws AuthenticationException if authentication fails.
* @throws ProviderNotFoundException DOCUMENT ME!
*/
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Iterator iter = providers.iterator();
Class toTest = authentication.getClass();
while (iter.hasNext()) {
AuthenticationProvider provider = (AuthenticationProvider) iter
.next();
if (provider.supports(toTest)) {
logger.debug("Authentication attempt using "
+ provider.getClass().getName());
return provider.authenticate(authentication);
}
}
throw new ProviderNotFoundException("No authentication provider for "
+ toTest.getName());
}
private void checkIfValidList(List listToCheck) {
if ((listToCheck == null) || (listToCheck.size() == 0)) {
throw new IllegalArgumentException("A list of AuthenticationManagers is required");
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.AuthenticationException;
/**
* Thrown by {@link ProviderManager} if no {@link AuthenticationProvider}
* could be found that supports the presented {@link
* net.sf.acegisecurity.Authentication} object.
*
* @author Ben Alex
* @version $Id$
*/
public class ProviderNotFoundException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>ProviderNotFoundException</code> with the specified
* message.
*
* @param msg the detail message
*/
public ProviderNotFoundException(String msg) {
super(msg);
}
/**
* Constructs a <code>ProviderNotFoundException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public ProviderNotFoundException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,46 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
/**
* An {@link AuthenticationProvider} implementation for the {@link
* TestingAuthenticationToken}.
*
* <p>
* It simply accepts as valid whatever is contained within the
* <code>TestingAuthenticationToken</code>.
* </p>
*
* <p>
* The purpose of this implementation is to facilitate unit testing. This
* provider should <B>never be enabled on a production system</b>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class TestingAuthenticationProvider implements AuthenticationProvider {
//~ Methods ================================================================
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
return authentication;
}
public boolean supports(Class authentication) {
if (TestingAuthenticationToken.class.isAssignableFrom(authentication)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.GrantedAuthority;
/**
* An {@link net.sf.acegisecurity.Authentication} implementation that is
* designed for use whilst unit testing.
*
* <p>
* The corresponding authentication provider is {@link
* TestingAuthenticationProvider}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class TestingAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ========================================================
private Object credentials;
private Object principal;
private GrantedAuthority[] authorities;
private boolean authenticated = false;
//~ Constructors ===========================================================
public TestingAuthenticationToken(Object principal, Object credentials,
GrantedAuthority[] authorities) {
this.principal = principal;
this.credentials = credentials;
this.authorities = authorities;
}
private TestingAuthenticationToken() {
super();
}
//~ Methods ================================================================
public void setAuthenticated(boolean isAuthenticated) {
this.authenticated = isAuthenticated;
}
public boolean isAuthenticated() {
return this.authenticated;
}
public GrantedAuthority[] getAuthorities() {
return this.authorities;
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
}

View File

@@ -0,0 +1,81 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.GrantedAuthority;
/**
* An {@link net.sf.acegisecurity.Authentication} implementation that is
* designed for simple presentation of a username and password.
*
* <p>
* The <code>principal</code> and <code>credentials</code> should be set with
* an <code>Object</code> that provides the respective property via its
* <code>Object.toString()</code> method. The simplest such
* <code>Object</code> to use is <code>String</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class UsernamePasswordAuthenticationToken
extends AbstractAuthenticationToken {
//~ Instance fields ========================================================
private Object credentials;
private Object principal;
private GrantedAuthority[] authorities;
private boolean authenticated = false;
//~ Constructors ===========================================================
public UsernamePasswordAuthenticationToken(Object principal,
Object credentials) {
this.principal = principal;
this.credentials = credentials;
}
public UsernamePasswordAuthenticationToken(Object principal,
Object credentials,
GrantedAuthority[] authorities) {
this.principal = principal;
this.credentials = credentials;
this.authorities = authorities;
}
private UsernamePasswordAuthenticationToken() {
super();
}
//~ Methods ================================================================
public void setAuthenticated(boolean isAuthenticated) {
this.authenticated = isAuthenticated;
}
public boolean isAuthenticated() {
return this.authenticated;
}
public void setAuthorities(GrantedAuthority[] authorities) {
this.authorities = authorities;
}
public GrantedAuthority[] getAuthorities() {
return this.authorities;
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
}

View File

@@ -0,0 +1,124 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.DisabledException;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
/**
* An {@link AuthenticationProvider} implementation that retrieves user details
* from an {@link AuthenticationDao}.
*
* <p>
* This <code>AuthenticationProvider</code> is capable of validating {@link
* UsernamePasswordAuthenticationToken} requests contain the correct username,
* password and the user is not disabled.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class DaoAuthenticationProvider implements AuthenticationProvider,
InitializingBean {
//~ Instance fields ========================================================
private AuthenticationDao authenticationDao;
private boolean ignorePasswordCase = false;
private boolean ignoreUsernameCase = true;
//~ Methods ================================================================
public void setAuthenticationDao(AuthenticationDao authenticationDao) {
this.authenticationDao = authenticationDao;
}
public AuthenticationDao getAuthenticationDao() {
return authenticationDao;
}
/**
* Indicates whether the password comparison is case sensitive. Defaults to
* <code>false</code>, meaning an exact case match is required.
*
* @param ignorePasswordCase set to <code>true</code> for less stringent
* comparison
*/
public void setIgnorePasswordCase(boolean ignorePasswordCase) {
this.ignorePasswordCase = ignorePasswordCase;
}
public boolean isIgnorePasswordCase() {
return ignorePasswordCase;
}
/**
* Indicates whether the username search is case sensitive. Default to
* <code>true</code>, meaning an exact case match is not required.
*
* @param ignoreUsernameCase set to <code>false</code> for more stringent
* comparison
*/
public void setIgnoreUsernameCase(boolean ignoreUsernameCase) {
this.ignoreUsernameCase = ignoreUsernameCase;
}
public boolean isIgnoreUsernameCase() {
return ignoreUsernameCase;
}
public void afterPropertiesSet() throws Exception {
if (this.authenticationDao == null) {
throw new IllegalArgumentException("An Authentication DAO must be set");
}
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
User user = null;
try {
user = this.authenticationDao.loadUserByUsername(authentication.getPrincipal()
.toString());
} catch (UsernameNotFoundException notFound) {
throw new BadCredentialsException("Bad credentials presented");
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem
.getMessage());
}
if (!user.isEnabled()) {
throw new DisabledException("User is disabled");
}
if (!user.getPassword().equals(authentication.getCredentials().toString())) {
throw new BadCredentialsException("Bad credentials presented");
}
return new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(),
user.getAuthorities());
}
public boolean supports(Class authentication) {
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao;
import net.sf.acegisecurity.AuthenticationException;
/**
* Thrown if an {@link AuthenticationDao} implementation cannot locate a {@link
* User} by its username.
*
* @author Ben Alex
* @version $Id$
*/
public class UsernameNotFoundException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>UsernameNotFoundException</code> with the specified
* message.
*
* @param msg the detail message.
*/
public UsernameNotFoundException(String msg) {
super(msg);
}
/**
* Constructs a <code>UsernameNotFoundException</code> with the specified
* message and root cause.
*
* @param msg the detail message.
* @param t root cause
*/
public UsernameNotFoundException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
An authentication provider that relies upon a data access object.
</body>
</html>

View File

@@ -0,0 +1,7 @@
<html>
<body>
Implements a provider-based approach to authorization decisions.
<p>
</body>
</html>

View File

@@ -0,0 +1,77 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.runas;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import org.springframework.beans.factory.InitializingBean;
/**
* An {@link AuthenticationProvider} implementation that can authenticate a
* {@link RunAsUserToken}.
*
* <P>
* Configured in the bean context with a key that should match the key used by
* adapters to generate the <code>RunAsUserToken</code>. It treats as valid
* any <code>RunAsUserToken</code> instance presenting a hash code that
* matches the <code>RunAsImplAuthenticationProvider</code>-configured key.
* </p>
*
* <P>
* If the key does not match, a <code>BadCredentialsException</code> is
* thrown.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RunAsImplAuthenticationProvider implements InitializingBean,
AuthenticationProvider {
//~ Instance fields ========================================================
private String key;
//~ Methods ================================================================
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void afterPropertiesSet() throws Exception {
if (key == null) {
throw new IllegalArgumentException("A Key is required and should match that configured for the RunAsManagerImpl");
}
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
RunAsUserToken token = (RunAsUserToken) authentication;
if (token.getKeyHash() == key.hashCode()) {
return authentication;
} else {
throw new BadCredentialsException("The presented RunAsUserToken does not contain the expected key");
}
}
public boolean supports(Class authentication) {
if (RunAsUserToken.class.isAssignableFrom(authentication)) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.runas;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.RunAsManager;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Basic concrete implementation of a {@link RunAsManager}.
*
* <p>
* Is activated if any {@link ConfigAttribute#getAttribute()} is prefixed with
* <Code>RUN_AS_</code>. If found, it generates a new {@link RunAsUserToken}
* containing the same principal, credentials and granted authorities as the
* original {@link Authentication} object, along with {@link
* GrantedAuthorityImpl}s for each <code>RUN_AS_</code> indicated. The created
* <code>GrantedAuthorityImpl</code>s will be prefixed with <code>ROLE_</code>
* and then the remainder of the <code>RUN_AS_</code> keyword. For example,
* <code>RUN_AS_FOO</code> will result in the creation of a granted authority
* of <code>ROLE_RUN_AS_FOO</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RunAsManagerImpl implements RunAsManager, InitializingBean {
//~ Instance fields ========================================================
private String key;
//~ Methods ================================================================
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void afterPropertiesSet() throws Exception {
if (key == null) {
throw new IllegalArgumentException("A Key is required and should match that configured for the RunAsImplAuthenticationProvider");
}
}
public Authentication buildRunAs(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config) {
Set newAuthorities = new HashSet();
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();
if (this.supports(attribute)) {
GrantedAuthorityImpl extraAuthority = new GrantedAuthorityImpl("ROLE_"
+ attribute
.getAttribute());
newAuthorities.add(extraAuthority);
}
}
if (newAuthorities.size() == 0) {
return null;
} else {
for (int i = 0; i < authentication.getAuthorities().length; i++) {
newAuthorities.add(authentication.getAuthorities()[i]);
}
GrantedAuthority[] resultType = {new GrantedAuthorityImpl("holder")};
GrantedAuthority[] newAuthoritiesAsArray = (GrantedAuthority[]) newAuthorities
.toArray(resultType);
return new RunAsUserToken(this.key, authentication.getPrincipal(),
authentication.getCredentials(),
newAuthoritiesAsArray,
authentication.getClass());
}
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().startsWith("RUN_AS_")) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.runas;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
/**
* An immutable {@link net.sf.acegisecurity.Authentication} implementation
* that supports {@link RunAsManagerImpl}.
*
* @author Ben Alex
* @version $Id$
*/
public class RunAsUserToken extends AbstractAuthenticationToken {
//~ Instance fields ========================================================
private Class originalAuthentication;
private Object credentials;
private Object principal;
private GrantedAuthority[] authorities;
private int keyHash;
//~ Constructors ===========================================================
public RunAsUserToken(String key, Object principal, Object credentials,
GrantedAuthority[] authorities,
Class originalAuthentication) {
super();
this.keyHash = key.hashCode();
this.authorities = authorities;
this.principal = principal;
this.credentials = credentials;
this.originalAuthentication = originalAuthentication;
}
private RunAsUserToken() {
super();
}
//~ Methods ================================================================
/**
* Setting is ignored. Always considered authenticated.
*
* @param ignored DOCUMENT ME!
*/
public void setAuthenticated(boolean ignored) {
// ignored
}
/**
* Always returns <code>true</code>.
*
* @return DOCUMENT ME!
*/
public boolean isAuthenticated() {
return true;
}
public GrantedAuthority[] getAuthorities() {
return this.authorities;
}
public Object getCredentials() {
return this.credentials;
}
public int getKeyHash() {
return this.keyHash;
}
public Class getOriginalAuthentication() {
return this.originalAuthentication;
}
public Object getPrincipal() {
return this.principal;
}
public String toString() {
StringBuffer sb = new StringBuffer(super.toString());
sb.append("; Original Class: " + this.originalAuthentication.getName());
return sb.toString();
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Allows intercepted methods to be run under a different authentication identity.
</body>
</html>

View File

@@ -0,0 +1,71 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao;
import net.sf.acegisecurity.GrantedAuthority;
/**
* Models core user information retieved by an {@link AuthenticationDao}.
*
* @author Ben Alex
* @version $Id$
*/
public class User {
//~ Instance fields ========================================================
private String password;
private String username;
private GrantedAuthority[] authorities;
private boolean enabled;
//~ Constructors ===========================================================
/**
* Construct the <code>User</code> with the details required by {@link
* DaoAuthenticationProvider}.
*
* @param username the username presented to the
* <code>DaoAuthenticationProvider</code>
* @param password the password that should be presented to the
* <code>DaoAuthenticationProvider</code>
* @param enabled set to <code>true</code> if the user is enabled
* @param authorities the authorities that should be granted to the caller
* if they presented the correct username and password and the user
* is enabled
*/
public User(String username, String password, boolean enabled,
GrantedAuthority[] authorities) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.authorities = authorities;
}
private User() {
super();
}
//~ Methods ================================================================
public GrantedAuthority[] getAuthorities() {
return authorities;
}
public boolean isEnabled() {
return enabled;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
}

View File

@@ -0,0 +1,46 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao;
import org.springframework.dao.DataAccessException;
/**
* Defines an interface for implementations that wish to provide data access
* services to the {@link DaoAuthenticationProvider}.
*
* <p>
* The interface requires only one read-only method, which simplifies support
* of new data access strategies.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface AuthenticationDao {
//~ Methods ================================================================
/**
* Locates the user based on the username. The search is case insensitive,
* meaning the implementation must return any matching object irrespective
* of the mixture of uppercase and lowercase characters in the username.
*
* @param username the username presented to the {@link
* DaoAuthenticationProvider}
*
* @return a fully populated user record
*
* @throws UsernameNotFoundException if the user could not be found or the
* user has no GrantedAuthority
* @throws DataAccessException if user could not be found for a
* repository-specific reason
*/
public User loadUserByUsername(String username)
throws UsernameNotFoundException,
DataAccessException;
}

View File

@@ -0,0 +1,139 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.jdbc;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.dao.AuthenticationDao;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContextException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import javax.sql.DataSource;
/**
* Retrieves user details from a JDBC location provided by the bean context.
*
* @author Ben Alex
* @version $Id$
*/
public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(JdbcDaoSupport.class);
//~ Instance fields ========================================================
private AuthoritiesByUsernameQuery authoritiesByUsernameQuery;
private UsersByUsernameQuery usersByUsernameQuery;
//~ Methods ================================================================
public User loadUserByUsername(String username)
throws UsernameNotFoundException,
DataAccessException {
List users = usersByUsernameQuery.execute(username);
if (users.size() == 0) {
throw new UsernameNotFoundException("User not found");
}
User user = (User) users.get(0); // contains no GrantedAuthority[]
List dbAuths = authoritiesByUsernameQuery.execute(user.getUsername());
if (dbAuths.size() == 0) {
throw new UsernameNotFoundException("User has no GrantedAuthority");
}
GrantedAuthority[] arrayAuths = {new GrantedAuthorityImpl("demo")};
arrayAuths = (GrantedAuthority[]) dbAuths.toArray(arrayAuths);
return new User(user.getUsername(), user.getPassword(),
user.isEnabled(), arrayAuths);
}
protected void setAuthoritiesByUsernameQuery(AuthoritiesByUsernameQuery authoritiesByUsernameQuery) {
this.authoritiesByUsernameQuery = authoritiesByUsernameQuery;
}
protected void setUsersByUsernameQuery(UsersByUsernameQuery usersByUsernameQuery) {
this.usersByUsernameQuery = usersByUsernameQuery;
}
protected void initDao() throws ApplicationContextException {
if (usersByUsernameQuery == null) {
usersByUsernameQuery = new UsersByUsernameQuery(getDataSource());
}
if (authoritiesByUsernameQuery == null) {
authoritiesByUsernameQuery = new AuthoritiesByUsernameQuery(getDataSource());
}
}
//~ Inner Classes ==========================================================
/**
* Query object to look up a user's authorities.
*/
protected static class AuthoritiesByUsernameQuery extends MappingSqlQuery {
protected AuthoritiesByUsernameQuery(DataSource ds) {
super(ds,
"SELECT username,authority FROM authorities WHERE username = ?");
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(rs
.getString("authority"));
return authority;
}
}
/**
* Query object to look up a user.
*/
protected static class UsersByUsernameQuery extends MappingSqlQuery {
protected UsersByUsernameQuery(DataSource ds) {
super(ds,
"SELECT username,password,enabled FROM users WHERE username = ?");
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
String username = rs.getString("username");
String password = rs.getString("password");
boolean enabled = rs.getBoolean("enabled");
User user = new User(username, password, enabled, null);
return user;
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Exposes a JDBC-based authentication repository.
</body>
</html>

View File

@@ -0,0 +1,57 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.providers.dao.AuthenticationDao;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
/**
* Retrieves user details from an in-memory list created by the bean context.
*
* @author Ben Alex
* @version $Id$
*/
public class InMemoryDaoImpl implements AuthenticationDao, InitializingBean {
//~ Instance fields ========================================================
private UserMap userMap;
//~ Methods ================================================================
public void setUserMap(UserMap userMap) {
this.userMap = userMap;
}
public UserMap getUserMap() {
return userMap;
}
public void afterPropertiesSet() throws Exception {
if (this.userMap == null) {
throw new IllegalArgumentException("A list of users, passwords, enabled/disabled status and their granted authorities must be set");
}
}
public User loadUserByUsername(String username)
throws UsernameNotFoundException,
DataAccessException {
User result = userMap.getUser(username);
if (result == null) {
throw new UsernameNotFoundException("User could not be found");
}
return result;
}
}

View File

@@ -0,0 +1,72 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import java.util.HashSet;
import java.util.Set;
/**
* Used by {@link InMemoryDaoImpl} to temporarily store the attributes
* associated with a user.
*
* @author Ben Alex
* @version $Id$
*/
public class UserAttributeDefinition {
//~ Instance fields ========================================================
private Set authorities = new HashSet();
private String password;
private boolean enabled = true;
//~ Constructors ===========================================================
public UserAttributeDefinition() {
super();
}
//~ Methods ================================================================
public GrantedAuthority[] getAuthorities() {
GrantedAuthority[] toReturn = {new GrantedAuthorityImpl("demo")};
return (GrantedAuthority[]) this.authorities.toArray(toReturn);
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() {
return enabled;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public boolean isValid() {
if ((this.password != null) && (authorities.size() > 0)) {
return true;
} else {
return false;
}
}
public void addAuthority(GrantedAuthority newAuthority) {
this.authorities.add(newAuthority);
}
}

View File

@@ -0,0 +1,57 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
/**
* Property editor that creates a {@link UserAttributeDefinition} from a comma
* separated list of values.
*
* @author Ben Alex
* @version $Id$
*/
public class UserAttributeEditor extends PropertyEditorSupport {
//~ Methods ================================================================
public void setAsText(String s) throws IllegalArgumentException {
if ((s == null) || "".equals(s)) {
setValue(null);
} else {
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
UserAttributeDefinition userAttrib = new UserAttributeDefinition();
for (int i = 0; i < tokens.length; i++) {
String currentToken = tokens[i];
if (i == 0) {
userAttrib.setPassword(currentToken);
} else {
if (currentToken.toLowerCase().equals("enabled")) {
userAttrib.setEnabled(true);
} else if (currentToken.toLowerCase().equals("disabled")) {
userAttrib.setEnabled(false);
} else {
userAttrib.addAuthority(new GrantedAuthorityImpl(currentToken));
}
}
}
if (userAttrib.isValid()) {
setValue(userAttrib);
} else {
setValue(null);
}
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.providers.dao.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashMap;
import java.util.Map;
/**
* Used by {@link InMemoryDaoImpl} to store a list of users and their
* corresponding granted authorities.
*
* @author Ben Alex
* @version $Id$
*/
public class UserMap {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(UserMap.class);
//~ Instance fields ========================================================
private Map userMap = new HashMap();
//~ Methods ================================================================
public User getUser(String username) {
return (User) this.userMap.get(username.toLowerCase());
}
/**
* Adds a user to the in-memory map.
*
* @param user the user to be stored
*/
public void addUser(User user) {
logger.info("Adding user [" + user + "]");
this.userMap.put(user.getUsername().toLowerCase(), user);
}
}

View File

@@ -0,0 +1,93 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.providers.dao.User;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import java.beans.PropertyEditorSupport;
import java.util.Iterator;
import java.util.Properties;
/**
* Property editor to assist with the setup of a {@link UserMap}.
*
* <p>
* The format of entries should be:
* </p>
*
* <p>
* <code>
* username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
* </code>
* </p>
*
* <p>
* The <code>password</code> must always be the first entry after the equals.
* The <code>enabled</code> or <code>disabled</code> keyword can appear
* anywhere (apart from the first entry reserved for the password). If neither
* <code>enabled</code> or <code>disabled</code> appear, the default is
* <code>enabled</code>. At least one granted authority must be listed.
* </p>
*
* <p>
* The <code>username</code> represents the key and duplicates are handled the
* same was as duplicates would be in Java <code>Properties</code> files.
* </p>
*
* <p>
* If the above requirements are not met, the invalid entry will be silently
* ignored.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class UserMapEditor extends PropertyEditorSupport {
//~ Methods ================================================================
public void setAsText(String s) throws IllegalArgumentException {
UserMap userMap = new UserMap();
if ((s == null) || "".equals(s)) {
// Leave value in property editor null
} else {
// Use properties editor to tokenize the string
PropertiesEditor propertiesEditor = new PropertiesEditor();
propertiesEditor.setAsText(s);
Properties props = (Properties) propertiesEditor.getValue();
// Now we have properties, process each one individually
UserAttributeEditor configAttribEd = new UserAttributeEditor();
for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
String username = (String) iter.next();
String value = props.getProperty(username);
// Convert value to a password, enabled setting, and list of granted authorities
configAttribEd.setAsText(value);
UserAttributeDefinition attr = (UserAttributeDefinition) configAttribEd
.getValue();
// Make a user object, assuming the properties were properly provided
if (attr != null) {
User user = new User(username, attr.getPassword(),
attr.isEnabled(), attr.getAuthorities());
userMap.addUser(user);
}
}
}
setValue(userMap);
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Exposes an in-memory authentication repository.
</body>
</html>

View File

@@ -0,0 +1,98 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.AccessDecisionManager;
import net.sf.acegisecurity.ConfigAttribute;
import org.springframework.beans.factory.InitializingBean;
import java.util.Iterator;
import java.util.List;
/**
* Abstract implementation of {@link AccessDecisionManager}.
*
* <p>
* Handles configuration of a bean context defined list of {@link
* AccessDecisionVoter}s and the access control behaviour if all voters
* abstain from voting (defaults to deny access).
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractAccessDecisionManager
implements AccessDecisionManager, InitializingBean {
//~ Instance fields ========================================================
private List decisionVoters;
private boolean allowIfAllAbstainDecisions = false;
//~ Methods ================================================================
public void setAllowIfAllAbstainDecisions(boolean allowIfAllAbstainDecisions) {
this.allowIfAllAbstainDecisions = allowIfAllAbstainDecisions;
}
public boolean isAllowIfAllAbstainDecisions() {
return allowIfAllAbstainDecisions;
}
public void setDecisionVoters(List newList) {
checkIfValidList(newList);
Iterator iter = newList.iterator();
while (iter.hasNext()) {
Object currentObject = null;
try {
currentObject = iter.next();
AccessDecisionVoter attemptToCast = (AccessDecisionVoter) currentObject;
} catch (ClassCastException cce) {
throw new IllegalArgumentException("AccessDecisionVoter "
+ currentObject.getClass()
.getName()
+ " must implement AccessDecisionVoter");
}
}
this.decisionVoters = newList;
}
public List getDecisionVoters() {
return this.decisionVoters;
}
public void afterPropertiesSet() throws Exception {
checkIfValidList(this.decisionVoters);
}
public boolean supports(ConfigAttribute attribute) {
Iterator iter = this.decisionVoters.iterator();
while (iter.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
if (voter.supports(attribute)) {
return true;
}
}
return false;
}
private void checkIfValidList(List listToCheck) {
if ((listToCheck == null) || (listToCheck.size() == 0)) {
throw new IllegalArgumentException("A list of AccessDecisionVoters is required");
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import org.aopalliance.intercept.MethodInvocation;
/**
* Indicates a class is responsible for voting on authorization decisions.
*
* <p>
* The coordination of voting (ie polling <code>AccessDecisionVoter</code>s,
* tallying their responses, and making the final authorization decision) is
* performed by an {@link net.sf.acegisecurity.AccessDecisionManager}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface AccessDecisionVoter {
//~ Static fields/initializers =============================================
public static final int ACCESS_GRANTED = 1;
public static final int ACCESS_ABSTAIN = 0;
public static final int ACCESS_DENIED = -1;
//~ Methods ================================================================
/**
* Indicates whether this <code>AccessDecisionVoter</code> is able to vote
* on the passed <code>ConfigAttribute</code>.
*
* <p>
* This allows the <code>SecurityInterceptor</code> to check every
* configuration attribute can be consumed by the configured
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code>.
* </p>
*
* @param attribute a configuration attribute that has been configured
* against the <code>SecurityInterceptor</code>
*
* @return true if this <code>AccessDecisionVoter</code> can support the
* passed configuration attribute
*/
public boolean supports(ConfigAttribute attribute);
/**
* Indicates whether or not access is granted.
*
* <p>
* The decision must be affirmative (<code>ACCESS_GRANTED</code>),
* negative (<code>ACCESS_DENIED</code>) or the
* <code>AccessDecisionVoter</code> can abstain
* (<code>ACCESS_ABSTAIN</code>) from voting. Under no circumstances
* should implementing classes return any other value. If a weighting of
* results is desired, this should be handled in a custom {@link
* net.sf.acegisecurity.AccessDecisionManager} instead.
* </p>
*
* <P>
* Unless an <code>AccessDecisionVoter</code> is specifically intended to
* vote on an access control decision due to a passed method invocation or
* configuration attribute parameter, it must return
* <code>ACCESS_ABSTAIN</code>. This prevents the coordinating
* <code>AccessDecisionManager</code> from counting votes from those
* <code>AccessDecisionVoter</code>s without a legitimate interest in the
* access control decision.
* </p>
*
* <p>
* Whilst the method invocation is passed as a parameter to maximise
* flexibility in making access control decisions, implementing classes
* must never modify the behaviour of the method invocation (such as
* calling <Code>MethodInvocation.proceed()</code>).
* </p>
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @return either {@link #ACCESS_GRANTED}, {@link #ACCESS_ABSTAIN} or
* {@link #ACCESS_DENIED}
*/
public int vote(Authentication authentication, MethodInvocation invocation,
ConfigAttributeDefinition config);
}

View File

@@ -0,0 +1,92 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
/**
* Simple concrete implementation of {@link
* net.sf.acegisecurity.AccessDecisionManager} that grants access if any
* <code>AccessDecisionVoter</code> returns an affirmative response.
*
* @author Ben Alex
* @version $Id$
*/
public class AffirmativeBased extends AbstractAccessDecisionManager {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(AffirmativeBased.class);
//~ Methods ================================================================
/**
* This concrete implementation simply polls all configured {@link
* AccessDecisionVoter}s and grants access if any
* <code>AccessDecisionVoter</code> voted affirmatively. Denies access
* only if there was a deny vote AND no affirmative votes.
*
* <p>
* If every <code>AccessDecisionVoter</code> abstained from voting, the
* decision will be based on the {@link #isAllowIfAllAbstainDecisions()}
* property (defaults to false).
* </p>
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @throws AccessDeniedException if access is denied
*/
public void decide(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config)
throws AccessDeniedException {
Iterator iter = this.getDecisionVoters().iterator();
int deny = 0;
while (iter.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
int result = voter.vote(authentication, invocation, config);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException("Access is denied.");
}
// To get this far, every AccessDecisionVoter abstained
if (this.isAllowIfAllAbstainDecisions()) {
return;
} else {
throw new AccessDeniedException("Access is denied.");
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
/**
* Simple concrete implementation of {@link
* net.sf.acegisecurity.AccessDecisionManager} that uses a consensus-based
* approach.
*
* @author Ben Alex
* @version $Id$
*/
public class ConsensusBased extends AbstractAccessDecisionManager {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(ConsensusBased.class);
//~ Instance fields ========================================================
private boolean allowIfEqualGrantedDeniedDecisions = true;
//~ Methods ================================================================
public void setAllowIfEqualGrantedDeniedDecisions(boolean allowIfEqualGrantedDeniedDecisions) {
this.allowIfEqualGrantedDeniedDecisions = allowIfEqualGrantedDeniedDecisions;
}
public boolean isAllowIfEqualGrantedDeniedDecisions() {
return allowIfEqualGrantedDeniedDecisions;
}
/**
* This concrete implementation simply polls all configured {@link
* AccessDecisionVoter}s and upon completion determines the consensus of
* granted vs denied responses.
*
* <p>
* If there were an equal number of grant and deny votes, the decision will
* be based on the {@link #isAllowIfEqualGrantedDeniedDecisions()}
* property (defaults to true).
* </p>
*
* <p>
* If every <code>AccessDecisionVoter</code> abstained from voting, the
* decision will be based on the {@link #isAllowIfAllAbstainDecisions()}
* property (defaults to false).
* </p>
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @throws AccessDeniedException if access is denied
*/
public void decide(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config)
throws AccessDeniedException {
Iterator iter = this.getDecisionVoters().iterator();
int grant = 0;
int deny = 0;
int abstain = 0;
while (iter.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
int result = voter.vote(authentication, invocation, config);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
grant++;
break;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
abstain++;
break;
}
}
if (grant > deny) {
return;
}
if (deny > grant) {
throw new AccessDeniedException("Access is denied.");
}
if ((grant == deny) && (grant != 0)) {
if (this.allowIfEqualGrantedDeniedDecisions) {
return;
} else {
throw new AccessDeniedException("Access is denied.");
}
}
// To get this far, every AccessDecisionVoter abstained
if (this.isAllowIfAllAbstainDecisions()) {
return;
} else {
throw new AccessDeniedException("Access is denied.");
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import org.aopalliance.intercept.MethodInvocation;
import java.util.Iterator;
/**
* Votes if any {@link ConfigAttribute#getAttribute()} is prefixed with
* <Code>ROLE_</code>.
*
* <p>
* Abstains from voting if no configuration attribute commences with
* <code>ROLE_</code>. Votes to grant access if there is an exact matching
* {@link net.sf.acegisecurity.GrantedAuthority} to a
* <code>ConfigAttribute</code> starting with <code>ROLE_</code>. Votes to
* deny access if there is no exact matching <code>GrantedAuthority</code> to
* a <code>ConfigAttribute</code> starting with <code>ROLE_</code>.
* </p>
*
* <p>
* All comparisons and prefixes are case sensitive.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RoleVoter implements AccessDecisionVoter {
//~ Methods ================================================================
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().startsWith("ROLE_")) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, MethodInvocation invocation,
ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();
if (this.supports(attribute)) {
result = ACCESS_DENIED;
// Attempt to find a matching granted authority
for (int i = 0; i < authentication.getAuthorities().length;
i++) {
if (attribute.getAttribute().equals(authentication
.getAuthorities()[i]
.getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
}

View File

@@ -0,0 +1,119 @@
/*
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
*
* Visit http://acegisecurity.sourceforge.net for further details.
*/
package net.sf.acegisecurity.vote;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
/**
* Simple concrete implementation of {@link
* net.sf.acegisecurity.AccessDecisionManager} that requires all voters to
* abstain or grant access.
*
* @author Ben Alex
* @version $Id$
*/
public class UnanimousBased extends AbstractAccessDecisionManager {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(UnanimousBased.class);
//~ Methods ================================================================
/**
* This concrete implementation polls all configured {@link
* AccessDecisionVoter}s for each {@link ConfigAttribute} and grants
* access if <b>only</b> grant votes were received.
*
* <p>
* Other voting implementations usually pass the entire list of {@link
* ConfigAttributeDefinition}s to the <code>AccessDecisionVoter</code>.
* This implementation differs in that each
* <code>AccessDecisionVoter</code> knows only about a single
* <code>ConfigAttribute</code> at a time.
* </p>
*
* <p>
* If every <code>AccessDecisionVoter</code> abstained from voting, the
* decision will be based on the {@link #isAllowIfAllAbstainDecisions()}
* property (defaults to false).
* </p>
*
* @param authentication the caller invoking the method
* @param invocation the method being called
* @param config the configuration attributes associated with the method
* being invoked
*
* @throws AccessDeniedException if access is denied
*/
public void decide(Authentication authentication,
MethodInvocation invocation,
ConfigAttributeDefinition config)
throws AccessDeniedException {
int grant = 0;
int deny = 0;
int abstain = 0;
Iterator configIter = config.getConfigAttributes();
while (configIter.hasNext()) {
ConfigAttributeDefinition thisDef = new ConfigAttributeDefinition();
thisDef.addConfigAttribute((ConfigAttribute) configIter.next());
Iterator voters = this.getDecisionVoters().iterator();
while (voters.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) voters.next();
int result = voter.vote(authentication, invocation, thisDef);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
grant++;
break;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
abstain++;
break;
}
}
}
if (deny > 0) {
throw new AccessDeniedException("Access is denied.");
}
// To get this far, there were no deny votes
if (grant > 0) {
return;
}
// To get this far, every AccessDecisionVoter abstained
if (this.isAllowIfAllAbstainDecisions()) {
return;
} else {
throw new AccessDeniedException("Access is denied.");
}
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Implements a vote-based approach to authorization decisions.
<p>
</body>
</html>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
* $Id$
-->
<beans>
<!-- ================= CONTAINER ADAPTER CONFIGURATION ================ -->
<!-- Data access object which stores authentication information -->
<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
</value>
</property>
</bean>
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
* The Acegi Security System for Spring is published under the terms
* of the Apache Software License.
* $Id$
-->
<beans>
<!-- ================= CONTAINER ADAPTER CONFIGURATION ================ -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
<property name="url"><value>jdbc:hsqldb:hsql://localhost:9001</value></property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>
</bean>
<!-- Data access object which stores authentication information -->
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="jdbcDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
</beans>