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