Initial commit.
This commit is contained in:
commit
35fe1e7b73
|
@ -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>
|
|
@ -0,0 +1,5 @@
|
||||||
|
dist
|
||||||
|
target
|
||||||
|
build.properties
|
||||||
|
*.log
|
||||||
|
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Adapter to Catalina web container (Tomcat).
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Adapter to JBoss.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Adapter to Jetty web container.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Adapter to Resin web container.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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>
|
|
@ -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$
|
|
@ -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$
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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())));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Provides "adapters" so that containers can authenticate with the
|
||||||
|
Acegi Security System for Spring.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
An authentication provider that relies upon a data access object.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Implements a provider-based approach to authorization decisions.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Allows intercepted methods to be run under a different authentication identity.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Exposes a JDBC-based authentication repository.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Exposes an in-memory authentication repository.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Implements a vote-based approach to authorization decisions.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
Loading…
Reference in New Issue