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

22
.classpath Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="src" path="samples/contacts/src"/>
<classpathentry kind="src" path="samples/attributes/src"/>
<classpathentry kind="src" path="integration-test/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/aop-alliance/aopalliance.jar"/>
<classpathentry kind="lib" path="lib/jakarta-commons/commons-logging.jar"/>
<classpathentry kind="lib" path="lib/j2ee/servlet.jar"/>
<classpathentry kind="lib" path="lib/junit/junit.jar"/>
<classpathentry kind="lib" path="lib/spring/spring.jar"/>
<classpathentry kind="lib" path="lib/extracted/jboss/jboss-common-extracted.jar"/>
<classpathentry kind="lib" path="lib/extracted/jboss/jbosssx-extracted.jar"/>
<classpathentry kind="lib" path="lib/extracted/catalina/catalina-extracted.jar"/>
<classpathentry kind="lib" path="lib/extracted/catalina/jmx-extracted.jar"/>
<classpathentry kind="lib" path="lib/extracted/jetty/org.mortbay.jetty-extracted.jar"/>
<classpathentry kind="lib" path="lib/extracted/resin/resin-extracted.jar"/>
<classpathentry kind="lib" path="integration-test/lib/httpunit.jar"/>
<classpathentry kind="output" path="target/eclipseclasses"/>
</classpath>

5
.cvsignore Normal file
View File

@ -0,0 +1,5 @@
dist
target
build.properties
*.log

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>acegisecurity</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,216 @@
/*
* 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.catalina;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.realm.RealmBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import java.io.File;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Map;
/**
* Adapter to enable Catalina (Tomcat) to authenticate via the Acegi Security
* System for Spring.
*
* <p>
* Returns a {@link PrincipalAcegiUserToken} to Catalina's authentication
* system, which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class CatalinaAcegiUserRealm extends RealmBase {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(CatalinaAcegiUserRealm.class);
//~ Instance fields ========================================================
protected final String name = "CatalinaSpringUserRealm / $Id$";
private AuthenticationManager authenticationManager;
private Container container;
private String appContextLocation;
private String key;
//~ Methods ================================================================
public void setAppContextLocation(String appContextLocation) {
this.appContextLocation = appContextLocation;
}
public String getAppContextLocation() {
return appContextLocation;
}
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public Principal authenticate(String username, String credentials) {
if (username == null) {
return null;
}
if (credentials == null) {
credentials = "";
}
Authentication request = new UsernamePasswordAuthenticationToken(username,
credentials);
Authentication response = null;
try {
response = authenticationManager.authenticate(request);
} catch (AuthenticationException failed) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication request for user: " + username
+ " failed: " + failed.toString());
}
return null;
}
return new PrincipalAcegiUserToken(this.key,
response.getPrincipal().toString(),
response.getCredentials().toString(), response.getAuthorities());
}
public Principal authenticate(String username, byte[] credentials) {
return authenticate(username, new String(credentials));
}
/**
* Not supported, returns null
*
* @param username DOCUMENT ME!
* @param digest DOCUMENT ME!
* @param nonce DOCUMENT ME!
* @param nc DOCUMENT ME!
* @param cnonce DOCUMENT ME!
* @param qop DOCUMENT ME!
* @param realm DOCUMENT ME!
* @param md5a2 DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public java.security.Principal authenticate(java.lang.String username,
java.lang.String digest, java.lang.String nonce, java.lang.String nc,
java.lang.String cnonce, java.lang.String qop, java.lang.String realm,
java.lang.String md5a2) {
return null;
}
/**
* Not supported, returns null
*
* @param x509Certificates DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Principal authenticate(X509Certificate[] x509Certificates) {
return null;
}
public boolean hasRole(Principal principal, String role) {
if (!(principal instanceof PrincipalAcegiUserToken)) {
if (logger.isWarnEnabled()) {
logger.warn(
"Expected passed principal to be of type PrincipalSpringUserToken but was "
+ principal.getClass().getName());
}
return false;
}
PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) principal;
return test.isUserInRole(role);
}
public void start() throws LifecycleException {
super.start();
if (appContextLocation == null) {
throw new LifecycleException("appContextLocation must be defined");
}
if (key == null) {
throw new LifecycleException("key must be defined");
}
File xml = new File(System.getProperty("catalina.base"),
appContextLocation);
if (!xml.exists()) {
throw new LifecycleException(
"appContextLocation does not seem to exist - try specifying conf/springsecurity.xml");
}
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(xml
.getAbsolutePath());
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) {
throw new IllegalArgumentException(
"Bean context must contain at least one bean of type AuthenticationManager");
}
String beanName = (String) beans.keySet().iterator().next();
authenticationManager = (AuthenticationManager) beans.get(beanName);
logger.info("CatalinaSpringUserRealm Started");
}
protected String getName() {
return this.name;
}
/**
* Always returns null (we override authenticate methods)
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
protected String getPassword(String arg0) {
return null;
}
/**
* Always returns null (we override authenticate methods)
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
protected Principal getPrincipal(String arg0) {
return null;
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
Adapter to Catalina web container (Tomcat).
<p>
</body>
</html>

View File

@ -0,0 +1,188 @@
/*
* 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.jboss;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
/**
* Adapter to enable JBoss to authenticate via the Acegi Security System for
* Spring.
*
* <p>
* Returns a {@link PrincipalAcegiUserToken} to JBoss' authentication system,
* which is subsequently available from
* <code>java:comp/env/security/subject</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class JbossAcegiLoginModule extends AbstractServerLoginModule {
//~ Instance fields ========================================================
private AuthenticationManager authenticationManager;
private Principal identity;
private String key;
private char[] credential;
//~ Methods ================================================================
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
super.initialize(subject, callbackHandler, sharedState, options);
this.key = (String) options.get("key");
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext((String) options
.get("appContextLocation"));
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) {
throw new IllegalArgumentException(
"Bean context must contain at least one bean of type AuthenticationManager");
}
String beanName = (String) beans.keySet().iterator().next();
authenticationManager = (AuthenticationManager) beans.get(beanName);
super.log.info("Successfully started JbossSpringLoginModule");
}
public boolean login() throws LoginException {
super.loginOk = false;
String[] info = getUsernameAndPassword();
String username = info[0];
String password = info[1];
if ((username == null) && (password == null)) {
identity = null;
super.log.trace("Authenticating as unauthenticatedIdentity="
+ identity);
}
if (identity == null) {
Authentication request = new UsernamePasswordAuthenticationToken(username,
password);
Authentication response = null;
try {
response = authenticationManager.authenticate(request);
} catch (AuthenticationException failed) {
if (super.log.isDebugEnabled()) {
super.log.debug("Bad password for username=" + username);
}
throw new FailedLoginException(
"Password Incorrect/Password Required");
}
identity = new PrincipalAcegiUserToken(this.key,
response.getPrincipal().toString(),
response.getCredentials().toString(),
response.getAuthorities());
}
if (getUseFirstPass() == true) {
// Add the username and password to the shared state map
sharedState.put("javax.security.auth.login.name", username);
sharedState.put("javax.security.auth.login.password", credential);
}
super.loginOk = true;
super.log.trace("User '" + identity + "' authenticated, loginOk="
+ loginOk);
return true;
}
protected Principal getIdentity() {
return this.identity;
}
protected Group[] getRoleSets() throws LoginException {
SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = {roles};
if (this.identity instanceof Authentication) {
Authentication user = (Authentication) this.identity;
for (int i = 0; i < user.getAuthorities().length; i++) {
roles.addMember(new SimplePrincipal(
user.getAuthorities()[i].getAuthority()));
}
}
return roleSets;
}
protected String[] getUsernameAndPassword() throws LoginException {
String[] info = {null, null};
// prompt for a username and password
if (callbackHandler == null) {
throw new LoginException("Error: no CallbackHandler available "
+ "to collect authentication information");
}
NameCallback nc = new NameCallback("User name: ", "guest");
PasswordCallback pc = new PasswordCallback("Password: ", false);
Callback[] callbacks = {nc, pc};
String username = null;
String password = null;
try {
callbackHandler.handle(callbacks);
username = nc.getName();
char[] tmpPassword = pc.getPassword();
if (tmpPassword != null) {
credential = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, credential, 0,
tmpPassword.length);
pc.clearPassword();
password = new String(credential);
}
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException("CallbackHandler does not support: "
+ uce.getCallback());
}
info[0] = username;
info[1] = password;
return info;
}
}

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.adapters.jboss;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.adapters.AbstractIntegrationFilter;
import java.security.Principal;
import java.util.Iterator;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.servlet.ServletRequest;
/**
* Populates a {@link net.sf.acegisecurity.context.SecureContext} from JBoss'
* <code>java:comp/env/security/subject</code>.
*
* <p>
* See {@link AbstractIntegrationFilter} for further information.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class JbossIntegrationFilter extends AbstractIntegrationFilter {
//~ Methods ================================================================
public Object extractFromContainer(ServletRequest request) {
Subject subject = null;
try {
InitialContext ic = new InitialContext();
subject = (Subject) ic.lookup("java:comp/env/security/subject");
} catch (NamingException ne) {
if (super.logger.isDebugEnabled()) {
super.logger.warn("Lookup on Subject failed "
+ ne.getLocalizedMessage());
}
}
if ((subject != null) && (subject.getPrincipals() != null)) {
Iterator principals = subject.getPrincipals().iterator();
while (principals.hasNext()) {
Principal p = (Principal) principals.next();
if (super.logger.isDebugEnabled()) {
super.logger.debug("Found Principal in container ("
+ p.getClass().getName() + ") : "
+ p.getName());
}
if (p instanceof Authentication) {
return p;
}
}
}
return null;
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
Adapter to JBoss.
<p>
</body>
</html>

View File

@ -0,0 +1,147 @@
/*
* 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.jetty;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.UserPrincipal;
import org.mortbay.http.UserRealm;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Map;
/**
* Adapter to enable Jetty to authenticate via the Acegi Security System for
* Spring.
*
* <p>
* Returns a {@link JettyAcegiUserToken} to Jetty's authentication system,
* which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public final class JettyAcegiUserRealm implements UserRealm {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(JettyAcegiUserRealm.class);
//~ Instance fields ========================================================
private AuthenticationManager authenticationManager;
private String key;
private String realm;
//~ Constructors ===========================================================
/**
* Construct a <code>SpringUserRealm</code>.
*
* @param realm the name of the authentication realm (within Jetty)
* @param providerKey a password to sign all authentication objects
* @param appContextLocation the classpath location of the bean context XML
* file
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public JettyAcegiUserRealm(String realm, String providerKey,
String appContextLocation) {
this.realm = realm;
this.key = providerKey;
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(appContextLocation);
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) {
throw new IllegalArgumentException(
"Bean context must contain at least one bean of type AuthenticationManager");
}
String beanName = (String) beans.keySet().iterator().next();
authenticationManager = (AuthenticationManager) beans.get(beanName);
}
private JettyAcegiUserRealm() {
super();
}
//~ Methods ================================================================
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
/**
* DOCUMENT ME!
*
* @return the name of the realm as defined when
* <code>SpringUserRealm</code> was created
*/
public String getName() {
return this.realm;
}
public UserPrincipal authenticate(String username, Object password,
HttpRequest httpRequest) {
if (username == null) {
return null;
}
if (password == null) {
password = "";
}
Authentication request = new UsernamePasswordAuthenticationToken(username
.toString(), password.toString());
Authentication response = null;
try {
response = authenticationManager.authenticate(request);
} catch (AuthenticationException failed) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication request for user: " + username
+ " failed: " + failed.toString());
}
return null;
}
return new JettyAcegiUserToken(this.key,
response.getPrincipal().toString(),
response.getCredentials().toString(), response.getAuthorities());
}
public void disassociate(UserPrincipal userPrincipal) {
// No action required
}
public void logout(UserPrincipal arg0) {
// Not supported
}
public UserPrincipal popRole(UserPrincipal userPrincipal) {
// Not supported
return userPrincipal;
}
public UserPrincipal pushRole(UserPrincipal userPrincipal, String role) {
// Not supported
return userPrincipal;
}
}

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.jetty;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.adapters.AbstractAdapterAuthenticationToken;
import org.mortbay.http.UserPrincipal;
/**
* A Jetty compatible {@link net.sf.acegisecurity.Authentication} object.
*
* @author Ben Alex
* @version $Id$
*/
public class JettyAcegiUserToken extends AbstractAdapterAuthenticationToken
implements UserPrincipal {
//~ Instance fields ========================================================
private String password;
private String username;
//~ Constructors ===========================================================
public JettyAcegiUserToken(String key, String username, String password,
GrantedAuthority[] authorities) {
super(key, authorities);
this.username = username;
this.password = password;
}
private JettyAcegiUserToken() {
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,7 @@
<html>
<body>
Adapter to Jetty web container.
<p>
</body>
</html>

View File

@ -0,0 +1,163 @@
/*
* 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.resin;
import com.caucho.http.security.AbstractAuthenticator;
import com.caucho.vfs.Path;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import java.io.File;
import java.security.Principal;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Adapter to enable Resin to authenticate via the Acegi Security System for
* Spring.
*
* <p>
* Returns a {@link PrincipalAcegiUserToken} to Resin's authentication system,
* which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class ResinAcegiAuthenticator extends AbstractAuthenticator {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(ResinAcegiAuthenticator.class);
//~ Instance fields ========================================================
private AuthenticationManager authenticationManager;
private Path appContextLocation;
private String key;
//~ Methods ================================================================
public void setAppContextLocation(Path appContextLocation) {
this.appContextLocation = appContextLocation;
}
public Path getAppContextLocation() {
return appContextLocation;
}
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public boolean isUserInRole(HttpServletRequest request,
HttpServletResponse response, ServletContext application,
Principal principal, String role) {
if (!(principal instanceof PrincipalAcegiUserToken)) {
if (logger.isWarnEnabled()) {
logger.warn(
"Expected passed principal to be of type PrincipalSpringUserToken but was "
+ principal.getClass().getName());
}
return false;
}
PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) principal;
return test.isUserInRole(role);
}
public void init() throws ServletException {
super.init();
if (appContextLocation == null) {
throw new ServletException("appContextLocation must be defined");
}
if (key == null) {
throw new ServletException("key must be defined");
}
File xml = new File(appContextLocation.getPath());
if (!xml.exists()) {
throw new ServletException(
"appContextLocation does not seem to exist - try specifying WEB-INF/resin-springsecurity.xml");
}
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(xml
.getAbsolutePath());
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) {
throw new ServletException(
"Bean context must contain at least one bean of type AuthenticationManager");
}
String beanName = (String) beans.keySet().iterator().next();
authenticationManager = (AuthenticationManager) beans.get(beanName);
logger.info("ResinSpringAuthenticator Started");
}
protected Principal loginImpl(String username, String credentials) {
if (username == null) {
return null;
}
if (credentials == null) {
credentials = "";
}
Authentication request = new UsernamePasswordAuthenticationToken(username,
credentials);
Authentication response = null;
try {
response = authenticationManager.authenticate(request);
} catch (AuthenticationException failed) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication request for user: " + username
+ " failed: " + failed.toString());
}
return null;
}
return new PrincipalAcegiUserToken(this.key,
response.getPrincipal().toString(),
response.getCredentials().toString(), response.getAuthorities());
}
protected Principal loginImpl(HttpServletRequest request,
HttpServletResponse response, ServletContext application,
String userName, String password) throws ServletException {
return loginImpl(userName, password);
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
Adapter to Resin web container.
<p>
</body>
</html>

464
build.xml Normal file
View File

@ -0,0 +1,464 @@
<?xml version="1.0"?>
<!--
Build file for the Acegi Security System for Spring.
$Id$
-->
<project name="acegi-security-core" default="usage" basedir=".">
<property file="build.properties"/>
<property file="project.properties"/>
<path id="qa-portalpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<path id="jalopy-classpath">
<fileset dir="${lib.dir}/jalopy">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="usage">
<echo message=""/>
<echo message="${name} build file"/>
<echo message="------------------------------------------------------"/>
<echo message=""/>
<echo message="Among the available targets are:"/>
<echo message=""/>
<echo message="build --> build all; don't create JARs"/>
<echo message="alljars --> create all JAR files"/>
<echo message="format --> format/tidy all source code"/>
<echo message="tests --> run tests"/>
<echo message="release --> build a distribution ZIP file"/>
<echo message=""/>
<echo message="To build or test, your lib directory needs to be populated"/>
</target>
<target name="clean" description="Clean all output dirs (dist, javadocs, classes, test-classes, etc.)">
<delete dir="${dist.dir}"/>
<delete dir="${javadocs.dir}"/>
<delete dir="${target.classes.dir}"/>
<delete dir="${target.junit.reports.dir}"/>
<delete dir="${target.otherclasses.dir}"/>
<delete dir="${target.release.dir}"/>
<delete dir="${target.testclasses.dir}"/>
</target>
<!--
Compile the main source tree.
-->
<target name="build"
depends=""
description="Compile main source tree java files into class files (no-jarring)">
<mkdir dir="${target.classes.dir}"/>
<javac destdir="${target.classes.dir}" target="1.3" debug="${debug}"
deprecation="false" optimize="false" failonerror="true">
<src path="${src.dir}"/>
<classpath refid="qa-portalpath"/>
</javac>
<copy todir="${target.classes.dir}" preservelastmodified="true">
<fileset dir="${src.dir}">
<include name="**/*.xml"/>
</fileset>
</copy>
</target>
<target name="format" description="Formats all project source code">
<taskdef name="jalopy" classname="de.hunsicker.jalopy.plugin.ant.AntPlugin">
<classpath refid="jalopy-classpath"/>
</taskdef>
<jalopy fileformat="unix"
convention="${jalopy.xml}"
history="file"
historymethod="adler32"
loglevel="error"
threads="2"
classpathref="qa-portalpath">
<fileset dir="${src.dir}">
<include name="**/*.java"/>
</fileset>
<fileset dir="${test.dir}">
<include name="**/*.java"/>
</fileset>
</jalopy>
<ant inheritall="no" antfile="build.xml" dir="samples/contacts" target="format"/>
<ant inheritall="no" antfile="build.xml" dir="samples/attributes" target="format"/>
<ant inheritall="no" antfile="build.xml" dir="integration-test" target="format"/>
</target>
<target name="initdist" description="Initialize the distribution directory">
<mkdir dir="${dist.dir}"/>
</target>
<target name="fulljar" depends="build,initdist" description="Create JAR file with all Acegi Security System for Spring classes">
<delete file="${dist.dir}/${acegi-security.jar}"/>
<!-- An all classes JAR file, which is provided for compiling web apps
only (at runtime all classes should be from web container) -->
<jar jarfile="${dist.dir}/${acegi-security.jar}">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/**"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
<!-- The class that has catalina.jar dependencies and thus belongs in
Catalina's "Catalina" classloader ($CATALINA_HOME/server/lib directory) -->
<jar jarfile="${dist.dir}/acegi-security-catalina-server.jar">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/adapters/catalina/CatalinaAcegiUserRealm.class"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
<!-- All Acegi Security System for Spring classes that belong in Catalina's
"Common" classloader ($CATALINA_HOME/common/lib directory) -->
<jar jarfile="${dist.dir}/acegi-security-catalina-common.jar">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/*"/>
<include name="net/sf/acegisecurity/context/**"/>
<include name="net/sf/acegisecurity/providers/**"/>
<include name="net/sf/acegisecurity/runas/**"/>
<include name="net/sf/acegisecurity/vote/**"/>
<include name="net/sf/acegisecurity/adapters/*"/>
<include name="net/sf/acegisecurity/adapters/catalina/*"/>
<exclude name="net/sf/acegisecurity/adapters/catalina/CatalinaAcegiUserRealm.class"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
<!-- All Acegi Security System for Spring classes that belong in Jetty's
"ext" directory -->
<jar jarfile="${dist.dir}/acegi-security-jetty-ext.jar">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/*"/>
<include name="net/sf/acegisecurity/context/**"/>
<include name="net/sf/acegisecurity/providers/**"/>
<include name="net/sf/acegisecurity/runas/**"/>
<include name="net/sf/acegisecurity/vote/**"/>
<include name="net/sf/acegisecurity/adapters/*"/>
<include name="net/sf/acegisecurity/adapters/jetty/*"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
<!-- All Acegi Security System for Spring classes that belong in JBoss'
"server/your_config/lib" directory -->
<jar jarfile="${dist.dir}/acegi-security-jboss-lib.jar">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/*"/>
<include name="net/sf/acegisecurity/context/**"/>
<include name="net/sf/acegisecurity/providers/**"/>
<include name="net/sf/acegisecurity/runas/**"/>
<include name="net/sf/acegisecurity/vote/**"/>
<include name="net/sf/acegisecurity/adapters/*"/>
<include name="net/sf/acegisecurity/adapters/jboss/*"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
<!-- All Acegi Security System for Spring classes that belong in
Resin's "lib" directory -->
<jar jarfile="${dist.dir}/acegi-security-resin-lib.jar">
<fileset dir="${target.classes.dir}">
<include name="net/sf/acegisecurity/*"/>
<include name="net/sf/acegisecurity/context/**"/>
<include name="net/sf/acegisecurity/providers/**"/>
<include name="net/sf/acegisecurity/runas/**"/>
<include name="net/sf/acegisecurity/vote/**"/>
<include name="net/sf/acegisecurity/adapters/*"/>
<include name="net/sf/acegisecurity/adapters/resin/*"/>
</fileset>
<manifest>
<attribute name="Acegi-Security-System-version" value="${acegi-security-version}"/>
</manifest>
</jar>
</target>
<target name="srczip" depends="initdist" description="Create source ZIP (containing all Java sources)">
<delete file="${dist.dir}/${acegi-security-src.zip}"/>
<zip zipfile="${dist.dir}/${acegi-security-src.zip}">
<fileset dir="${src.dir}">
<include name="net/sf/acegisecurity/**"/>
<include name="net/sf/acegisecurity/context/**"/>
</fileset>
</zip>
</target>
<target name="alljars" depends="fulljar,srczip" description="Create all JAR files"/>
<target name="javadoc" description="Generate Javadocs.">
<mkdir dir="${javadocs.dir}"/>
<javadoc sourcepath="src" destdir="${javadocs.dir}" windowtitle="Acegi Security System for Spring"
defaultexcludes="yes" author="true" version="true" use="true">
<doctitle><![CDATA[<h1>Acegi Security System for Spring</h1>]]></doctitle>
<bottom><![CDATA[<A HREF="http://acegisecurity.sourceforge.net">Acegi Security System for Spring Project]]></bottom>
<classpath refid="qa-portalpath"/>
<packageset dir="${src.dir}">
<include name="net/sf/acegisecurity/**"/>
<include name="net/sf/acegisecurity/context/**"/>
</packageset>
</javadoc>
</target>
<target name="release" depends="clean,alljars,format,tests,javadoc,refdoc" description="Generate release zip file">
<ant inheritall="no" antfile="build.xml" dir="samples/contacts" target="release"/>
<ant inheritall="no" antfile="build.xml" dir="samples/attributes" target="release"/>
<delete dir="${target.release.dir}"/>
<mkdir dir="${target.release.dir}"/>
<fileset id="main" dir=".">
<include name="dist/*.jar"/>
<include name="docs/**"/>
<exclude name="docs/reference/lib/**"/>
<include name="extractor/*"/>
<include name="extractor/source/*"/>
<include name="integration-test/**"/>
<exclude name="integration-test/lib/**"/>
<exclude name="integration-test/build.properties"/>
<exclude name="integration-test/classes/**"/>
<exclude name="integration-test/containers/**"/>
<exclude name="integration-test/reports/**"/>
<exclude name="integration-test/temporary/**"/>
<include name="samples/**"/>
<exclude name="samples/contacts/classes/**"/>
<exclude name="samples/contacts/build.properties"/>
<exclude name="samples/attributes/classes/**"/>
<exclude name="samples/attributes/reports/**"/>
<exclude name="samples/attributes/generated/**"/>
<include name="src/**"/>
<include name="test/**"/>
<include name="hsqldb/**"/>
<include name="*.txt"/>
<include name="*.xml"/>
<exclude name="project.properties"/>
</fileset>
<zip zipfile="${target.release.dir}/${release.zip}">
<zipfileset refid="main" prefix="${release.path}"/>
</zip>
<zip zipfile="${target.release.dir}/${release-with-dependencies.zip}">
<zipfileset refid="main" prefix="${release.path}"/>
<zipfileset dir="." prefix="${release.path}">
<include name="lib/**"/>
<include name="integration-test/lib/**"/>
</zipfileset>
</zip>
</target>
<!--
Compile test cases
-->
<target name="buildtests" depends="" description="Compile test source tree Java files into class files">
<mkdir dir="${target.testclasses.dir}"/>
<javac destdir="${target.testclasses.dir}" target="1.3" debug="${debug}"
deprecation="false" optimize="false" failonerror="true">
<src path="${test.dir}"/>
<classpath refid="qa-portalpath"/>
<classpath location="${target.classes.dir}"/>
</javac>
<!-- Pick up logging config from test directory -->
<copy todir="${target.testclasses.dir}" preservelastmodified="true">
<fileset dir="${test.dir}">
<include name="**/*.properties"/>
</fileset>
</copy>
</target>
<!--
Run tests.
-->
<target name="tests" depends="buildtests" description="Run tests.">
<property name="reports.dir" value="${target.junit.reports.dir}"/>
<delete dir="${reports.dir}"/>
<mkdir dir="${reports.dir}"/>
<junit printsummary="yes" haltonfailure="yes">
<!-- Must go first to ensure any jndi.properties files etc take precedence -->
<classpath location="${target.testclasses.dir}"/>
<classpath location="${target.classes.dir}"/>
<!-- Need files loaded as resources -->
<classpath location="${test.dir}"/>
<classpath refid="qa-portalpath"/>
<formatter type="plain"/>
<batchtest fork="yes" todir="${reports.dir}">
<fileset dir="${target.testclasses.dir}" includes="${test.includes}" excludes="${test.excludes}"/>
</batchtest>
</junit>
</target>
<target name="docclean" description="Delete temporary and distribution directories for docs">
<delete quiet="true" dir="${basedir}/${dist.ref.dir}/pdf"/>
<delete quiet="true" dir="${basedir}/${dist.ref.dir}/html_single"/>
<delete quiet="true" dir="${basedir}/${dist.ref.dir}/html"/>
</target>
<target name="preparedocs" description="Extra preparation for the documentation">
<!-- For now, no dynamic inclusion of the DTD since it looks ugly because of
all the extra newlines the replace is mysteriously adding.
I'll figure something out for that later on
<delete file="${basedir}/${doc.ref.dir}/src/dtd.xml"/>
<loadfile
property="doc.beansdtd"
srcFile="${src.dir}/org/springframework/beans/factory/xml/spring-beans.dtd"/>
<copy
file="${basedir}/${doc.ref.dir}/src/dtd-template.xml"
tofile="${basedir}/${doc.ref.dir}/src/dtd.xml"/>
<replace
file="${basedir}/${doc.ref.dir}/src/dtd.xml"
token="@dtd-include@"
value="${doc.beansdtd}">
</replace>
<replace
file="${basedir}/${doc.ref.dir}/src/dtd.xml"
token="\\n"
value=""/>
-->
</target>
<target name="docpdf" depends="preparedocs" description="Compile reference documentation to pdf">
<mkdir dir="${basedir}/${dist.ref.dir}/pdf/images"/>
<copy todir="${basedir}/${dist.ref.dir}/pdf/images">
<fileset dir="${basedir}/${doc.ref.dir}/src/images">
<include name="*.gif"/>
<include name="*.svg"/>
<include name="*.jpg"/>
</fileset>
</copy>
<java classname="com.icl.saxon.StyleSheet" fork="true" dir="${doc.ref.dir}">
<classpath>
<fileset dir="${basedir}/${doc.ref.dir}/lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
<arg value="-o"/>
<arg value="${basedir}/${dist.ref.dir}/pdf/docbook_fop.tmp"/>
<arg value="${basedir}/${doc.ref.dir}/src/index.xml"/>
<arg value="${basedir}/${doc.ref.dir}/styles/fopdf.xsl"/>
</java>
<java classname="org.apache.fop.apps.Fop" fork="true" dir="${doc.ref.dir}">
<classpath>
<fileset dir="${basedir}/${doc.ref.dir}/lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
<arg value="${basedir}/${dist.ref.dir}/pdf/docbook_fop.tmp"/>
<arg value="${basedir}/${dist.ref.dir}/pdf/acegi-security-reference.pdf"/>
</java>
<delete file="${dist.ref.dir}/pdf/docbook_fop.tmp"/>
</target>
<target name="dochtml" depends="preparedocs" description="Compile reference documentation to chunked html">
<mkdir dir="${dist.ref.dir}/html/images"/>
<copy todir="${basedir}/${dist.ref.dir}/html/images">
<fileset dir="${basedir}/${doc.ref.dir}/src/images">
<include name="*.gif"/>
<include name="*.svg"/>
<include name="*.jpg"/>
</fileset>
</copy>
<java classname="com.icl.saxon.StyleSheet" fork="true" dir="${dist.ref.dir}/html/">
<classpath>
<fileset dir="${basedir}/${doc.ref.dir}/lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
<arg value="${basedir}/${doc.ref.dir}/src/index.xml"/>
<arg value="${basedir}/${doc.ref.dir}/styles/html_chunk.xsl"/>
</java>
</target>
<target name="dochtmlsingle" description="Compile reference documentation to single html">
<mkdir dir="${dist.ref.dir}/html_single/images"/>
<copy todir="${basedir}/${dist.ref.dir}/html_single/images">
<fileset dir="${basedir}/${doc.ref.dir}/src/images">
<include name="*.gif"/>
<include name="*.svg"/>
<include name="*.jpg"/>
</fileset>
</copy>
<java classname="com.icl.saxon.StyleSheet" fork="true" dir="${doc.ref.dir}">
<classpath>
<fileset dir="${basedir}/${doc.dir}/reference/lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
<arg value="-o"/>
<arg value="${basedir}/${dist.ref.dir}/html_single/index.html"/>
<arg value="${basedir}/${doc.ref.dir}/src/index.xml"/>
<arg value="${basedir}/${doc.ref.dir}/styles/html.xsl"/>
</java>
</target>
<target name="refdoc" depends="dochtml,dochtmlsingle,docpdf" description="Generate and copy reference documentation"/>
</project>

39
changelog.txt Normal file
View File

@ -0,0 +1,39 @@
Changes in version 0.3 (2004-03-16)
-----------------------------------
* Added "in container" unit test system for container adapters and sample app
* Added library extractor tool to reduce the "with deps" ZIP release sizes
* Added unit test to the attributes sample
* Added Jalopy source formatting
* Modified all files to use net.sf.acegisecurity namespace
* Renamed springsecurity.xml to acegisecurity.xml for consistency
* Reduced length of ZIP and JAR filenames
* Clarified licenses and sources for all included libraries
* Updated documentation to reflect new file and package names
* Setup Sourceforge.net project and added to CVS etc
Changes in version 0.2 (2004-03-10)
-----------------------------------
* Added Commons Attributes support and sample (thanks to Cameron Braid)
* Added JBoss container adapter
* Added Resin container adapter
* Added JDBC DAO authentication provider
* Added several filter implementations for container adapter integration
* Added SecurityInterceptor startup time validation of ConfigAttributes
* Added more unit tests
* Refactored ConfigAttribute to interface and added concrete implementation
* Enhanced diagnostics information provided by sample application debug.jsp
* Modified sample application for wider container portability (Resin, JBoss)
* Fixed switch block in voting decision manager implementations
* Removed Spring MVC interceptor for container adapter integration
* Documentation improvements
Changes in version 0.1 (2004-03-03)
-----------------------------------
* Initial public release
$Id$

15
contributors.txt Normal file
View File

@ -0,0 +1,15 @@
===============================================================================
ACEGI SECURITY SYSTEM FOR SPRING - CONTRIBUTORS
===============================================================================
The following people and organisations are gratefully acknowledged for their
contributions to the Acegi Security System for Spring project:
* Ben Alex of Acegi Technology Pty Limited (http://www.acegi.com.au) donated
the original code and currently maintains the project.
* Cameron Braid added support for configuration using Commons Attributes.
$Id$

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>

View File

@ -0,0 +1,88 @@
/*
* 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.vote.AccessDecisionVoter;
import org.aopalliance.intercept.MethodInvocation;
import java.util.Iterator;
/**
* Implementation of an {@link AccessDecisionVoter} that provides a token
* example of application-specific security.
*
* <p>
* If the {@link ConfigAttribute#getAttribute()} has a value of
* <code>BANKSECURITY_CUSTOMER</code>, the account number subject of the
* method call to be compared with any granted authority prefixed with
* <code>ACCOUNT_</code> and followed by that account number. For example, if
* account number 12 was subject of the call, a search would be conducted for
* a granted authority named <code>ACCOUNT_12</code>.
* </p>
*
* <p>
* All comparisons are case sensitive.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class BankSecurityVoter implements AccessDecisionVoter {
//~ Methods ================================================================
public boolean supports(ConfigAttribute attribute) {
if ("BANKSECURITY_CUSTOMER".equals(attribute.getAttribute())) {
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;
// Lookup the account number being passed
Integer accountNumber = null;
for (int i = 0; i < invocation.getArgumentCount(); i++) {
Class argClass = invocation.getArgument(i).getClass();
if (Integer.class.isAssignableFrom(argClass)) {
accountNumber = (Integer) invocation.getArgument(i);
}
}
if (accountNumber != null) {
// Attempt to find a matching granted authority
String targetAttribute = "ACCOUNT_"
+ accountNumber.toString();
for (int i = 0; i < authentication.getAuthorities().length;
i++) {
if (targetAttribute.equals(
authentication.getAuthorities()[i].getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
}
return result;
}
}

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;
import net.sf.acegisecurity.context.ContextInvalidException;
import net.sf.acegisecurity.context.SecureContextImpl;
/**
* Demonstrates subclassing the {@link SecureContextImpl} with
* application-specific requirements.
*
* @author Ben Alex
* @version $Id$
*/
public class ExoticSecureContext extends SecureContextImpl {
//~ Instance fields ========================================================
private int magicNumber;
//~ Methods ================================================================
public void setMagicNumber(int magicNumber) {
this.magicNumber = magicNumber;
}
public int getMagicNumber() {
return magicNumber;
}
public void validate() throws ContextInvalidException {
super.validate();
if (magicNumber != 7) {
throw new ContextInvalidException("Magic number is not 7");
}
}
}

View File

@ -0,0 +1,217 @@
/*
* 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 junit.framework.TestCase;
import net.sf.acegisecurity.context.Account;
import net.sf.acegisecurity.context.BankManager;
import net.sf.acegisecurity.context.Context;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.ContextImpl;
import net.sf.acegisecurity.context.SecureContext;
import net.sf.acegisecurity.context.SecureContextImpl;
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Tests security objects.
*
* @author Ben Alex
* @version $Id$
*/
public class SecurityTests extends TestCase {
//~ Instance fields ========================================================
private ClassPathXmlApplicationContext ctx;
//~ Constructors ===========================================================
public SecurityTests() {
super();
}
public SecurityTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
ctx = new ClassPathXmlApplicationContext(
"/net/sf/acegisecurity/applicationContext.xml");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(SecurityTests.class);
}
public void testDetectsInvalidConfigAttribute() throws Exception {
try {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"/net/sf/acegisecurity/badContext.xml");
fail("Should have thrown BeanCreationException");
} catch (BeanCreationException expected) {
assertTrue(true);
}
}
public void testSecurityInterceptorCustomVoter() throws Exception {
Account marissa = new Account(2, "marissa");
BankManager bank = (BankManager) ctx.getBean("bankManager");
// Indicate the authenticated user holds an account number of 65
GrantedAuthority[] useless = {new GrantedAuthorityImpl("ACCOUNT_65")};
TestingAuthenticationToken auth = new TestingAuthenticationToken("Peter",
"emu", useless);
SecureContext secureContext = new SecureContextImpl();
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
// Confirm the absence of holding a valid account number rejects access
try {
bank.saveAccount(marissa);
fail("Should have thrown an AccessDeniedException");
} catch (AccessDeniedException expected) {
assertTrue(true);
}
// Now setup a user with the correct account number
GrantedAuthority[] account2 = {new GrantedAuthorityImpl("ACCOUNT_2")};
auth = new TestingAuthenticationToken("Kristy", "opal", account2);
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
// Check the user can perform operations related to their account number
bank.loadAccount(marissa.getId());
ContextHolder.setContext(null);
}
public void testSecurityInterceptorDetectsInvalidContexts()
throws Exception {
// Normally the security interceptor does not need to detect these conditions,
// because the context interceptor should with its validate method. However,
// the security interceptor still checks it is passed the correct objects.
Account ben = new Account(1, "ben");
BankManager bank = (BankManager) ctx.getBean("bankManager");
// First try with a totally empty ContextHolder
try {
bank.saveAccount(ben);
fail(
"Should have thrown AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
assertTrue(true);
}
// Now try with a ContextHolder but of the wrong type (not a SecureContext)
Context context = new ContextImpl();
ContextHolder.setContext(context);
try {
bank.saveAccount(ben);
fail(
"Should have thrown AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
assertTrue(true);
}
// Next try with a SecureContext but without an authentication object in it
SecureContext secureContext = new SecureContextImpl();
ContextHolder.setContext((Context) secureContext);
try {
bank.saveAccount(ben);
fail(
"Should have thrown AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
assertTrue(true);
}
// Now try with a SecureContext, correctly setup, which should work
GrantedAuthority[] granted = {new GrantedAuthorityImpl(
"ROLE_SUPERVISOR")};
TestingAuthenticationToken auth = new TestingAuthenticationToken("Jeni",
"kangaroo", granted);
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
Account marissa = new Account(2, "marissa");
marissa.deposit(2000);
bank.saveAccount(marissa);
assertTrue(2000 == bank.getBalance(marissa.getId()));
// Now confirm if we subclass SecureContextImpl it still works.
// Note the validate method in our ExoticSecureContext will not be
// called, as we do not have the context interceptor defined.
ExoticSecureContext exoticContext = new ExoticSecureContext();
exoticContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
Account scott = new Account(3, "scott");
scott.deposit(50);
bank.saveAccount(scott);
assertTrue(50 == bank.getBalance(scott.getId()));
ContextHolder.setContext(null);
}
public void testSecurityInterceptorEnforcesRoles()
throws Exception {
Account ben = new Account(1, "ben");
ben.deposit(25);
BankManager bank = (BankManager) ctx.getBean("bankManager");
// Indicate the authenticated user holds a role that is not useful
GrantedAuthority[] useless = {new GrantedAuthorityImpl(
"ROLE_NOTHING_USEFUL")};
TestingAuthenticationToken auth = new TestingAuthenticationToken("George",
"koala", useless);
SecureContext secureContext = new SecureContextImpl();
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
// Confirm the absence of holding a valid role rejects access
try {
bank.saveAccount(ben);
fail("Should have thrown an AccessDeniedException");
} catch (AccessDeniedException expected) {
assertTrue(true);
}
// Now try to call a public method (getBankFundsUnderControl)
bank.getBankFundsUnderControl();
// Now setup a user with only a teller role
GrantedAuthority[] teller = {new GrantedAuthorityImpl("ROLE_TELLER")};
auth = new TestingAuthenticationToken("Michelle", "wombat", teller);
secureContext.setAuthentication(auth);
ContextHolder.setContext((Context) secureContext);
// Confirm the absence of ROLE_SUPERVISOR prevents calling deleteAccount
try {
bank.deleteAccount(ben.getId());
fail("Should have thrown an AccessDeniedException");
} catch (AccessDeniedException expected) {
assertTrue(true);
}
// Check the teller can perform ROLE_TELLER secured operations
bank.saveAccount(ben);
assertTrue(25 == bank.getBalance(ben.getId()));
ContextHolder.setContext(null);
}
}

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.adapters;
import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.adapters.jetty.JettyAcegiUserToken;
import net.sf.acegisecurity.providers.ProviderNotFoundException;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Tests {@link AuthByAdapterProvider}
*
* @author Ben Alex
* @version $Id$
*/
public class AuthByAdapterTests extends TestCase {
//~ Instance fields ========================================================
private ClassPathXmlApplicationContext ctx;
//~ Constructors ===========================================================
public AuthByAdapterTests() {
super();
}
public AuthByAdapterTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
ctx = new ClassPathXmlApplicationContext(
"/net/sf/acegisecurity/adapters/applicationContext.xml");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(AuthByAdapterTests.class);
}
public void testAdapterProvider() throws Exception {
AuthenticationManager authMgr = (AuthenticationManager) ctx.getBean(
"providerManager");
// Should authenticate as JettySpringUser is interface of AuthByAdapter
JettyAcegiUserToken jetty = new JettyAcegiUserToken("my_password",
"Test", "Password", null);
Authentication response = authMgr.authenticate(jetty);
jetty = null;
assertTrue(true);
// Should fail as UsernamePassword is not interface of AuthByAdapter
UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken("Test",
"Password");
try {
Authentication response2 = authMgr.authenticate(user);
fail("Should have thrown ProviderNotFoundException");
} catch (ProviderNotFoundException expected) {
assertTrue(true);
}
}
}

View File

@ -0,0 +1,29 @@
<?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>
<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
<!-- Authentication provider that accepts as valid any adapter-created Authentication token -->
<bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider">
<property name="key"><value>my_password</value></property>
</bean>
<!-- The authentication manager that iterates through our authentication providers -->
<bean id="providerManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="authByAdapterProvider"/>
</list>
</property>
</bean>
</beans>

View File

@ -0,0 +1,84 @@
<?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>
<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
<!-- RunAsManager -->
<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
<!-- This authentication provider accepts any presented TestingAuthenticationToken -->
<bean id="testingAuthenticationProvider" class="net.sf.acegisecurity.providers.TestingAuthenticationProvider"/>
<!-- 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="testingAuthenticationProvider"/>
</list>
</property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->
<!-- An access decision voter that reads ROLE_* configuaration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads BANKSECURITY_CUSTOMER configuaration settings -->
<bean id="bankSecurityVoter" class="net.sf.acegisecurity.BankSecurityVoter"/>
<!-- An affirmative access decision manager -->
<bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
<ref bean="bankSecurityVoter"/>
</list>
</property>
</bean>
<!-- ===================== SECURITY DEFINITIONS ======================= -->
<!-- No declaration for BankManager.getBankFundsUnderControl() makes it public -->
<bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
<property name="runAsManager"><ref bean="runAsManager"/></property>
<property name="methodDefinitionSource">
<value>
net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR
net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER
net.sf.acegisecurity.context.BankManager.loadAccount=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER
net.sf.acegisecurity.context.BankManager.saveAccount=ROLE_TELLER,ROLE_SUPERVISOR
net.sf.acegisecurity.context.BankManager.transferFunds=ROLE_SUPERVISOR
</value>
</property>
</bean>
<!-- ======================= BUSINESS DEFINITIONS ===================== -->
<bean id="bankManagerTarget" class="net.sf.acegisecurity.context.BankManagerImpl"/>
<!-- We don't include any context interceptor, although we should do so prior to the security interceptor -->
<bean id="bankManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>net.sf.acegisecurity.context.BankManager</value></property>
<property name="interceptorNames">
<list>
<value>bankManagerSecurity</value>
<value>bankManagerTarget</value>
</list>
</property>
</bean>
</beans>

View File

@ -0,0 +1,141 @@
/*
* 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.attribute;
import junit.framework.TestCase;
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.MethodDefinitionAttributes;
import net.sf.acegisecurity.SecurityConfig;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContextImpl;
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* DOCUMENT ME!
*
* @author CameronBraid
*/
public class AttributesTests extends TestCase {
//~ Instance fields ========================================================
ClassPathXmlApplicationContext applicationContext;
//~ Constructors ===========================================================
/**
*
*/
public AttributesTests(String a) {
super(a);
}
//~ Methods ================================================================
public void testAttributesForImpl() throws Exception {
ConfigAttributeDefinition def = getConfigAttributeDefinition(TestServiceImpl.class);
Set set = toSet(def);
assertTrue(set.contains(new SecurityConfig("ROLE_INTERFACE")));
assertTrue(set.contains(new SecurityConfig("ROLE_INTERFACE_METHOD")));
assertTrue(set.contains(new SecurityConfig("ROLE_CLASS")));
assertTrue(set.contains(new SecurityConfig("ROLE_CLASS_METHOD")));
}
public void testAttributesForInterface() throws Exception {
ConfigAttributeDefinition def = getConfigAttributeDefinition(TestService.class);
Set set = toSet(def);
System.out.println(set.toString());
assertTrue(set.contains(new SecurityConfig("ROLE_INTERFACE")));
assertTrue(set.contains(new SecurityConfig("ROLE_INTERFACE_METHOD")));
}
public void testInterceptionWithMockAttributesAndSecureContext()
throws Exception {
applicationContext = new ClassPathXmlApplicationContext(
"/net/sf/acegisecurity/attribute/applicationContext.xml");
TestService service = (TestService) applicationContext.getBean(
"testService");
SecureContextImpl context = new SecureContextImpl();
ContextHolder.setContext(context);
Authentication auth;
auth = new TestingAuthenticationToken("test", "test",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_CLASS"), new GrantedAuthorityImpl(
"ROLE_INTERFACE"), new GrantedAuthorityImpl(
"ROLE_CLASS_METHOD"), new GrantedAuthorityImpl(
"ROLE_INTERFACE_METHOD")});
context.setAuthentication(auth);
service.myMethod();
auth = new TestingAuthenticationToken("test", "test",
new GrantedAuthority[] {});
context.setAuthentication(auth);
try {
service.myMethod();
fail(
"security interceptor should have detected insufficient permissions");
} catch (Exception e) {}
applicationContext.close();
ContextHolder.setContext(null);
}
private ConfigAttributeDefinition getConfigAttributeDefinition(Class clazz)
throws Exception {
final Method method = clazz.getMethod("myMethod", null);
MethodDefinitionAttributes source = new MethodDefinitionAttributes();
source.setAttributes(new TestAttributes());
ConfigAttributeDefinition config = source.getAttributes(new MockMethodInvocation() {
public Method getMethod() {
return method;
}
});
return config;
}
/**
* convert a ConfigAttributeDefinition into a set of
* <code>ConfigAttribute</code>(s)
*
* @param def DOCUMENT ME!
*
* @return
*/
private Set toSet(ConfigAttributeDefinition def) {
Set set = new HashSet();
Iterator i = def.getConfigAttributes();
while (i.hasNext()) {
ConfigAttribute a = (ConfigAttribute) i.next();
set.add(a);
}
return set;
}
}

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.attribute;
import org.springframework.metadata.Attributes;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
/**
* DOCUMENT ME!
*
* @author CameronBraid
*/
public class MockAttributes implements Attributes {
//~ Methods ================================================================
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.Class, java.lang.Class)
*/
public Collection getAttributes(Class arg0, Class arg1) {
throw new UnsupportedOperationException("mock method not implemented");
}
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.Class)
*/
public Collection getAttributes(Class arg0) {
throw new UnsupportedOperationException("mock method not implemented");
}
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.reflect.Field, java.lang.Class)
*/
public Collection getAttributes(Field arg0, Class arg1) {
throw new UnsupportedOperationException("mock method not implemented");
}
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.reflect.Field)
*/
public Collection getAttributes(Field arg0) {
throw new UnsupportedOperationException("mock method not implemented");
}
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.reflect.Method, java.lang.Class)
*/
public Collection getAttributes(Method arg0, Class arg1) {
throw new UnsupportedOperationException("mock method not implemented");
}
/* (non-Javadoc)
* @see org.springframework.metadata.Attributes#getAttributes(java.lang.reflect.Method)
*/
public Collection getAttributes(Method arg0) {
throw new UnsupportedOperationException("mock method not implemented");
}
}

Some files were not shown because too many files have changed in this diff Show More