commit 35fe1e7b73ca1f12bfea0a9cdde9aadf40a53e65 Author: Ben Alex Date: Tue Mar 16 23:57:17 2004 +0000 Initial commit. diff --git a/.classpath b/.classpath new file mode 100644 index 0000000000..7c5deba380 --- /dev/null +++ b/.classpath @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000000..eca46bd805 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,5 @@ +dist +target +build.properties +*.log + diff --git a/.project b/.project new file mode 100644 index 0000000000..6b1579d588 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + acegisecurity + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/CatalinaAcegiUserRealm.java b/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/CatalinaAcegiUserRealm.java new file mode 100644 index 0000000000..bda6830aa4 --- /dev/null +++ b/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/CatalinaAcegiUserRealm.java @@ -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. + * + *

+ * Returns a {@link PrincipalAcegiUserToken} to Catalina's authentication + * system, which is subsequently available via + * HttpServletRequest.getUserPrincipal(). + *

+ * + * @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; + } +} diff --git a/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/package.html b/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/package.html new file mode 100644 index 0000000000..108b431840 --- /dev/null +++ b/adapters/catalina/src/main/java/org/acegisecurity/adapters/catalina/package.html @@ -0,0 +1,7 @@ + + +Adapter to Catalina web container (Tomcat). +

+ + + diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java new file mode 100644 index 0000000000..5abe9a5774 --- /dev/null +++ b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java @@ -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. + * + *

+ * Returns a {@link PrincipalAcegiUserToken} to JBoss' authentication system, + * which is subsequently available from + * java:comp/env/security/subject. + *

+ * + * @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; + } +} diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java new file mode 100644 index 0000000000..1a3aa74e7a --- /dev/null +++ b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java @@ -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' + * java:comp/env/security/subject. + * + *

+ * See {@link AbstractIntegrationFilter} for further information. + *

+ * + * @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; + } +} diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/package.html b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/package.html new file mode 100644 index 0000000000..51d3d07932 --- /dev/null +++ b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/package.html @@ -0,0 +1,7 @@ + + +Adapter to JBoss. +

+ + + diff --git a/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserRealm.java b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserRealm.java new file mode 100644 index 0000000000..76b14aacaf --- /dev/null +++ b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserRealm.java @@ -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. + * + *

+ * Returns a {@link JettyAcegiUserToken} to Jetty's authentication system, + * which is subsequently available via + * HttpServletRequest.getUserPrincipal(). + *

+ * + * @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 SpringUserRealm. + * + * @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 + * SpringUserRealm 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; + } +} diff --git a/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserToken.java b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserToken.java new file mode 100644 index 0000000000..ace27aa91e --- /dev/null +++ b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/JettyAcegiUserToken.java @@ -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; + } +} diff --git a/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/package.html b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/package.html new file mode 100644 index 0000000000..f307ffa811 --- /dev/null +++ b/adapters/jetty/src/main/java/org/acegisecurity/adapters/jetty/package.html @@ -0,0 +1,7 @@ + + +Adapter to Jetty web container. +

+ + + diff --git a/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/ResinAcegiAuthenticator.java b/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/ResinAcegiAuthenticator.java new file mode 100644 index 0000000000..b01863c3c8 --- /dev/null +++ b/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/ResinAcegiAuthenticator.java @@ -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. + * + *

+ * Returns a {@link PrincipalAcegiUserToken} to Resin's authentication system, + * which is subsequently available via + * HttpServletRequest.getUserPrincipal(). + *

+ * + * @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); + } +} diff --git a/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/package.html b/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/package.html new file mode 100644 index 0000000000..e9c986fb64 --- /dev/null +++ b/adapters/resin/src/main/java/org/acegisecurity/adapters/resin/package.html @@ -0,0 +1,7 @@ + + +Adapter to Resin web container. +

+ + + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000000..35b1ecb5ca --- /dev/null +++ b/build.xml @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Acegi Security System for Spring]]> + Acegi Security System for Spring Project]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000000..9b2e006946 --- /dev/null +++ b/changelog.txt @@ -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$ diff --git a/contributors.txt b/contributors.txt new file mode 100644 index 0000000000..7fef58d1b6 --- /dev/null +++ b/contributors.txt @@ -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$ diff --git a/core/src/main/java/org/acegisecurity/AccessDecisionManager.java b/core/src/main/java/org/acegisecurity/AccessDecisionManager.java new file mode 100644 index 0000000000..4903181f61 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AccessDecisionManager.java @@ -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 AccessDecisionManager is able to + * process authorization requests presented with the passed + * ConfigAttribute. + * + *

+ * This allows the SecurityInterceptor to check every + * configuration attribute can be consumed by the configured + * AccessDecisionManager and/or RunAsManager. + *

+ * + * @param attribute a configuration attribute that has been configured + * against the SecurityInterceptor + * + * @return true if this AccessDecisionManager can support the + * passed configuration attribute + */ + public boolean supports(ConfigAttribute attribute); +} diff --git a/core/src/main/java/org/acegisecurity/AccessDeniedException.java b/core/src/main/java/org/acegisecurity/AccessDeniedException.java new file mode 100644 index 0000000000..55e44c9638 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AccessDeniedException.java @@ -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 AccessDeniedException with the specified + * message. + * + * @param msg the detail message + */ + public AccessDeniedException(String msg) { + super(msg); + } + + /** + * Constructs an AccessDeniedException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/AcegiSecurityException.java b/core/src/main/java/org/acegisecurity/AcegiSecurityException.java new file mode 100644 index 0000000000..e12c43a5e0 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AcegiSecurityException.java @@ -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. + * + *

+ * Note that this is a runtime (unchecked) exception. Security exceptions are + * usually fatal; there is no reason for them to be checked. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public abstract class AcegiSecurityException extends NestedRuntimeException { + //~ Constructors =========================================================== + + /** + * Constructs an AcegiSecurityException 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 AcegiSecurityException with the specified + * message and no root cause. + * + * @param msg the detail message + */ + public AcegiSecurityException(String msg) { + super(msg); + } +} diff --git a/core/src/main/java/org/acegisecurity/Authentication.java b/core/src/main/java/org/acegisecurity/Authentication.java new file mode 100644 index 0000000000..a6cde31ee3 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/Authentication.java @@ -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. + * + *

+ * An Authentication object is not considered authenticated until + * it is processed by an {@link AuthenticationManager}. + *

+ * + *

+ * Stored in a request {@link net.sf.acegisecurity.context.SecureContext}. + *

+ * + * @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 SecurityInterceptor. + * + * @return true if authenticated by the SecurityInterceptor + */ + public boolean isAuthenticated(); + + /** + * Set by an AuthenticationManager 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 + * AuthenticationManager. + * + * @return the authorities granted to the principal, or null + * 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 + * AuthenticationManager. Callers are expected to populate + * the credentials. + * + * @return the credentials that prove the identity of the + * Principal + */ + public Object getCredentials(); + + /** + * The identity of the principal being authenticated. This is usually a + * username. Callers are expected to populate the principal. + * + * @return the Principal being authenticated + */ + public Object getPrincipal(); +} diff --git a/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java b/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java new file mode 100644 index 0000000000..46e44344d6 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java @@ -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 AuthenticationCredentialsNotFoundException + * with the specified message. + * + * @param msg the detail message + */ + public AuthenticationCredentialsNotFoundException(String msg) { + super(msg); + } + + /** + * Constructs an AuthenticationCredentialsNotFoundException + * 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/AuthenticationException.java b/core/src/main/java/org/acegisecurity/AuthenticationException.java new file mode 100644 index 0000000000..a03b83930b --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AuthenticationException.java @@ -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 AuthenticationException 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 AuthenticationException with the specified + * message and no root cause. + * + * @param msg the detail message + */ + public AuthenticationException(String msg) { + super(msg); + } +} diff --git a/core/src/main/java/org/acegisecurity/AuthenticationManager.java b/core/src/main/java/org/acegisecurity/AuthenticationManager.java new file mode 100644 index 0000000000..1e8da4c828 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AuthenticationManager.java @@ -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 Authentication object + * (including granted authorities) if successful. + * + *

+ * An AuthenticationManager must honour the following contract + * concerning exceptions: + *

+ * + *

+ * A {@link DisabledException} must be thrown if an account is disabled and + * the AuthenticationManager can test for this state. + *

+ * + *

+ * A {@link LockedException} must be thrown if an account is locked and the + * AuthenticationManager can test for account locking. + *

+ * + *

+ * A {@link BadCredentialsException} must be thrown if incorrect + * credentials are presented. Whilst the above exceptions are optional, an + * AuthenticationManager must always test credentials. + *

+ * + *

+ * 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. + *

+ * + * @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; +} diff --git a/core/src/main/java/org/acegisecurity/AuthenticationServiceException.java b/core/src/main/java/org/acegisecurity/AuthenticationServiceException.java new file mode 100644 index 0000000000..4535e8127f --- /dev/null +++ b/core/src/main/java/org/acegisecurity/AuthenticationServiceException.java @@ -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. + * + *

+ * This might be thrown if a backend authentication repository is unavailable. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class AuthenticationServiceException extends AuthenticationException { + //~ Constructors =========================================================== + + /** + * Constructs an AuthenticationServiceException with the + * specified message. + * + * @param msg the detail message + */ + public AuthenticationServiceException(String msg) { + super(msg); + } + + /** + * Constructs an AuthenticationServiceException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/BadCredentialsException.java b/core/src/main/java/org/acegisecurity/BadCredentialsException.java new file mode 100644 index 0000000000..b5c332f831 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/BadCredentialsException.java @@ -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 BadCredentialsException with the specified + * message. + * + * @param msg the detail message + */ + public BadCredentialsException(String msg) { + super(msg); + } + + /** + * Constructs a BadCredentialsException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/ConfigAttribute.java b/core/src/main/java/org/acegisecurity/ConfigAttribute.java new file mode 100644 index 0000000000..e96d99eb38 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/ConfigAttribute.java @@ -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. + * + *

+ * 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 AccessDecisionManager delegate. + *

+ * + *

+ * Stored at runtime with other ConfigAttributes for the same + * method within a {@link ConfigAttributeDefinition}. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface ConfigAttribute { + //~ Methods ================================================================ + + /** + * If the ConfigAttribute can be represented as a + * String and that String is sufficient in + * precision to be relied upon as a configuration parameter by a {@link + * RunAsManager}, {@link AccessDecisionManager} or + * AccessDecisionManager delegate, this method should return + * such a String. + * + *

+ * If the ConfigAttribute cannot be expressed with sufficient + * precision as a String, null should be + * returned. Returning null will require an relying classes + * to specifically support the ConfigAttribute + * implementation, so returning null should be avoided + * unless actually required. + *

+ * + * @return a representation of the configuration attribute (or + * null if the configuration attribute cannot be + * expressed as a String with sufficient precision). + */ + public String getAttribute(); +} diff --git a/core/src/main/java/org/acegisecurity/ConfigAttributeDefinition.java b/core/src/main/java/org/acegisecurity/ConfigAttributeDefinition.java new file mode 100644 index 0000000000..ad7ee1ff8d --- /dev/null +++ b/core/src/main/java/org/acegisecurity/ConfigAttributeDefinition.java @@ -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. + * + *

+ * All the ConfigAttributeDefinitions associated with a given + * SecurityInterceptor are stored in a {@link + * MethodDefinitionMap}. + *

+ * + * @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 ConfigAttribute 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(); + } +} diff --git a/core/src/main/java/org/acegisecurity/ConfigAttributeEditor.java b/core/src/main/java/org/acegisecurity/ConfigAttributeEditor.java new file mode 100644 index 0000000000..202b30a45e --- /dev/null +++ b/core/src/main/java/org/acegisecurity/ConfigAttributeEditor.java @@ -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); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/DisabledException.java b/core/src/main/java/org/acegisecurity/DisabledException.java new file mode 100644 index 0000000000..0ba20b612f --- /dev/null +++ b/core/src/main/java/org/acegisecurity/DisabledException.java @@ -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 DisabledException with the specified message. + * + * @param msg the detail message + */ + public DisabledException(String msg) { + super(msg); + } + + /** + * Constructs a DisabledException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/GrantedAuthority.java b/core/src/main/java/org/acegisecurity/GrantedAuthority.java new file mode 100644 index 0000000000..8fcfc8da83 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/GrantedAuthority.java @@ -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. + * + *

+ * A GrantedAuthority must either represent itself as a + * String or be specifically supported by an {@link + * AccessDecisionManager}. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface GrantedAuthority { + //~ Methods ================================================================ + + /** + * If the GrantedAuthority can be represented as a + * String and that String 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 + * String. + * + *

+ * If the GrantedAuthority cannot be expressed with sufficient + * precision as a String, null should be + * returned. Returning null will require an + * AccessDecisionManager (or delegate) to specifically + * support the GrantedAuthority implementation, so returning + * null should be avoided unless actually required. + *

+ * + * @return a representation of the granted authority (or null + * if the granted authority cannot be expressed as a + * String with sufficient precision). + */ + public String getAuthority(); +} diff --git a/core/src/main/java/org/acegisecurity/GrantedAuthorityImpl.java b/core/src/main/java/org/acegisecurity/GrantedAuthorityImpl.java new file mode 100644 index 0000000000..bbc3c85f14 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/GrantedAuthorityImpl.java @@ -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}. + * + *

+ * Stores a String representation of an authority granted to the + * {@link Authentication} object. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/LockedException.java b/core/src/main/java/org/acegisecurity/LockedException.java new file mode 100644 index 0000000000..868c3a0ce3 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/LockedException.java @@ -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 LockedException with the specified message. + * + * @param msg the detail message. + */ + public LockedException(String msg) { + super(msg); + } + + /** + * Constructs a LockedException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/MethodDefinitionAttributes.java b/core/src/main/java/org/acegisecurity/MethodDefinitionAttributes.java new file mode 100644 index 0000000000..e5f52333b2 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/MethodDefinitionAttributes.java @@ -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); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/MethodDefinitionMap.java b/core/src/main/java/org/acegisecurity/MethodDefinitionMap.java new file mode 100644 index 0000000000..8471b907bf --- /dev/null +++ b/core/src/main/java/org/acegisecurity/MethodDefinitionMap.java @@ -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()))); + } +} diff --git a/core/src/main/java/org/acegisecurity/MethodDefinitionSource.java b/core/src/main/java/org/acegisecurity/MethodDefinitionSource.java new file mode 100644 index 0000000000..1cd6a8d180 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/MethodDefinitionSource.java @@ -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 ConfigAttributeDefinition 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 ConfigAttributeDefinition that applies to the + * passed method call + */ + public ConfigAttributeDefinition getAttributes(MethodInvocation invocation); + + /** + * If available, all of the ConfigAttributeDefinitions defined + * by the implementing class. + * + * @return an iterator over all the ConfigAttributeDefinitions + * or null if unsupported + */ + public Iterator getConfigAttributeDefinitions(); +} diff --git a/core/src/main/java/org/acegisecurity/MethodDefinitionSourceEditor.java b/core/src/main/java/org/acegisecurity/MethodDefinitionSourceEditor.java new file mode 100644 index 0000000000..3fc22251cb --- /dev/null +++ b/core/src/main/java/org/acegisecurity/MethodDefinitionSourceEditor.java @@ -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}. + * + *

+ * The class creates and populates an {@link MethodDefinitionMap}. + *

+ * + * @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); + } +} diff --git a/core/src/main/java/org/acegisecurity/RunAsManager.java b/core/src/main/java/org/acegisecurity/RunAsManager.java new file mode 100644 index 0000000000..5d9201d639 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/RunAsManager.java @@ -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. + * + *

+ * This interface permits implementations to replace the + * Authentication object that applies to the current method + * invocation only. The {@link SecurityInterceptor} will replace the + * Authentication object held in the {@link + * net.sf.acegisecurity.context.SecureContext} for the duration of the method + * invocation only, returning it to the original Authentication + * object when the method invocation completes. + *

+ * + *

+ * 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 + * RunAsManager interface provides a mechanism to elevate + * security in this manner. + *

+ * + *

+ * It is expected implementations will provide a corresponding concrete + * Authentication and AuthenticationProvider so that + * the replacement Authentication object can be authenticated. + * Some form of security will need to be implemented to prevent to ensure the + * AuthenticationProvider only accepts + * Authentication objects created by an authorized concrete + * implementation of RunAsManager. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface RunAsManager { + //~ Methods ================================================================ + + /** + * Returns a replacement Authentication object for the current + * method invocation, or null 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 RunAsManager is able to process the + * passed ConfigAttribute. + * + *

+ * This allows the SecurityInterceptor to check every + * configuration attribute can be consumed by the configured + * AccessDecisionManager and/or RunAsManager. + *

+ * + * @param attribute a configuration attribute that has been configured + * against the SecurityInterceptor + * + * @return true if this RunAsManager can support the passed + * configuration attribute + */ + public boolean supports(ConfigAttribute attribute); +} diff --git a/core/src/main/java/org/acegisecurity/SecurityConfig.java b/core/src/main/java/org/acegisecurity/SecurityConfig.java new file mode 100644 index 0000000000..a499b22d63 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/SecurityConfig.java @@ -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 String. + * + * @author Ben Alex + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/SecurityInterceptor.java b/core/src/main/java/org/acegisecurity/SecurityInterceptor.java new file mode 100644 index 0000000000..4afd500ea2 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/SecurityInterceptor.java @@ -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. + * + *

+ * 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 Authentication object exists, its + * {@link Authentication#isAuthenticated()} method will return + * false once the SecurityInterceptor has + * intercepted the public method). + *

+ * + *

+ * 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. + *

+ * + *

+ * 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 Authentication object. The + * AccessDecisionManager which will then make the authorization + * decision. + *

+ * + *

+ * There shouldn't be any requirement to customise the behaviour of the + * SecurityInterceptor, as all security decisions are made by the + * AuthenticationProvider and AccessDecisionManager + * interfaces, which can of course be replaced with different concrete + * implementations. + *

+ * + * @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 + * ContextHolder does not contain a valid + * SecureContext which in turn contains an + * Authentication 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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/AbstractAdapterAuthenticationToken.java b/core/src/main/java/org/acegisecurity/adapters/AbstractAdapterAuthenticationToken.java new file mode 100644 index 0000000000..a7350997cc --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/AbstractAdapterAuthenticationToken.java @@ -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 AbstractAdapterAuthentication 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 true. + * + * @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. + * + *

+ * Comparison is based on the String returned by {@link + * GrantedAuthority#getAuthority}. + *

+ * + * @param role the role being searched for in this object's granted + * authorities list + * + * @return true if the granted authority is held, or + * false 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; + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/AbstractIntegrationFilter.java b/core/src/main/java/org/acegisecurity/adapters/AbstractIntegrationFilter.java new file mode 100644 index 0000000000..03fd56f753 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/AbstractIntegrationFilter.java @@ -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. + * + *

+ * The container is expected to expose an {@link Authentication} object in a + * well-known location. The Authentication object will have been + * created by the container-specific Acegi Security System for Spring adapter. + *

+ * + *

+ * Once the Authentication 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. + *

+ * + *

+ * This interceptor will not operate if the container does not provide an + * Authentication object from its well-known location. + *

+ * + * @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 Object + * that contains the Authentication interface. + * + *

+ * For convenience we have allowed any Object to be returned + * by subclasses, as the abstract class will ensure class casting safety + * and ignore objects that do not implement Authentication. + *

+ * + *

+ * If no authentication object is available, subclasses should return + * null. + *

+ * + *

+ * 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 Authentication). + *

+ * + * @param request the request, which may be of use in extracting the + * authentication object + * + * @return null or an object that implements + * Authentication + */ + public abstract Object extractFromContainer(ServletRequest request); + + public void init(FilterConfig filterConfig) throws ServletException {} +} diff --git a/core/src/main/java/org/acegisecurity/adapters/AuthByAdapter.java b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapter.java new file mode 100644 index 0000000000..c8b9f53d86 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapter.java @@ -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. + * + *

+ * Automatically considered valid by the {@link AuthByAdapterProvider}, + * provided the hash code presented by the implementation objects matches that + * expected by the AuthByAdapterProvider. + *

+ * + * @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(); +} diff --git a/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java new file mode 100644 index 0000000000..5cc1fa2d69 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java @@ -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}. + * + *

+ * Configured in the bean context with a key that should match the key used by + * adapters to generate AuthByAdapter instances. It treats as + * valid any such instance presenting a hash code that matches the + * AuthByAdapterProvider-configured key. + *

+ * + *

+ * If the key does not match, a BadCredentialsException is + * thrown. + *

+ * + * @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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/AutoIntegrationFilter.java b/core/src/main/java/org/acegisecurity/adapters/AutoIntegrationFilter.java new file mode 100644 index 0000000000..b91fc4bbe0 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/AutoIntegrationFilter.java @@ -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}. + * + *

+ * This eases the creation of portable secured Spring applications, as the + * web.xml will not need to refer to a specific container + * integration filter. + *

+ * + *

+ * See {@link AbstractIntegrationFilter} for further information. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java b/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java new file mode 100644 index 0000000000..7e5bcef832 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java @@ -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 HttpServletRequest.getUserPrincipal(). + * + *

+ * See {@link AbstractIntegrationFilter} for further information. + *

+ * + * @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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/PrincipalAcegiUserToken.java b/core/src/main/java/org/acegisecurity/adapters/PrincipalAcegiUserToken.java new file mode 100644 index 0000000000..290470344d --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/PrincipalAcegiUserToken.java @@ -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; + } +} diff --git a/core/src/main/java/org/acegisecurity/adapters/package.html b/core/src/main/java/org/acegisecurity/adapters/package.html new file mode 100644 index 0000000000..cd2ca6424b --- /dev/null +++ b/core/src/main/java/org/acegisecurity/adapters/package.html @@ -0,0 +1,8 @@ + + +Provides "adapters" so that containers can authenticate with the +Acegi Security System for Spring. +

+ + + diff --git a/core/src/main/java/org/acegisecurity/context/Context.java b/core/src/main/java/org/acegisecurity/context/Context.java new file mode 100644 index 0000000000..4c07a97f23 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/Context.java @@ -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. + * + *

+ * A Context will be sent between application tiers via a {@link + * ContextHolder}. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface Context extends Serializable { + //~ Methods ================================================================ + + /** + * Check the Context is properly configured. + * + *

+ * This allows implementations to confirm they are valid, as this method + * is automatically called by the {@link ContextInterceptor}. + *

+ * + * @throws ContextInvalidException if the Context is invalid. + */ + public void validate() throws ContextInvalidException; +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextException.java b/core/src/main/java/org/acegisecurity/context/ContextException.java new file mode 100644 index 0000000000..3930208b1b --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextException.java @@ -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. + * + *

+ * Note that this is a runtime (unchecked) exception. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public abstract class ContextException extends NestedRuntimeException { + //~ Constructors =========================================================== + + /** + * Constructs a ContextException 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 ContextException with the specified message + * and no root cause. + * + * @param msg the detail message + */ + public ContextException(String msg) { + super(msg); + } +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextHolder.java b/core/src/main/java/org/acegisecurity/context/ContextHolder.java new file mode 100644 index 0000000000..bafa29db49 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextHolder.java @@ -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(); + } +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextHolderEmptyException.java b/core/src/main/java/org/acegisecurity/context/ContextHolderEmptyException.java new file mode 100644 index 0000000000..84c4fee9b2 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextHolderEmptyException.java @@ -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 ContextHolderEmptyException with the specified + * message. + * + * @param msg the detail message + */ + public ContextHolderEmptyException(String msg) { + super(msg); + } + + /** + * Constructs a ContextHolderEmptyException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextImpl.java b/core/src/main/java/org/acegisecurity/context/ContextImpl.java new file mode 100644 index 0000000000..f950c8df60 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextImpl.java @@ -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. + } +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextInterceptor.java b/core/src/main/java/org/acegisecurity/context/ContextInterceptor.java new file mode 100644 index 0000000000..f357bc7996 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextInterceptor.java @@ -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}. + * + *

+ * This interceptor works by calling {@link Context#validate()} before + * proceeding with method invocations. It is configured in the bean context + * with a ProxyFactoryBean. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/context/ContextInvalidException.java b/core/src/main/java/org/acegisecurity/context/ContextInvalidException.java new file mode 100644 index 0000000000..119ea69c8a --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/ContextInvalidException.java @@ -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 ContextInvalidException with the specified + * message. + * + * @param msg the detail message. + */ + public ContextInvalidException(String msg) { + super(msg); + } + + /** + * Constructs a ContextInvalidException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/context/SecureContext.java b/core/src/main/java/org/acegisecurity/context/SecureContext.java new file mode 100644 index 0000000000..376f4d4772 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/SecureContext.java @@ -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. + * + *

+ * 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}. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface SecureContext { + //~ Methods ================================================================ + + public void setAuthentication(Authentication newAuthentication); + + public Authentication getAuthentication(); +} diff --git a/core/src/main/java/org/acegisecurity/context/SecureContextImpl.java b/core/src/main/java/org/acegisecurity/context/SecureContextImpl.java new file mode 100644 index 0000000000..274e258963 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/SecureContextImpl.java @@ -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"); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/context/package.html b/core/src/main/java/org/acegisecurity/context/package.html new file mode 100644 index 0000000000..bbf26cca8c --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/package.html @@ -0,0 +1,10 @@ + + +Provides a "request context". +

+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. + + + diff --git a/core/src/main/java/org/acegisecurity/package.html b/core/src/main/java/org/acegisecurity/package.html new file mode 100644 index 0000000000..7f31f9fd64 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/package.html @@ -0,0 +1,21 @@ + + +Provides core security classes of the Acegi Security System for Spring. +

+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. +

+When configuring SecurityInterceptor 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 +AccessDecisionManagers. +

+Read the JavaDocs of the key classes listed above to learn more about how +the security classes operate. + + + diff --git a/core/src/main/java/org/acegisecurity/providers/AbstractAuthenticationToken.java b/core/src/main/java/org/acegisecurity/providers/AbstractAuthenticationToken.java new file mode 100644 index 0000000000..0bab47daf7 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/AbstractAuthenticationToken.java @@ -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 String 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(); + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/AuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/AuthenticationProvider.java new file mode 100644 index 0000000000..b5b1012caa --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/AuthenticationProvider.java @@ -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 AuthenticationProvider supports the + * indicated Authentication object. + * + *

+ * Selection of an AuthenticationProvider capable of + * performing authentication is conducted at runtime the + * ProviderManager. + *

+ * + * @return DOCUMENT ME! + */ + public boolean supports(Class authentication); +} diff --git a/core/src/main/java/org/acegisecurity/providers/ProviderManager.java b/core/src/main/java/org/acegisecurity/providers/ProviderManager.java new file mode 100644 index 0000000000..eaa7e2c232 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/ProviderManager.java @@ -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. + * + *

+ * The list of {@link AuthenticationProvider}s will be successively tried + * until an AuthenticationProvider indicates it is capable + * of authenticating the type of Authentication object + * passed. Authentication will then be attempted with that + * AuthenticationProvider. + *

+ * + *

+ * If more than one AuthenticationProvider supports the passed + * Authentication object, only the first + * AuthenticationProvider tried will determine the result. No + * subsequent AuthenticationProviders will be tried. + *

+ * + * @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"); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/ProviderNotFoundException.java b/core/src/main/java/org/acegisecurity/providers/ProviderNotFoundException.java new file mode 100644 index 0000000000..3688566daa --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/ProviderNotFoundException.java @@ -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 ProviderNotFoundException with the specified + * message. + * + * @param msg the detail message + */ + public ProviderNotFoundException(String msg) { + super(msg); + } + + /** + * Constructs a ProviderNotFoundException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationProvider.java new file mode 100644 index 0000000000..6d766af2ac --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationProvider.java @@ -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}. + * + *

+ * It simply accepts as valid whatever is contained within the + * TestingAuthenticationToken. + *

+ * + *

+ * The purpose of this implementation is to facilitate unit testing. This + * provider should never be enabled on a production system. + *

+ * + * @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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationToken.java b/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationToken.java new file mode 100644 index 0000000000..c3da60eaef --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/TestingAuthenticationToken.java @@ -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. + * + *

+ * The corresponding authentication provider is {@link + * TestingAuthenticationProvider}. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/UsernamePasswordAuthenticationToken.java b/core/src/main/java/org/acegisecurity/providers/UsernamePasswordAuthenticationToken.java new file mode 100644 index 0000000000..4632a1b3df --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/UsernamePasswordAuthenticationToken.java @@ -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. + * + *

+ * The principal and credentials should be set with + * an Object that provides the respective property via its + * Object.toString() method. The simplest such + * Object to use is String. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java new file mode 100644 index 0000000000..eb14fc3065 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java @@ -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}. + * + *

+ * This AuthenticationProvider is capable of validating {@link + * UsernamePasswordAuthenticationToken} requests contain the correct username, + * password and the user is not disabled. + *

+ * + * @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 + * false, meaning an exact case match is required. + * + * @param ignorePasswordCase set to true 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 + * true, meaning an exact case match is not required. + * + * @param ignoreUsernameCase set to false 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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/dao/UsernameNotFoundException.java b/core/src/main/java/org/acegisecurity/providers/dao/UsernameNotFoundException.java new file mode 100644 index 0000000000..9cb841f5d8 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/UsernameNotFoundException.java @@ -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 UsernameNotFoundException with the specified + * message. + * + * @param msg the detail message. + */ + public UsernameNotFoundException(String msg) { + super(msg); + } + + /** + * Constructs a UsernameNotFoundException 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); + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/dao/package.html b/core/src/main/java/org/acegisecurity/providers/dao/package.html new file mode 100644 index 0000000000..f6caf3b566 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/package.html @@ -0,0 +1,5 @@ + + +An authentication provider that relies upon a data access object. + + diff --git a/core/src/main/java/org/acegisecurity/providers/package.html b/core/src/main/java/org/acegisecurity/providers/package.html new file mode 100644 index 0000000000..ab98f28b3f --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/package.html @@ -0,0 +1,7 @@ + + +Implements a provider-based approach to authorization decisions. +

+ + + diff --git a/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java new file mode 100644 index 0000000000..0faf832b2c --- /dev/null +++ b/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java @@ -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}. + * + *

+ * Configured in the bean context with a key that should match the key used by + * adapters to generate the RunAsUserToken. It treats as valid + * any RunAsUserToken instance presenting a hash code that + * matches the RunAsImplAuthenticationProvider-configured key. + *

+ * + *

+ * If the key does not match, a BadCredentialsException is + * thrown. + *

+ * + * @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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/runas/RunAsManagerImpl.java b/core/src/main/java/org/acegisecurity/runas/RunAsManagerImpl.java new file mode 100644 index 0000000000..5d7fffb2b5 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/runas/RunAsManagerImpl.java @@ -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}. + * + *

+ * Is activated if any {@link ConfigAttribute#getAttribute()} is prefixed with + * RUN_AS_. 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 RUN_AS_ indicated. The created + * GrantedAuthorityImpls will be prefixed with ROLE_ + * and then the remainder of the RUN_AS_ keyword. For example, + * RUN_AS_FOO will result in the creation of a granted authority + * of ROLE_RUN_AS_FOO. + *

+ * + * @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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/runas/RunAsUserToken.java b/core/src/main/java/org/acegisecurity/runas/RunAsUserToken.java new file mode 100644 index 0000000000..fd447ffda9 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/runas/RunAsUserToken.java @@ -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 true. + * + * @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(); + } +} diff --git a/core/src/main/java/org/acegisecurity/runas/package.html b/core/src/main/java/org/acegisecurity/runas/package.html new file mode 100644 index 0000000000..c0ca485b74 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/runas/package.html @@ -0,0 +1,5 @@ + + +Allows intercepted methods to be run under a different authentication identity. + + diff --git a/core/src/main/java/org/acegisecurity/userdetails/User.java b/core/src/main/java/org/acegisecurity/userdetails/User.java new file mode 100644 index 0000000000..ad9b1b8e32 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/User.java @@ -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 User with the details required by {@link + * DaoAuthenticationProvider}. + * + * @param username the username presented to the + * DaoAuthenticationProvider + * @param password the password that should be presented to the + * DaoAuthenticationProvider + * @param enabled set to true 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; + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/UserDetailsService.java b/core/src/main/java/org/acegisecurity/userdetails/UserDetailsService.java new file mode 100644 index 0000000000..eef5694c42 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/UserDetailsService.java @@ -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}. + * + *

+ * The interface requires only one read-only method, which simplifies support + * of new data access strategies. + *

+ * + * @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; +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java b/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java new file mode 100644 index 0000000000..b3d2a28b7c --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java @@ -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; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/jdbc/package.html b/core/src/main/java/org/acegisecurity/userdetails/jdbc/package.html new file mode 100644 index 0000000000..695b3d5c9f --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/jdbc/package.html @@ -0,0 +1,5 @@ + + +Exposes a JDBC-based authentication repository. + + diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/InMemoryDaoImpl.java b/core/src/main/java/org/acegisecurity/userdetails/memory/InMemoryDaoImpl.java new file mode 100644 index 0000000000..da44f26337 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/InMemoryDaoImpl.java @@ -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; + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeDefinition.java b/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeDefinition.java new file mode 100644 index 0000000000..a3da5b1a2c --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeDefinition.java @@ -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); + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeEditor.java b/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeEditor.java new file mode 100644 index 0000000000..7e67f9d634 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/UserAttributeEditor.java @@ -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); + } + } + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/UserMap.java b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMap.java new file mode 100644 index 0000000000..ff5765822d --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMap.java @@ -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); + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java new file mode 100644 index 0000000000..4489794db8 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java @@ -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}. + * + *

+ * The format of entries should be: + *

+ * + *

+ * + * username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] + * + *

+ * + *

+ * The password must always be the first entry after the equals. + * The enabled or disabled keyword can appear + * anywhere (apart from the first entry reserved for the password). If neither + * enabled or disabled appear, the default is + * enabled. At least one granted authority must be listed. + *

+ * + *

+ * The username represents the key and duplicates are handled the + * same was as duplicates would be in Java Properties files. + *

+ * + *

+ * If the above requirements are not met, the invalid entry will be silently + * ignored. + *

+ * + * @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); + } +} diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/package.html b/core/src/main/java/org/acegisecurity/userdetails/memory/package.html new file mode 100644 index 0000000000..b8a3b5d88f --- /dev/null +++ b/core/src/main/java/org/acegisecurity/userdetails/memory/package.html @@ -0,0 +1,6 @@ + + +Exposes an in-memory authentication repository. + + + diff --git a/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java b/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java new file mode 100644 index 0000000000..b8e69011ba --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java @@ -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}. + * + *

+ * 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). + *

+ * + * @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"); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/AccessDecisionVoter.java b/core/src/main/java/org/acegisecurity/vote/AccessDecisionVoter.java new file mode 100644 index 0000000000..6292ca0998 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/AccessDecisionVoter.java @@ -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. + * + *

+ * The coordination of voting (ie polling AccessDecisionVoters, + * tallying their responses, and making the final authorization decision) is + * performed by an {@link net.sf.acegisecurity.AccessDecisionManager}. + *

+ * + * @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 AccessDecisionVoter is able to vote + * on the passed ConfigAttribute. + * + *

+ * This allows the SecurityInterceptor to check every + * configuration attribute can be consumed by the configured + * AccessDecisionManager and/or RunAsManager. + *

+ * + * @param attribute a configuration attribute that has been configured + * against the SecurityInterceptor + * + * @return true if this AccessDecisionVoter can support the + * passed configuration attribute + */ + public boolean supports(ConfigAttribute attribute); + + /** + * Indicates whether or not access is granted. + * + *

+ * The decision must be affirmative (ACCESS_GRANTED), + * negative (ACCESS_DENIED) or the + * AccessDecisionVoter can abstain + * (ACCESS_ABSTAIN) 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. + *

+ * + *

+ * Unless an AccessDecisionVoter is specifically intended to + * vote on an access control decision due to a passed method invocation or + * configuration attribute parameter, it must return + * ACCESS_ABSTAIN. This prevents the coordinating + * AccessDecisionManager from counting votes from those + * AccessDecisionVoters without a legitimate interest in the + * access control decision. + *

+ * + *

+ * 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 MethodInvocation.proceed()). + *

+ * + * @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); +} diff --git a/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java b/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java new file mode 100644 index 0000000000..923c232521 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java @@ -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 + * AccessDecisionVoter 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 + * AccessDecisionVoter voted affirmatively. Denies access + * only if there was a deny vote AND no affirmative votes. + * + *

+ * If every AccessDecisionVoter abstained from voting, the + * decision will be based on the {@link #isAllowIfAllAbstainDecisions()} + * property (defaults to false). + *

+ * + * @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."); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java b/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java new file mode 100644 index 0000000000..edcc3fab17 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java @@ -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. + * + *

+ * If there were an equal number of grant and deny votes, the decision will + * be based on the {@link #isAllowIfEqualGrantedDeniedDecisions()} + * property (defaults to true). + *

+ * + *

+ * If every AccessDecisionVoter abstained from voting, the + * decision will be based on the {@link #isAllowIfAllAbstainDecisions()} + * property (defaults to false). + *

+ * + * @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."); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/RoleVoter.java b/core/src/main/java/org/acegisecurity/vote/RoleVoter.java new file mode 100644 index 0000000000..3132bc0988 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/RoleVoter.java @@ -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 + * ROLE_. + * + *

+ * Abstains from voting if no configuration attribute commences with + * ROLE_. Votes to grant access if there is an exact matching + * {@link net.sf.acegisecurity.GrantedAuthority} to a + * ConfigAttribute starting with ROLE_. Votes to + * deny access if there is no exact matching GrantedAuthority to + * a ConfigAttribute starting with ROLE_. + *

+ * + *

+ * All comparisons and prefixes are case sensitive. + *

+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java b/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java new file mode 100644 index 0000000000..6a4e8d97c9 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java @@ -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 only grant votes were received. + * + *

+ * Other voting implementations usually pass the entire list of {@link + * ConfigAttributeDefinition}s to the AccessDecisionVoter. + * This implementation differs in that each + * AccessDecisionVoter knows only about a single + * ConfigAttribute at a time. + *

+ * + *

+ * If every AccessDecisionVoter abstained from voting, the + * decision will be based on the {@link #isAllowIfAllAbstainDecisions()} + * property (defaults to false). + *

+ * + * @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."); + } + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/package.html b/core/src/main/java/org/acegisecurity/vote/package.html new file mode 100644 index 0000000000..f33ca8bd9e --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/package.html @@ -0,0 +1,6 @@ + + +Implements a vote-based approach to authorization decisions. +

+ + diff --git a/core/src/main/resources/org/acegisecurity/adapters/acegisecurity.xml b/core/src/main/resources/org/acegisecurity/adapters/acegisecurity.xml new file mode 100644 index 0000000000..1b9bfa6b2a --- /dev/null +++ b/core/src/main/resources/org/acegisecurity/adapters/acegisecurity.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR + dianne=emu,ROLE_TELLER + scott=wombat,ROLE_TELLER + peter=opal,disabled,ROLE_TELLER + + + + + + + + false + true + + + + + + + + + + + + diff --git a/core/src/main/resources/org/acegisecurity/providers/dao/jdbc/acegisecurity-jdbc.xml b/core/src/main/resources/org/acegisecurity/providers/dao/jdbc/acegisecurity-jdbc.xml new file mode 100644 index 0000000000..378ed2d3d3 --- /dev/null +++ b/core/src/main/resources/org/acegisecurity/providers/dao/jdbc/acegisecurity-jdbc.xml @@ -0,0 +1,41 @@ + + + + + + + + + + org.hsqldb.jdbcDriver + jdbc:hsqldb:hsql://localhost:9001 + sa + + + + + + + + + + + + false + true + + + + + + + + + + + + diff --git a/core/src/test/java/org/acegisecurity/BankSecurityVoter.java b/core/src/test/java/org/acegisecurity/BankSecurityVoter.java new file mode 100644 index 0000000000..5e899e879f --- /dev/null +++ b/core/src/test/java/org/acegisecurity/BankSecurityVoter.java @@ -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. + * + *

+ * If the {@link ConfigAttribute#getAttribute()} has a value of + * BANKSECURITY_CUSTOMER, the account number subject of the + * method call to be compared with any granted authority prefixed with + * ACCOUNT_ 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 ACCOUNT_12. + *

+ * + *

+ * All comparisons are case sensitive. + *

+ * + * @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; + } +} diff --git a/core/src/test/java/org/acegisecurity/ExoticSecureContext.java b/core/src/test/java/org/acegisecurity/ExoticSecureContext.java new file mode 100644 index 0000000000..35676644be --- /dev/null +++ b/core/src/test/java/org/acegisecurity/ExoticSecureContext.java @@ -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"); + } + } +} diff --git a/core/src/test/java/org/acegisecurity/SecurityTests.java b/core/src/test/java/org/acegisecurity/SecurityTests.java new file mode 100644 index 0000000000..b276d55cc7 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/SecurityTests.java @@ -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); + } +} diff --git a/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java b/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java new file mode 100644 index 0000000000..2e86dc7ab9 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java @@ -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); + } + } +} diff --git a/core/src/test/java/org/acegisecurity/adapters/applicationContext.xml b/core/src/test/java/org/acegisecurity/adapters/applicationContext.xml new file mode 100644 index 0000000000..85f550adc2 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/adapters/applicationContext.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + my_password + + + + + + + + + + + + diff --git a/core/src/test/java/org/acegisecurity/applicationContext.xml b/core/src/test/java/org/acegisecurity/applicationContext.xml new file mode 100644 index 0000000000..1351a2079e --- /dev/null +++ b/core/src/test/java/org/acegisecurity/applicationContext.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + net.sf.acegisecurity.context.BankManager + + + bankManagerSecurity + bankManagerTarget + + + + + diff --git a/core/src/test/java/org/acegisecurity/attribute/AttributesTests.java b/core/src/test/java/org/acegisecurity/attribute/AttributesTests.java new file mode 100644 index 0000000000..cefc74ff71 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/AttributesTests.java @@ -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 + * ConfigAttribute(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; + } +} diff --git a/core/src/test/java/org/acegisecurity/attribute/MockAttributes.java b/core/src/test/java/org/acegisecurity/attribute/MockAttributes.java new file mode 100644 index 0000000000..bf4b9576c1 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/MockAttributes.java @@ -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"); + } +} diff --git a/core/src/test/java/org/acegisecurity/attribute/MockMethodInvocation.java b/core/src/test/java/org/acegisecurity/attribute/MockMethodInvocation.java new file mode 100644 index 0000000000..578c9534e3 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/MockMethodInvocation.java @@ -0,0 +1,109 @@ +/* + * The Acegi Security System 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.aopalliance.intercept.AttributeRegistry; +import org.aopalliance.intercept.Invocation; +import org.aopalliance.intercept.MethodInvocation; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; + + +/** + * DOCUMENT ME! + * + * @author CameronBraid + */ +public class MockMethodInvocation implements MethodInvocation { + //~ Methods ================================================================ + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#setArgument(int, java.lang.Object) + */ + public void setArgument(int arg0, Object arg1) { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getArgument(int) + */ + public Object getArgument(int arg0) { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getArgumentCount() + */ + public int getArgumentCount() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getArguments() + */ + public Object[] getArguments() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getAttachment(java.lang.String) + */ + public Object getAttachment(String arg0) { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getAttributeRegistry() + */ + public AttributeRegistry getAttributeRegistry() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInvocation#getMethod() + */ + public Method getMethod() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#getStaticPart() + */ + public AccessibleObject getStaticPart() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#getThis() + */ + public Object getThis() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#addAttachment(java.lang.String, java.lang.Object) + */ + public Object addAttachment(String arg0, Object arg1) { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#cloneInstance() + */ + public Invocation cloneInstance() { + throw new UnsupportedOperationException("mock method not implemented"); + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#proceed() + */ + public Object proceed() throws Throwable { + throw new UnsupportedOperationException("mock method not implemented"); + } +} diff --git a/core/src/test/java/org/acegisecurity/attribute/TestAttributes.java b/core/src/test/java/org/acegisecurity/attribute/TestAttributes.java new file mode 100644 index 0000000000..e4326ec03b --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/TestAttributes.java @@ -0,0 +1,65 @@ +/* + * The Acegi Security System 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 net.sf.acegisecurity.SecurityConfig; + +import java.lang.reflect.Method; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + + +/** + * DOCUMENT ME! + * + * @author CameronBraid + */ +public class TestAttributes extends MockAttributes { + //~ Instance fields ======================================================== + + List classAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig( + "ROLE_CLASS")}); + List classMethodAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig( + "ROLE_CLASS_METHOD")}); + List intrefaceAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig( + "ROLE_INTERFACE")}); + List intrefaceMethodAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig( + "ROLE_INTERFACE_METHOD")}); + + //~ Methods ================================================================ + + public Collection getAttributes(Class clazz) { + // interface + if (clazz.equals(TestServiceImpl.class)) { + return classAttributes; + } + + // class + if (clazz.equals(TestService.class)) { + return intrefaceAttributes; + } + + return null; + } + + public Collection getAttributes(Method method) { + // interface + if (method.getDeclaringClass().equals(TestService.class)) { + return intrefaceMethodAttributes; + } + + // class + if (method.getDeclaringClass().equals(TestServiceImpl.class)) { + return classMethodAttributes; + } + + return null; + } +} diff --git a/core/src/test/java/org/acegisecurity/attribute/TestService.java b/core/src/test/java/org/acegisecurity/attribute/TestService.java new file mode 100644 index 0000000000..b9558b3305 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/TestService.java @@ -0,0 +1,19 @@ +/* + * The Acegi Security System 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; + +/** + * DOCUMENT ME! + * + * @author CameronBraid + */ +public interface TestService { + //~ Methods ================================================================ + + public abstract void myMethod(); +} diff --git a/core/src/test/java/org/acegisecurity/attribute/TestServiceImpl.java b/core/src/test/java/org/acegisecurity/attribute/TestServiceImpl.java new file mode 100644 index 0000000000..eafcd50282 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/TestServiceImpl.java @@ -0,0 +1,19 @@ +/* + * The Acegi Security System 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; + +/** + * DOCUMENT ME! + * + * @author CameronBraid + */ +public class TestServiceImpl implements TestService { + //~ Methods ================================================================ + + public void myMethod() {} +} diff --git a/core/src/test/java/org/acegisecurity/attribute/applicationContext.xml b/core/src/test/java/org/acegisecurity/attribute/applicationContext.xml new file mode 100644 index 0000000000..74abff07f5 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/attribute/applicationContext.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + securityInterceptor + + + + + + + testService + + + + + + diff --git a/core/src/test/java/org/acegisecurity/badContext.xml b/core/src/test/java/org/acegisecurity/badContext.xml new file mode 100644 index 0000000000..db3dbc5001 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/badContext.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR + net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,INVALID_ATTRIBUTE,BANKSECURITY_CUSTOMER + + + + + diff --git a/core/src/test/java/org/acegisecurity/context/Account.java b/core/src/test/java/org/acegisecurity/context/Account.java new file mode 100644 index 0000000000..d397fb0412 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/Account.java @@ -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.context; + +/** + * Models a bank account. + */ +public class Account { + //~ Instance fields ======================================================== + + private Integer id; + private String owningUserName; + private float balance; + + //~ Constructors =========================================================== + + public Account(Integer id, String owningUserName) { + this.id = id; + this.owningUserName = owningUserName; + } + + public Account(int id, String owningUserName) { + this.id = new Integer(id); + this.owningUserName = owningUserName; + } + + private Account() { + super(); + } + + //~ Methods ================================================================ + + public float getBalance() { + return this.balance; + } + + public Integer getId() { + return this.id; + } + + public String getOwningUserName() { + return this.owningUserName; + } + + public void deposit(float amount) { + this.balance = this.balance + amount; + } + + public void withdraw(float amount) { + this.balance = this.balance - amount; + } +} diff --git a/core/src/test/java/org/acegisecurity/context/BankManager.java b/core/src/test/java/org/acegisecurity/context/BankManager.java new file mode 100644 index 0000000000..5fbfa37297 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/BankManager.java @@ -0,0 +1,36 @@ +/* + * The Acegi Security System 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; + +/** + * Simple business object of an in-memory banking system. + * + *

+ * We'll spare you from InsufficientFundsExceptions etc. After + * all, this is intended to test security features rather than OO design! + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public interface BankManager { + //~ Methods ================================================================ + + public float getBalance(Integer accountNumber); + + public float getBankFundsUnderControl(); + + public void deleteAccount(Integer accountNumber); + + public Account loadAccount(Integer accountNumber); + + public void saveAccount(Account account); + + public void transferFunds(Integer fromAccountNumber, + Integer toAccountNumber, float amount); +} diff --git a/core/src/test/java/org/acegisecurity/context/BankManagerImpl.java b/core/src/test/java/org/acegisecurity/context/BankManagerImpl.java new file mode 100644 index 0000000000..38c8576fcd --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/BankManagerImpl.java @@ -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.context; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + + +/** + * Implementation of {@link BankManager}. + * + * @author Ben Alex + * @version $Id$ + */ +public class BankManagerImpl implements BankManager { + //~ Instance fields ======================================================== + + private Map accounts = new HashMap(); + + //~ Methods ================================================================ + + public float getBalance(Integer accountNumber) { + Account account = this.loadAccount(accountNumber); + + return account.getBalance(); + } + + public float getBankFundsUnderControl() { + float total = 0; + Iterator iter = this.accounts.keySet().iterator(); + + while (iter.hasNext()) { + Integer account = (Integer) iter.next(); + total = total + this.getBalance(account); + } + + return total; + } + + public void deleteAccount(Integer accountNumber) { + this.accounts.remove(accountNumber); + } + + public Account loadAccount(Integer accountNumber) { + return (Account) accounts.get(accountNumber); + } + + public void saveAccount(Account account) { + this.accounts.put(account.getId(), account); + } + + public void transferFunds(Integer fromAccountNumber, + Integer toAccountNumber, float amount) { + Account from = this.loadAccount(fromAccountNumber); + Account to = this.loadAccount(toAccountNumber); + from.withdraw(amount); + to.deposit(amount); + this.saveAccount(from); + this.saveAccount(to); + } +} diff --git a/core/src/test/java/org/acegisecurity/context/ContextTests.java b/core/src/test/java/org/acegisecurity/context/ContextTests.java new file mode 100644 index 0000000000..6dac6e12c7 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/ContextTests.java @@ -0,0 +1,120 @@ +/* + * The Acegi Security System 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 junit.framework.TestCase; + +import net.sf.acegisecurity.providers.TestingAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests context objects. + * + * @author Ben Alex + * @version $Id$ + */ +public class ContextTests extends TestCase { + //~ Instance fields ======================================================== + + private ClassPathXmlApplicationContext ctx; + + //~ Constructors =========================================================== + + public ContextTests() { + super(); + } + + public ContextTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + ctx = new ClassPathXmlApplicationContext( + "/net/sf/acegisecurity/context/applicationContext.xml"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ContextTests.class); + } + + public void testContextInterceptorDetectsEmptyContexts() + throws Exception { + Account ben = new Account(1, "ben"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + try { + bank.saveAccount(ben); + fail("Should have thrown ContextHolderEmptyException"); + } catch (ContextHolderEmptyException expected) { + assertTrue(true); + } + + Context context = new ContextImpl(); + ContextHolder.setContext(context); + + Account marissa = new Account(2, "marissa"); + bank.saveAccount(marissa); + + ContextHolder.setContext(null); + } + + public void testContextInterceptorProcessesValidations() + throws Exception { + ExoticContext context = new ExoticContext(); + ContextHolder.setContext(context); + + Account ben = new Account(1, "ben"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + try { + bank.saveAccount(ben); + fail( + "Should have thrown ContextInvalidException (magic number is incorrect)"); + } catch (ContextInvalidException expected) { + assertTrue(true); + } + + context.setMagicNumber(7); + ContextHolder.setContext(context); + + Account marissa = new Account(2, "marissa"); + bank.saveAccount(marissa); + + ContextHolder.setContext(null); + } + + public void testContextInterceptorValidatesASecureContext() + throws Exception { + SecureContext context = new SecureContextImpl(); + ContextHolder.setContext((Context) context); + + Account ben = new Account(1, "ben"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + try { + bank.saveAccount(ben); + fail( + "Should have thrown ContextInvalidException (no authentication object)"); + } catch (ContextInvalidException expected) { + assertTrue(true); + } + + context.setAuthentication(new TestingAuthenticationToken("a", "b", null)); + ContextHolder.setContext((Context) context); + + Account marissa = new Account(2, "marissa"); + bank.saveAccount(marissa); + + ContextHolder.setContext(null); + } +} diff --git a/core/src/test/java/org/acegisecurity/context/ExoticContext.java b/core/src/test/java/org/acegisecurity/context/ExoticContext.java new file mode 100644 index 0000000000..cd58e72750 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/ExoticContext.java @@ -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; + +/** + * Exotic implementation of a {@link Context}. + * + *

+ * Requires the context to be set with a magicNumber of 7. Tests + * validation in the unit tests. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class ExoticContext implements Context { + //~ Instance fields ======================================================== + + private int magicNumber; + + //~ Methods ================================================================ + + public void setMagicNumber(int magicNumber) { + this.magicNumber = magicNumber; + } + + public int getMagicNumber() { + return magicNumber; + } + + public void validate() throws ContextInvalidException { + if (magicNumber != 7) { + throw new ContextInvalidException("Magic number is not 7"); + } + } +} diff --git a/core/src/test/java/org/acegisecurity/context/applicationContext.xml b/core/src/test/java/org/acegisecurity/context/applicationContext.xml new file mode 100644 index 0000000000..c36c11e3f9 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/applicationContext.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + net.sf.acegisecurity.context.BankManager + + + contextInterceptor + bankManagerTarget + + + + + diff --git a/core/src/test/java/org/acegisecurity/providers/dao/memory/InMemoryDaoTests.java b/core/src/test/java/org/acegisecurity/providers/dao/memory/InMemoryDaoTests.java new file mode 100644 index 0000000000..ace9ae98f1 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/providers/dao/memory/InMemoryDaoTests.java @@ -0,0 +1,189 @@ +/* + * The Acegi Security System 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 junit.framework.TestCase; + +import net.sf.acegisecurity.AccessDeniedException; +import net.sf.acegisecurity.BadCredentialsException; +import net.sf.acegisecurity.DisabledException; +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.SecureContext; +import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests {@link DaoAuthenticationProvider} with {@link InMemoryDaoImpl}. + * + * @author Ben Alex + * @version $Id$ + */ +public class InMemoryDaoTests extends TestCase { + //~ Instance fields ======================================================== + + private ClassPathXmlApplicationContext ctx; + + //~ Constructors =========================================================== + + public InMemoryDaoTests() { + super(); + } + + public InMemoryDaoTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + ctx = new ClassPathXmlApplicationContext( + "/net/sf/acegisecurity/providers/dao/memory/applicationContext.xml"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(InMemoryDaoTests.class); + } + + public void testAuthentication() throws Exception { + Account account = new Account(1, "someone"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + // Try with an invalid username and password + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("jennifer", + "zebra"); + SecureContext secureContext = new SecureContextImpl(); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a BadCredentialsException"); + } catch (BadCredentialsException expected) { + assertTrue(true); + } + + // Check our token represents itself properly as a String + System.out.println(token.toString()); + assertTrue(token.toString().length() > 10); + + // Now try with a valid username, but invalid password + token = new UsernamePasswordAuthenticationToken("marissa", "zebra"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a BadCredentialsException"); + } catch (BadCredentialsException expected) { + assertTrue(true); + } + + // Now try with a valid username and password, but disabled user + token = new UsernamePasswordAuthenticationToken("dianne", "emu"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a DisabledException"); + } catch (DisabledException expected) { + assertTrue(true); + } + + // Now try as a user who didn't have a password defined, and thus + // would have been considered invalid at time of creation + token = new UsernamePasswordAuthenticationToken("someoneelse", ""); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a BadCredentialsException"); + } catch (BadCredentialsException expected) { + assertTrue(true); + } + + // Now try as a user who had a password, but no granted authorities, + // and thus would have been considered invalid at time of creation + token = new UsernamePasswordAuthenticationToken("someone", "password"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a BadCredentialsException"); + } catch (BadCredentialsException expected) { + assertTrue(true); + } + + // Now try with a valid mixed case username, valid mixed case password, + // (application context requires passwords to be case matched) + token = new UsernamePasswordAuthenticationToken("MaRiSsA", "kOaLa"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown a BadCredentialsException"); + } catch (BadCredentialsException expected) { + assertTrue(true); + } + + // Now try with a valid mixed case username, correct case password, + // (application context does not require usernames to be case matched) + token = new UsernamePasswordAuthenticationToken("MaRiSsA", "koala"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + bank.saveAccount(account); + + ContextHolder.setContext(null); + } + + public void testAuthorization() throws Exception { + Account account = new Account(45, "someone"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + // Try as a user without access to the account + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + SecureContext secureContext = new SecureContextImpl(); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + // NB: account number 45 != granted authority for account 77 + bank.loadAccount(account.getId()); + fail("Should have thrown an AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + // Now try as user with access to account number 45 + token = new UsernamePasswordAuthenticationToken("scott", "wombat"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + bank.loadAccount(account.getId()); + assertTrue(true); + + // Now try as user with ROLE_SUPERVISOR access to the account + token = new UsernamePasswordAuthenticationToken("marissa", "koala"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + bank.loadAccount(account.getId()); + assertTrue(true); + + ContextHolder.setContext(null); + } +} diff --git a/core/src/test/java/org/acegisecurity/providers/dao/memory/applicationContext.xml b/core/src/test/java/org/acegisecurity/providers/dao/memory/applicationContext.xml new file mode 100644 index 0000000000..78230a5149 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/providers/dao/memory/applicationContext.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR + dianne=emu,disabled,ROLE_TELLER + scott=wombat,ACCOUNT_45 + peter=opal,ACCOUNT_77 + someone=password + someoneelse= + + + + + + + + false + true + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + net.sf.acegisecurity.context.BankManager + + + bankManagerSecurity + bankManagerTarget + + + + + diff --git a/core/src/test/java/org/acegisecurity/runas/BankManagerPublicFacade.java b/core/src/test/java/org/acegisecurity/runas/BankManagerPublicFacade.java new file mode 100644 index 0000000000..fc8e7135e9 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/runas/BankManagerPublicFacade.java @@ -0,0 +1,75 @@ +/* + * The Acegi Security System 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.context.Account; +import net.sf.acegisecurity.context.BankManager; + +import org.springframework.beans.factory.InitializingBean; + + +/** + * Acts as the "public facade" to a BankManager. + * + *

+ * The security configuration of this, the public facade, specifies authorities + * that should be held by the end user. The security configuration of the + * "backend", which is not accessible to the general public, specifies certain + * authorities that are granted by the RunAsManagerImpl. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class BankManagerPublicFacade implements BankManager, InitializingBean { + //~ Instance fields ======================================================== + + private BankManager backend; + + //~ Methods ================================================================ + + public void setBackend(BankManager backend) { + this.backend = backend; + } + + public BankManager getBackend() { + return backend; + } + + public float getBalance(Integer accountNumber) { + return backend.getBalance(accountNumber); + } + + public float getBankFundsUnderControl() { + return backend.getBankFundsUnderControl(); + } + + public void afterPropertiesSet() throws Exception { + if (backend == null) { + throw new IllegalArgumentException( + "A backend BankManager implementation is required"); + } + } + + public void deleteAccount(Integer accountNumber) { + backend.deleteAccount(accountNumber); + } + + public Account loadAccount(Integer accountNumber) { + return backend.loadAccount(accountNumber); + } + + public void saveAccount(Account account) { + backend.saveAccount(account); + } + + public void transferFunds(Integer fromAccountNumber, + Integer toAccountNumber, float amount) { + backend.transferFunds(fromAccountNumber, toAccountNumber, amount); + } +} diff --git a/core/src/test/java/org/acegisecurity/runas/RunAsTests.java b/core/src/test/java/org/acegisecurity/runas/RunAsTests.java new file mode 100644 index 0000000000..c1becd7c68 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/runas/RunAsTests.java @@ -0,0 +1,106 @@ +/* + * The Acegi Security System 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 junit.framework.TestCase; + +import net.sf.acegisecurity.AccessDeniedException; +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.SecureContext; +import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests {@link RunAsManagerImpl}. + * + * @author Ben Alex + * @version $Id$ + */ +public class RunAsTests extends TestCase { + //~ Instance fields ======================================================== + + private ClassPathXmlApplicationContext ctx; + + //~ Constructors =========================================================== + + public RunAsTests() { + super(); + } + + public RunAsTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + ctx = new ClassPathXmlApplicationContext( + "/net/sf/acegisecurity/runas/applicationContext.xml"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(RunAsTests.class); + } + + public void testRunAs() throws Exception { + Account account = new Account(45, "someone"); + BankManager bank = (BankManager) ctx.getBean("bankManager"); + + // Try as a user without access to the account + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + SecureContext secureContext = new SecureContextImpl(); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + // NB: account number 45 != granted authority for account 77 + bank.loadAccount(account.getId()); + fail("Should have thrown an AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + // Now try as user with access to account number 45 + // Proves ROLE_RUN_AS_SERVER is being allocated + token = new UsernamePasswordAuthenticationToken("scott", "wombat"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + bank.loadAccount(account.getId()); + assertTrue(true); + + // Now try as user with ROLE_SUPERVISOR access to the account + // Proves ROLE_RUN_AS_SERVER is being allocated + token = new UsernamePasswordAuthenticationToken("marissa", "koala"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + bank.loadAccount(account.getId()); + assertTrue(true); + + // Now try to call a method that ROLE_RUN_AS_BACKEND not granted for + token = new UsernamePasswordAuthenticationToken("marissa", "koala"); + secureContext.setAuthentication(token); + ContextHolder.setContext((Context) secureContext); + + try { + bank.saveAccount(account); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + ContextHolder.setContext(null); + } +} diff --git a/core/src/test/java/org/acegisecurity/runas/applicationContext.xml b/core/src/test/java/org/acegisecurity/runas/applicationContext.xml new file mode 100644 index 0000000000..eefbb9e47a --- /dev/null +++ b/core/src/test/java/org/acegisecurity/runas/applicationContext.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR + dianne=emu,disabled,ROLE_TELLER + scott=wombat,ACCOUNT_45 + peter=opal,ACCOUNT_77 + someone=password + someoneelse= + + + + + + + + false + true + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.loadAccount=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.saveAccount=ROLE_TELLER,ROLE_SUPERVISOR + net.sf.acegisecurity.context.BankManager.transferFunds=ROLE_SUPERVISOR,RUN_AS_SERVER + + + + + + + + + + + + net.sf.acegisecurity.context.BankManager.delete*=ROLE_RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.getBalance=ROLE_RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.loadAccount=ROLE_RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.saveAccount=ROLE_RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.transferFunds=ROLE_RUN_AS_SERVER + + + + + + + + net.sf.acegisecurity.context.BankManager + + + publicBankManagerSecurity + publicBankManagerTarget + + + + + + + + + + net.sf.acegisecurity.context.BankManager + + + backendBankManagerSecurity + backendBankManagerTarget + + + + + + + diff --git a/core/src/test/java/org/acegisecurity/vote/VoterManagerTests.java b/core/src/test/java/org/acegisecurity/vote/VoterManagerTests.java new file mode 100644 index 0000000000..1f774a508d --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/VoterManagerTests.java @@ -0,0 +1,268 @@ +/* + * The Acegi Security System 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 junit.framework.TestCase; + +import net.sf.acegisecurity.AccessDecisionManager; +import net.sf.acegisecurity.AccessDeniedException; +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.SecurityConfig; +import net.sf.acegisecurity.providers.TestingAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests voter decision managers. + * + * @author Ben Alex + * @version $Id$ + */ +public class VoterManagerTests extends TestCase { + //~ Instance fields ======================================================== + + private ClassPathXmlApplicationContext ctx; + + //~ Constructors =========================================================== + + public VoterManagerTests() { + super(); + } + + public VoterManagerTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + ctx = new ClassPathXmlApplicationContext( + "/net/sf/acegisecurity/vote/applicationContext.xml"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(VoterManagerTests.class); + } + + public void testAffirmative() throws Exception { + AccessDecisionManager mgr = (AccessDecisionManager) ctx.getBean( + "affirmativeBased"); + ConfigAttributeDefinition config; + TestingAuthenticationToken auth; + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"), new GrantedAuthorityImpl("ROLE_MAGIC")}); + + // Check if we'd get access if ROLE_2 was all that is acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if YYYY was all that is acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if everything was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + config.addConfigAttribute(new SecurityConfig("XXXX")); // grant + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if ROLE_9 was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_9")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"),}); + + // Check if we'd get access if ROLE_1 and 2 was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get granted access even if one returned deny + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + config.addConfigAttribute(new SecurityConfig("XXXX")); // deny + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if all returned deny + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("YYYY")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + } + + public void testConsensus() throws Exception { + AccessDecisionManager mgr = (AccessDecisionManager) ctx.getBean( + "consensusBased"); + ConfigAttributeDefinition config; + TestingAuthenticationToken auth; + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"), new GrantedAuthorityImpl("ROLE_MAGIC")}); + + // Check if we'd get access if ROLE_2 was all that is acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if YYYY was all that is acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if everything was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + config.addConfigAttribute(new SecurityConfig("XXXX")); // grant + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if ROLE_9 was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_9")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"),}); + + // Check if we'd get access if ROLE_1 and 2 was acceptable + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get granted access even if one returned deny + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant and return + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // not tested + config.addConfigAttribute(new SecurityConfig("XXXX")); // deny + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if all returned deny + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("XXXX")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + } + + public void testUnanimous() throws Exception { + AccessDecisionManager mgr = (AccessDecisionManager) ctx.getBean( + "unanimousBased"); + ConfigAttributeDefinition config; + TestingAuthenticationToken auth; + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"), new GrantedAuthorityImpl("ROLE_MAGIC")}); + + // Check if we'd get access if ROLE_2 was all that is required + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if YYYY was all that is required + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get access if everything was required + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + config.addConfigAttribute(new SecurityConfig("XXXX")); // grant + config.addConfigAttribute(new SecurityConfig("YYYY")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if ROLE_9 was required + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_9")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + auth = new TestingAuthenticationToken("test", "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl( + "ROLE_2"),}); + + // Check if we'd get access if ROLE_1 and 2 was required + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + mgr.decide(auth, null, config); + assertTrue(true); + + // Check if we'd get denied access if all any return deny at all + config = new ConfigAttributeDefinition(); + config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant + config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant + config.addConfigAttribute(new SecurityConfig("XXXX")); // deny + + try { + mgr.decide(auth, null, config); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + } +} diff --git a/core/src/test/java/org/acegisecurity/vote/XVoter.java b/core/src/test/java/org/acegisecurity/vote/XVoter.java new file mode 100644 index 0000000000..00f604f7dd --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/XVoter.java @@ -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.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; + + +/** + * Implementation of an {@link AccessDecisionVoter} for unit testing. + * + *

+ * If the {@link ConfigAttribute#getAttribute()} has a value of + * XXXX, a granted authority that equals ROLE_MAGIC + * will cause a grant vote. The voter will abstain if there is no + * configuration attribute named XXXX. + *

+ * + *

+ * All comparisons are case sensitive. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class XVoter implements AccessDecisionVoter { + //~ Methods ================================================================ + + public boolean supports(ConfigAttribute attribute) { + if ("XXXX".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; + + for (int i = 0; i < authentication.getAuthorities().length; + i++) { + if ("ROLE_MAGIC".equals( + authentication.getAuthorities()[i].getAuthority())) { + return ACCESS_GRANTED; + } + } + } + } + + return result; + } +} diff --git a/core/src/test/java/org/acegisecurity/vote/YVoter.java b/core/src/test/java/org/acegisecurity/vote/YVoter.java new file mode 100644 index 0000000000..c4895515d1 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/YVoter.java @@ -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.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; + + +/** + * Implementation of an {@link AccessDecisionVoter} for unit testing. + * + *

+ * If the {@link ConfigAttribute#getAttribute()} has a value of + * YYYY, a granted authority that equals ROLE_MAGIC + * will cause a grant vote. The voter will abstain if there is no + * configuration attribute named YYYY. + *

+ * + *

+ * All comparisons are case sensitive. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class YVoter implements AccessDecisionVoter { + //~ Methods ================================================================ + + public boolean supports(ConfigAttribute attribute) { + if ("YYYY".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; + + for (int i = 0; i < authentication.getAuthorities().length; + i++) { + if ("ROLE_MAGIC".equals( + authentication.getAuthorities()[i].getAuthority())) { + return ACCESS_GRANTED; + } + } + } + } + + return result; + } +} diff --git a/core/src/test/java/org/acegisecurity/vote/applicationContext.xml b/core/src/test/java/org/acegisecurity/vote/applicationContext.xml new file mode 100644 index 0000000000..fb1fd5a121 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/applicationContext.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + + + + false + true + + + + + + + + + diff --git a/docs/.cvsignore b/docs/.cvsignore new file mode 100644 index 0000000000..a8f46ee569 --- /dev/null +++ b/docs/.cvsignore @@ -0,0 +1,2 @@ +api + diff --git a/docs/reference/.cvsignore b/docs/reference/.cvsignore new file mode 100644 index 0000000000..c8e2b9d580 --- /dev/null +++ b/docs/reference/.cvsignore @@ -0,0 +1,5 @@ +lib +html +html_single +pdf + diff --git a/docs/reference/README b/docs/reference/README new file mode 100644 index 0000000000..b502b2766b --- /dev/null +++ b/docs/reference/README @@ -0,0 +1,25 @@ +We're using the DocBook XSL distribution for HTML and PDF +generation. The best results can be achieved with the +Saxon XSLT processor (don't use Xalan!) and the Apache +FOP library. + +The documentation is generated by the build.xml file of +Spring and Ant. Targets included are: + +- docpdf - generates the PDF documentation +- dochtml - generates the HTML documentation +- dochtmlsingle - generates single page HTML documenation +- docclean - clean any output directories for docs + +To generate documentation, you need to include a lot +of libraries, which haven't been added to CVS because +they're simply too big. The libraries can be found at: +http://www.jteam.nl/spring/reference-libraries.zip. +Download them, create a lib directory in the +docs/reference directory and unzip the zip there. +Then, the targets should work. + +Thanks to Hibernate, for providing the skeleton for +DocBook documentation! + +alef@jteam.nl diff --git a/docs/reference/images/admons/blank.png b/docs/reference/images/admons/blank.png new file mode 100644 index 0000000000..764bf4f0c3 Binary files /dev/null and b/docs/reference/images/admons/blank.png differ diff --git a/docs/reference/images/admons/caution.gif b/docs/reference/images/admons/caution.gif new file mode 100644 index 0000000000..d9f5e5b1bc Binary files /dev/null and b/docs/reference/images/admons/caution.gif differ diff --git a/docs/reference/images/admons/caution.png b/docs/reference/images/admons/caution.png new file mode 100644 index 0000000000..5b7809ca4a Binary files /dev/null and b/docs/reference/images/admons/caution.png differ diff --git a/docs/reference/images/admons/caution.tif b/docs/reference/images/admons/caution.tif new file mode 100644 index 0000000000..4a282948c4 Binary files /dev/null and b/docs/reference/images/admons/caution.tif differ diff --git a/docs/reference/images/admons/draft.png b/docs/reference/images/admons/draft.png new file mode 100644 index 0000000000..0084708c9b Binary files /dev/null and b/docs/reference/images/admons/draft.png differ diff --git a/docs/reference/images/admons/home.gif b/docs/reference/images/admons/home.gif new file mode 100644 index 0000000000..6784f5bb01 Binary files /dev/null and b/docs/reference/images/admons/home.gif differ diff --git a/docs/reference/images/admons/home.png b/docs/reference/images/admons/home.png new file mode 100644 index 0000000000..cbb711de71 Binary files /dev/null and b/docs/reference/images/admons/home.png differ diff --git a/docs/reference/images/admons/important.gif b/docs/reference/images/admons/important.gif new file mode 100644 index 0000000000..6795d9a819 Binary files /dev/null and b/docs/reference/images/admons/important.gif differ diff --git a/docs/reference/images/admons/important.png b/docs/reference/images/admons/important.png new file mode 100644 index 0000000000..12c90f607a Binary files /dev/null and b/docs/reference/images/admons/important.png differ diff --git a/docs/reference/images/admons/important.tif b/docs/reference/images/admons/important.tif new file mode 100644 index 0000000000..184de63711 Binary files /dev/null and b/docs/reference/images/admons/important.tif differ diff --git a/docs/reference/images/admons/next.gif b/docs/reference/images/admons/next.gif new file mode 100644 index 0000000000..aa1516e691 Binary files /dev/null and b/docs/reference/images/admons/next.gif differ diff --git a/docs/reference/images/admons/next.png b/docs/reference/images/admons/next.png new file mode 100644 index 0000000000..45835bf89a Binary files /dev/null and b/docs/reference/images/admons/next.png differ diff --git a/docs/reference/images/admons/note.gif b/docs/reference/images/admons/note.gif new file mode 100644 index 0000000000..f329d359e5 Binary files /dev/null and b/docs/reference/images/admons/note.gif differ diff --git a/docs/reference/images/admons/note.png b/docs/reference/images/admons/note.png new file mode 100644 index 0000000000..d0c3c645ab Binary files /dev/null and b/docs/reference/images/admons/note.png differ diff --git a/docs/reference/images/admons/note.tif b/docs/reference/images/admons/note.tif new file mode 100644 index 0000000000..08644d6b5d Binary files /dev/null and b/docs/reference/images/admons/note.tif differ diff --git a/docs/reference/images/admons/prev.gif b/docs/reference/images/admons/prev.gif new file mode 100644 index 0000000000..64ca8f3c7c Binary files /dev/null and b/docs/reference/images/admons/prev.gif differ diff --git a/docs/reference/images/admons/prev.png b/docs/reference/images/admons/prev.png new file mode 100644 index 0000000000..cf24654f8a Binary files /dev/null and b/docs/reference/images/admons/prev.png differ diff --git a/docs/reference/images/admons/tip.gif b/docs/reference/images/admons/tip.gif new file mode 100644 index 0000000000..823f2b417c Binary files /dev/null and b/docs/reference/images/admons/tip.gif differ diff --git a/docs/reference/images/admons/tip.png b/docs/reference/images/admons/tip.png new file mode 100644 index 0000000000..5c4aab3bb3 Binary files /dev/null and b/docs/reference/images/admons/tip.png differ diff --git a/docs/reference/images/admons/tip.tif b/docs/reference/images/admons/tip.tif new file mode 100644 index 0000000000..4a3d8c75fd Binary files /dev/null and b/docs/reference/images/admons/tip.tif differ diff --git a/docs/reference/images/admons/toc-blank.png b/docs/reference/images/admons/toc-blank.png new file mode 100644 index 0000000000..6ffad17a0c Binary files /dev/null and b/docs/reference/images/admons/toc-blank.png differ diff --git a/docs/reference/images/admons/toc-minus.png b/docs/reference/images/admons/toc-minus.png new file mode 100644 index 0000000000..abbb020c8e Binary files /dev/null and b/docs/reference/images/admons/toc-minus.png differ diff --git a/docs/reference/images/admons/toc-plus.png b/docs/reference/images/admons/toc-plus.png new file mode 100644 index 0000000000..941312ce0d Binary files /dev/null and b/docs/reference/images/admons/toc-plus.png differ diff --git a/docs/reference/images/admons/up.gif b/docs/reference/images/admons/up.gif new file mode 100644 index 0000000000..aabc2d0165 Binary files /dev/null and b/docs/reference/images/admons/up.gif differ diff --git a/docs/reference/images/admons/up.png b/docs/reference/images/admons/up.png new file mode 100644 index 0000000000..07634de26b Binary files /dev/null and b/docs/reference/images/admons/up.png differ diff --git a/docs/reference/images/admons/warning.gif b/docs/reference/images/admons/warning.gif new file mode 100644 index 0000000000..3adf191293 Binary files /dev/null and b/docs/reference/images/admons/warning.gif differ diff --git a/docs/reference/images/admons/warning.png b/docs/reference/images/admons/warning.png new file mode 100644 index 0000000000..1c33db8f34 Binary files /dev/null and b/docs/reference/images/admons/warning.png differ diff --git a/docs/reference/images/admons/warning.tif b/docs/reference/images/admons/warning.tif new file mode 100644 index 0000000000..7b6611ec7a Binary files /dev/null and b/docs/reference/images/admons/warning.tif differ diff --git a/docs/reference/images/callouts/1.gif b/docs/reference/images/callouts/1.gif new file mode 100644 index 0000000000..0d66977193 Binary files /dev/null and b/docs/reference/images/callouts/1.gif differ diff --git a/docs/reference/images/callouts/1.png b/docs/reference/images/callouts/1.png new file mode 100644 index 0000000000..7d473430b7 Binary files /dev/null and b/docs/reference/images/callouts/1.png differ diff --git a/docs/reference/images/callouts/10.gif b/docs/reference/images/callouts/10.gif new file mode 100644 index 0000000000..fb50b06d15 Binary files /dev/null and b/docs/reference/images/callouts/10.gif differ diff --git a/docs/reference/images/callouts/10.png b/docs/reference/images/callouts/10.png new file mode 100644 index 0000000000..997bbc8246 Binary files /dev/null and b/docs/reference/images/callouts/10.png differ diff --git a/docs/reference/images/callouts/11.gif b/docs/reference/images/callouts/11.gif new file mode 100644 index 0000000000..9f5dba4f8d Binary files /dev/null and b/docs/reference/images/callouts/11.gif differ diff --git a/docs/reference/images/callouts/11.png b/docs/reference/images/callouts/11.png new file mode 100644 index 0000000000..ce47dac3f5 Binary files /dev/null and b/docs/reference/images/callouts/11.png differ diff --git a/docs/reference/images/callouts/12.gif b/docs/reference/images/callouts/12.gif new file mode 100644 index 0000000000..a373d0b4f4 Binary files /dev/null and b/docs/reference/images/callouts/12.gif differ diff --git a/docs/reference/images/callouts/12.png b/docs/reference/images/callouts/12.png new file mode 100644 index 0000000000..31daf4e2f2 Binary files /dev/null and b/docs/reference/images/callouts/12.png differ diff --git a/docs/reference/images/callouts/13.gif b/docs/reference/images/callouts/13.gif new file mode 100644 index 0000000000..b00b1637bd Binary files /dev/null and b/docs/reference/images/callouts/13.gif differ diff --git a/docs/reference/images/callouts/13.png b/docs/reference/images/callouts/13.png new file mode 100644 index 0000000000..14021a89c2 Binary files /dev/null and b/docs/reference/images/callouts/13.png differ diff --git a/docs/reference/images/callouts/14.gif b/docs/reference/images/callouts/14.gif new file mode 100644 index 0000000000..6d6642ee96 Binary files /dev/null and b/docs/reference/images/callouts/14.gif differ diff --git a/docs/reference/images/callouts/14.png b/docs/reference/images/callouts/14.png new file mode 100644 index 0000000000..64014b75fe Binary files /dev/null and b/docs/reference/images/callouts/14.png differ diff --git a/docs/reference/images/callouts/15.gif b/docs/reference/images/callouts/15.gif new file mode 100644 index 0000000000..cdd7072d28 Binary files /dev/null and b/docs/reference/images/callouts/15.gif differ diff --git a/docs/reference/images/callouts/15.png b/docs/reference/images/callouts/15.png new file mode 100644 index 0000000000..0d65765fcf Binary files /dev/null and b/docs/reference/images/callouts/15.png differ diff --git a/docs/reference/images/callouts/2.gif b/docs/reference/images/callouts/2.gif new file mode 100644 index 0000000000..100ff79f01 Binary files /dev/null and b/docs/reference/images/callouts/2.gif differ diff --git a/docs/reference/images/callouts/2.png b/docs/reference/images/callouts/2.png new file mode 100644 index 0000000000..5d09341b2f Binary files /dev/null and b/docs/reference/images/callouts/2.png differ diff --git a/docs/reference/images/callouts/3.gif b/docs/reference/images/callouts/3.gif new file mode 100644 index 0000000000..5008ca7dbc Binary files /dev/null and b/docs/reference/images/callouts/3.gif differ diff --git a/docs/reference/images/callouts/3.png b/docs/reference/images/callouts/3.png new file mode 100644 index 0000000000..ef7b700471 Binary files /dev/null and b/docs/reference/images/callouts/3.png differ diff --git a/docs/reference/images/callouts/4.gif b/docs/reference/images/callouts/4.gif new file mode 100644 index 0000000000..0e5617d2f2 Binary files /dev/null and b/docs/reference/images/callouts/4.gif differ diff --git a/docs/reference/images/callouts/4.png b/docs/reference/images/callouts/4.png new file mode 100644 index 0000000000..adb8364eb5 Binary files /dev/null and b/docs/reference/images/callouts/4.png differ diff --git a/docs/reference/images/callouts/5.gif b/docs/reference/images/callouts/5.gif new file mode 100644 index 0000000000..9bc75ada64 Binary files /dev/null and b/docs/reference/images/callouts/5.gif differ diff --git a/docs/reference/images/callouts/5.png b/docs/reference/images/callouts/5.png new file mode 100644 index 0000000000..4d7eb46002 Binary files /dev/null and b/docs/reference/images/callouts/5.png differ diff --git a/docs/reference/images/callouts/6.gif b/docs/reference/images/callouts/6.gif new file mode 100644 index 0000000000..d396407074 Binary files /dev/null and b/docs/reference/images/callouts/6.gif differ diff --git a/docs/reference/images/callouts/6.png b/docs/reference/images/callouts/6.png new file mode 100644 index 0000000000..0ba694af6c Binary files /dev/null and b/docs/reference/images/callouts/6.png differ diff --git a/docs/reference/images/callouts/7.gif b/docs/reference/images/callouts/7.gif new file mode 100644 index 0000000000..c90b2f3df0 Binary files /dev/null and b/docs/reference/images/callouts/7.gif differ diff --git a/docs/reference/images/callouts/7.png b/docs/reference/images/callouts/7.png new file mode 100644 index 0000000000..472e96f8ac Binary files /dev/null and b/docs/reference/images/callouts/7.png differ diff --git a/docs/reference/images/callouts/8.gif b/docs/reference/images/callouts/8.gif new file mode 100644 index 0000000000..6fe3287d25 Binary files /dev/null and b/docs/reference/images/callouts/8.gif differ diff --git a/docs/reference/images/callouts/8.png b/docs/reference/images/callouts/8.png new file mode 100644 index 0000000000..5e60973c21 Binary files /dev/null and b/docs/reference/images/callouts/8.png differ diff --git a/docs/reference/images/callouts/9.gif b/docs/reference/images/callouts/9.gif new file mode 100644 index 0000000000..bc5c8125b0 Binary files /dev/null and b/docs/reference/images/callouts/9.gif differ diff --git a/docs/reference/images/callouts/9.png b/docs/reference/images/callouts/9.png new file mode 100644 index 0000000000..a0676d26cc Binary files /dev/null and b/docs/reference/images/callouts/9.png differ diff --git a/docs/reference/src/images/logo.gif b/docs/reference/src/images/logo.gif new file mode 100644 index 0000000000..38bac7e01a Binary files /dev/null and b/docs/reference/src/images/logo.gif differ diff --git a/docs/reference/src/images/logo.psd b/docs/reference/src/images/logo.psd new file mode 100644 index 0000000000..684ad2e078 Binary files /dev/null and b/docs/reference/src/images/logo.psd differ diff --git a/docs/reference/src/index.xml b/docs/reference/src/index.xml new file mode 100644 index 0000000000..29f304bf81 --- /dev/null +++ b/docs/reference/src/index.xml @@ -0,0 +1,1509 @@ + + + + + Acegi Security System for Spring + + Reference Documentation + + 0.3 + + + + Ben + + Alex + + + + + + + + Preface + + This document provides a reference guide to the Acegi Security + System for Spring, which is a series of classes that deliver + authentication and authorization services within the Spring Framework. + Whilst the Acegi Security System for Spring is not officially part of + Spring, it is hoped this implementation will further discussion concerning + the implementation of security capabilities within Spring itself. + + I would like to acknowledge this reference was prepared using the + DocBook configuration included with the Spring Framework. The Spring team + in turn acknowledge Chris Bauer (Hibernate) for his assistance with their + DocBook. + + + + Security + + + Introduction + + The Acegi Security System for Spring provides authentication and + authorization capabilities for Spring-powered projects, with full + integration with popular web containers. The security architecture was + designed from the ground up using "The Spring Way" of development, which + includes using bean contexts, interceptors and interface-driven + programming. As a consequence, the Acegi Security System for Spring is + useful out-of-the-box for those seeking to secure their Spring-based + applications, and can be easily adapted to complex customized + requirements. + + Security involves two distinct operations, authentication and + authorization. The former relates to resolving whether or not a caller + is who they claim to be. Authorization on the other hand relates to + determining whether or not an authenticated caller is permitted to + perform a given operation. + + Throughout the Acegi Security System for Spring, the user, system + or agent that needs to be authenticated is referred to as a "principal". + The security architecture does not have a notion of roles or groups, + which you may be familiar with from other security + implementations. + + + + Request Contexts + + + Contexts + + Many applications require a way of sharing objects between + classes, but without resorting to passing them in method signatures. + This is commonly achieved by using a ThreadLocal. + The Acegi Security System for Spring uses + ThreadLocal functionality and introduces the + concept of "request contexts". + + By placing an object into a request context, that object becomes + available to any other object on the current thread of execution. The + request context is not passed around as a method parameter, but is + held in a ThreadLocal. The Acegi Security System + for Spring uses the request context to pass around the authentication + request and response. + + A request context is a concrete implementation of the + Context interface, which exposes a single + method: + + public void validate() throws ContextInvalidException; + + This validate() method is called to confirm + the Context is properly setup. An implementation + will typically use this method to check that the objects it holds are + properly setup. + + The ContextHolder class makes the + Context available to the current thread of + execution using a ThreadLocal. A + ContextInterceptor is also provided, which is + intended to be chained into the bean context using + ProxyFactoryBean. The + ContextInterceptor simply calls + Context.validate(), which guarantees to business + methods that a valid Context is available from the + ContextHolder. + + + + Secure Contexts + + The Acegi Security System for Spring requires the + ContextHolder to contain a request context that + implements the SecureContext interface. An + implementation is provided named SecureContextImpl. + The SecureContext simply extends the + Context discussed above and adds a holder and + validation for an Authentication object. + + + + Custom Contexts + + Developers can create their own request context classes to store + application-specific objects. Such request context classes will need + to implement the Context interface. If the Acegi + Security System for Spring is to be used, developers must ensure any + custom request contexts implement the SecureContext + interface. + + + + Future Work + + Over time it is hoped that the Spring remoting classes can be + extended to support propagation of the Context + between ContextHolders on the client and + server. + + + + + Security Interception + + + Configuration + + The security architecture is implemented by placing a properly + configured SecurityInterceptor into the bean + context, and then chaining that SecurityInterceptor + into a business object. This chaining is accomplished using Spring’s + ProxyFactoryBean, as commonly used by many other + parts of Spring (refer to the security test cases and sample + application for examples). The SecurityInterceptor + is configured as follows: + + <bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor"> + <property name="validateConfigAttributes"><value>true</value></property> + <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,RUN_AS_SERVER + net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER + </value> + </property> +</bean> + + As shown above, the SecurityInterceptor is + configured with a reference to an + AuthenticationManager, + AccessDecisionManager and + RunAsManager, which are each discussed in separate + sections below. The SecurityInterceptor is also + configured with "configuration attributes" that apply to different + method signatures. A configuration attribute is simply a + ConfigAttribute instance that has special meaning + to an AccessDecisionManager and/or + RunAsManager. + + The SecurityInterceptor can be configured + with configuration attributes in three ways. The first is via a + property editor and the bean context, which is shown above. The second + is via defining the configuration attributes in your source code using + Commons Attributes. The third is via writing your own + MethodDefinitionSource, although this is beyond the + scope of this document. Irrespective of the approach used, the + MethodDefinitionSource is responsible for returning + a ConfigAttributeDefinition object that contains + all of the configuration attributes associated with a single secure + method. + + If using the property editor approach (as shown above), commas + are used to delimit the different configuration attributes that apply + to a given method pattern. Each configuration attribute is assigned + into its own SecurityConfig object. + SecurityConfig is a concrete implementation of + ConfigAttribute, and simply stores the + configuration attribute as a String. + + If using the Commons Attributes approach, your bean context will + be configured differently: + + <bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/> +<bean id="methodDefinitionSource" class="net.sf.acegisecurity.MethodDefinitionAttributes"> + <property name="attributes"><ref local="attributes"/></property> +</bean> + +<bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor"> + <property name="validateConfigAttributes"><value>false</value></property> + <property name="authenticationManager"><ref bean="authenticationManager"/></property> + <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> + <property name="runAsManager"><ref bean="runAsManager"/></property> + <property name="methodDefinitionSource"><ref bean="methodDefinitionSource"/></property> +</bean> + + In addition, your source code will contain Commons Attributes + tags that refer to a concrete implementation of + ConfigAttribute. The following example uses the + SecurityConfig implementation to represent the + configuration attributes, and results in the same security + configuration as provided by the property editor approach + above: + + public interface BankManager { + + /** + * @@SecurityConfig("ROLE_SUPERVISOR") + * @@SecurityConfig("RUN_AS_SERVER") + */ + public void deleteSomething(int id); + + /** + * @@SecurityConfig("ROLE_SUPERVISOR") + * @@SecurityConfig("RUN_AS_SERVER") + */ + public void deleteAnother(int id); + + /** + * @@SecurityConfig("ROLE_TELLER") + * @@SecurityConfig("ROLE_SUPERVISOR") + * @@SecurityConfig("BANKSECURITY_CUSTOMER") + * @@SecurityConfig("RUN_AS_SERVER") + */ + public float getBalance(int id); +} + + You might have noticed the + validateConfigAttributes property in the above + SecurityInterceptor examples. When set to + true (the default), at startup time the + SecurityInterceptor will evaluate if the provided + configuration attributes are valid. It does this by checking each + configuration attribute can be processed by either the + AccessDecisionManager or the + RunAsManager. If neither of these can process a + given configuration attribute, an exception is thrown. If using the + Commons Attributes method of configuration, you should set + validateConfigAttributes to + false. + + + + Runtime Processing + + At runtime the SecurityInterceptor has three + basic tasks: authenticate, authorize and perform any run-as + authentication replacement. It assesses the method pattern being + invoked to determine whether or not it is secure. A secure method + matches a method pattern defined with configuration attributes in the + bean context, whilst a public method is not defined in the bean + context. + + If a public method is called, + SecurityInterceptor will make no effort to + authenticate, authorize or perform any run-as authentication + replacement for the request. However, should there be an + Authentication object in the + ContextHolder, it will have its authenticated + property set to false. Once this is handled, + invocation of the public method will proceed as normal. + + If a secure method is called, + SecurityInterceptor will need to extract an + Authentication object from the request context. As + discussed above, the SecurityInterceptor requires + the SecureContext interface be implemented on the + object contained in the ContextHolder. Once the + Authentication object is extracted from the + SecureContext, it will be passed to the + SecurityInterceptor’s + AuthenticationManager. + + The AuthenticationManager will perform + authentication, throwing an AuthenticationException + if there is a problem. If successful, the + AuthenticationManager will return a populated + Authentication object, including the authorities + granted to the principal. SecurityInterceptor will + then call its AccessDecisionManager. + + When the AccessDecisionManager is invoked by + the SecurityInterceptor, it will be passed + important information it may require to make an authorization + decision. This includes details of the secure method that is being + invoked, the authenticated principal, and the + ConfigAttributeDefinition (the collection of + configuration attributes associated with the secure method). If + authorization fails, the AccessDecisionManager will + throw an AccessDeniedException. If successful, the + SecurityInterceptor will then call the + RunAsManager. + + Like the AccessDecisionManager, the + RunAsManager is called with details of the secure + method being invoked, the authenticated principal, and the + ConfigAttributeDefinition. The + RunAsManager can then choose to return a + replacement Authentication object that should be + used for the request. If a replacement + Authentication object is returned, the + SecurityInterceptor will update the + ContextHolder for the duration of the method + invocation, returning to the original + Authentication object after the method has been + invoked. + + + + Putting it into Context + + The above briefly outlines that the + AuthenticationManager, + AccessDecisionManager and + RunAsManager perform the bulk of the security + decision making. The SecurityInterceptor simply + coordinates the method invocation and stores the configuration + attributes that are relevant to different methods. It also coordinates + the temporary replacement of the Authentication + object as a consequence of RunAsManager responses. + The way AuthenticationManager, + AccessDecisionManager and + RunAsManager operate is discussed in detail + below. + + + + + Authentication + + + Authentication Requests + + Authentication requires a way for client code to present its + security identification to the Acegi Security System for Spring. This + is the role of the Authentication interface. The + Authentication interface holds three important + objects: the principal (the identity of the caller), the credentials + (the proof of the identity of the caller, such as a password), and the + authorities that have been granted to the principal. The principal and + its credentials are populated by the client code, whilst the granted + authorities are populated by the + AuthenticationManager. The Acegi Security System + for Spring includes several concrete Authentication + implementations: + + + + UsernamePasswordAuthenticationToken + allows a username and password to be presented as the principal + and credentials respectively. + + + + TestingAuthenticationToken facilitates + unit testing by automatically being considered an authenticated + object by its associated + AuthenticationProvider. + + + + RunAsUserToken is used by the default + run-as authentication replacement implementation. This is + discussed further in the Run-As Authentication Replacement + section. + + + + PrincipalAcegiUserToken and + JettyAcegiUserToken implement + AuthByAdapter (a subclass of + Authentication) and are used whenever + authentication is completed by Acegi Security System for Spring + container adapters. This is discussed further in the Container + Adapters section. + + + + The authorities granted to a principal are represented by the + GrantedAuthority interface. The + GrantedAuthority interface is discussed at length + in the Authorization section. + + + + Authentication Manager + + As discussed in the Security Interception section, the + SecurityInterceptor extracts the + Authentication object from the + SecureContext. This is then passed to an + AuthenticationManager. The + AuthenticationManager interface is very + simple: + + public Authentication authenticate(Authentication authentication) throws AuthenticationException; + + Implementations of AuthenticationManager are + required to throw an AuthenticationException should + authentication fail, or return a fully populated + Authentication object. In particular, the returned + Authentication object should contain an array of + GrantedAuthority objects. The + SecurityInterceptor places the populated + Authentication object back in the + SecureContext, overwriting the original + Authentication object. + + The AuthenticationException has a number of + subclasses. The most important are + BadCredentialsException (an incorrect principal or + credentials), DisabledException and + LockedException. The latter two exceptions indicate + the principal was found, but the credentials were not checked and + authentication is denied. An + AuthenticationServiceException is also provided, + which indicates the authentication system could not process the + request (eg a database was unavailable). + + + + Provider-Based Authentication + + Whilst the basic Authentication and + AuthenticationManager interfaces enable users to + develop their own authentication systems, users should consider using + the provider-based authentication packages provided in the Acegi + Security System for Spring. The key class, + ProviderManager, is configured via the bean context + with a list of AuthenticationProviders: + + <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"> + <property name="providers"> + <list> + <ref bean="daoAuthenticationProvider"/> + </list> + </property> +</bean> + + ProviderManager calls a series of registered + AuthenticationProvider implementations, until one + is found that indicates it is able to authenticate a given + Authentication class. When the first compatible + AuthenticationProvider is located, it is passed the + authentication request. The AuthenticationProvider + will then either throw an AuthenticationException + or return a fully populated Authentication + object. + + Note the ProviderManager may throw a + ProviderNotFoundException (subclass of + AuthenticationException) if it none of the + registered AuthenticationProviders can validate the + Authentication object. + + Several AuthenticationProvider + implementations are provided with the Acegi Security System for + Spring: + + + + TestingAuthenticationProvider is able + to authenticate a TestingAuthenticationToken. + The limit of its authentication is simply to treat whatever is + contained in the TestingAuthenticationToken + as valid. This makes it ideal for use during unit testing, as + you can create an Authentication object with + precisely the GrantedAuthority objects + required for calling a given method. + + + + DaoAuthenticationProvider is able to + authenticate a + UsernamePasswordAuthenticationToken by + accessing an authentication respository via a data access + object. This is discussed further below. + + + + RunAsImplAuthenticationToken is able to + authenticate a RunAsUserToken. This is + discussed further in the Run-As Authentication Replacement + section. + + + + AuthByAdapterProvider is able to + authenticate any AuthByAdapter (a subclass of + Authentication used with container adapters). + This is discussed further in the Container Adapters + section. + + + + + + Data Access Object Authentication Provider + + The Acegi Security System for Spring includes a + production-quality AuthenticationProvider + implementation called DaoAuthenticationProvider. + This authentication provider is able to authenticate a + UsernamePasswordAuthenticationToken by obtaining + authentication details from a data access object configured at bean + creation time: + + <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> + + By default the DaoAuthenticationProvider does + not require an exact match on usernames, but it does require an exact + match on passwords. This behavior can be configured with the optional + properties shown above. + + For a class to be able to provide the + DaoAuthenticationProvider with access to an + authentication repository, it must implement the + AuthenticationDao interface: + + public User loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException; + + The User object holds basic information such + as the username, password, granted authorities and whether the user is + enabled or disabled. + + Given AuthenticationDao is so simple to + implement, it should be easy for users to retrieve authentication + information using a persistence strategy of their choice. + + A design decision was made not to support account locking in the + DaoAuthenticationProvider, as doing so would have + increased the complexity of the AuthenticationDao + interface. Such functionality could be easily provided in a new + AuthenticationManager or + AuthenticationProvider implementation. + + + + In-Memory Authentication + + Whilst it is easy to use the + DaoAuthenticationProvider and create a custom + AuthenticationDao implementation that extracts + information from a persistence engine of choice, many applications do + not require such complexity. One alternative is to configure an + authentication repository in the bean context itself using the + InMemoryDaoImpl: + + <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> + + The userMap property contains each of the + usernames, passwords, a list of granted authorities and an optional + enabled/disabled keyword. Commas delimit each token. The username must + appear to the left of the equals sign, and the password must be the + first token to the right of the equals sign. The + enabled and disabled keywords + (case insensitive) may appear in the second or any subsequent token. + Any remaining tokens are treated as granted authorities, which are + created as GrantedAuthorityImpl objects (refer to + the Authorization section for further discussion on granted + authorities). Note that if a user has no password or no granted + authorities, the user will not be created in the in-memory + authentication repository. + + + + JDBC Authentication + + The Acegi Security System for Spring also includes an + authentication provider that can obtain authentication information + from a JDBC data source. The typical configuration for the + JdbcDaoImpl is shown below: + + <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> + + You can use different relational database management systems by + modifying the DriverManagerDataSource shown above. + Irrespective of the database used, a standard schema must be used as + indicated in dbinit.txt. + + The Acegi Security System for Spring ships with a Hypersonic SQL + instance that has the required authentication information and sample + data already populated. To use this server, simply execute the + server.bat or server.sh script + included in the distribution. This will load a new database server + instance that will service requests made to the URL indicated in the + bean context configuration shown above. + + As discussed further in the Container Adapters section, most + authentication providers that perform actual authentication are + configured within a container adapter bean context typically called + acegisecurity.xml. This file by default uses the + in-memory DAO authentication provider. The Acegi Security System for + Spring includes an alternative configuration file named + acegisecurity-jdbc.xml, which uses the JDBC DAO + authentication provider. To use a JDBC authentication repository, + simply copy this file over the existing + acegisecurity.xml (or other name) being used by + your container. Alternatively, leave the name as + acegisecurity-jdbc.xml and modify your container + configuration file to refer to + acegisecurity-jdbc.xml. You will also need to copy + the relevant JDBC driver library to your container's + lib directory. If you are using Hypersonic SQL, + copy the hsqldb.jar file. + + + + Authentication Recommendations + + With the heavy use of interfaces throughout the authentication + system (Authentication, + AuthenticationManager, + AuthenticationProvider and + AuthenticationDao) it might be confusing to a new + user to know which part of the authentication system to customize. In + general, the following is recommended: + + + + Use the + UsernamePasswordAuthenticationToken or an + AuthByContainer implementation where + possible. + + + + If you simply need to implement a new authentication + repository (eg to obtain user details from your application’s + existing database), use the + DaoAuthenticationProvider along with the + AuthenticationDao. It is the fastest and safest + way to integrate an external database. + + + + Never enable the + TestingAuthenticationProvider on a production + system. Doing so will allow any client to simply present a + TestingAuthenticationToken and obtain whatever + access they request. + + + + Adding a new AuthenticationProvider is + sufficient to support most custom authentication requirements. + Only unusual requirements would require the + ProviderManager to be replaced with a different + AuthenticationManager. + + + + + + + Authorization + + + Granted Authorities + + As briefly mentioned in the Authentication + section, all Authentication implementations are + required to store an array of GrantedAuthority + objects. These represent the authorities that have been granted to the + principal. The GrantedAuthority objects are + inserted into the Authentication object by the + AuthenticationManager and are later read by + AccessDecisionManagers when making authorization + decisions. + + GrantedAuthority is an interface with only + one method: + + public String getAuthority(); + + This method allows AccessDecisionManagers to + obtain a precise String representation of the + GrantedAuthority. By returning a representation as + a String, a GrantedAuthority can + be easily "read" by most AccessDecisionManagers. If + a GrantedAuthority cannot be precisely represented + as a String, the + GrantedAuthority is considered "complex" and + getAuthority() must return + null. + + An example of a "complex" GrantedAuthority + would be an implementation that stores a list of operations and + authority thresholds that apply to different customer account numbers. + Representing this complex GrantedAuthority as a + String would be quite complex, and as a result the + getAuthority() method should return + null. This will indicate to any + AccessDecisionManager that it will need to + specifically support the GrantedAuthority + implementation in order to understand its contents. + + The Acegi Security System for Spring includes one concrete + GrantedAuthority implementation, + GrantedAuthorityImpl. This allows any + user-specified String to be converted into a + GrantedAuthority. All + AuthenticationProviders included with the security + architecture used GrantedAuthorityImpl to populate + the Authentication object. + + + + Access Decision Managers + + The AccessDecisionManager is called by the + SecurityInterceptor and is responsible for making + final access control decisions. The + AccessDecisionManager interface contains two + methods: + + public void decide(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config) throws AccessDeniedException; +public boolean supports(ConfigAttribute attribute); + + As can be seen from the first method, the + AccessDecisionManager is passed via method + parameters all information that is likely to be of value in assessing + an authorization decision. In particular, passing the + MethodInvocation enables those arguments contained + in the intercepted method call to be inspected. For example, if a + Customer argument was passed in the intercepted + method call, this could be extracted from the + MethodInvocation and used in making an access + control decision. Implementations are expected to throw an + AccessDeniedException if access is denied. + + The supports(ConfigAttribute) method is + called by the SecurtyInterceptor at startup time to + determine if the AccessDecisionManager can process + the passed ConfigAttribute. + + + + Voting Decision Manager + + Whilst users can implement their own + AccessDecisionManager to control all aspects of + authorization, the Acegi Security System for Spring includes an + AccessDecisionManager implementation that is based + on voting. Using this approach, a series of + AccessDecisionVoter implementations are polled on + an authorization decision. The + AccessDecisionManager then decides whether or not + to throw an AccessDeniedException based on its + assessment of the votes. + + The AccessDecisionVoter interface has two + methods: + + public int vote(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config); +public boolean supports(ConfigAttribute attribute); + + Concrete implementations return an int, with possible values + being reflected in the AccessDecisionVoter static + fields ACCESS_ABSTAIN, + ACCESS_DENIED and + ACCESS_GRANTED. A voting implementation will return + ACCESS_ABSTAIN if it has no opinion on an + authorization decision. If it does have an opinion, it must return + either ACCESS_DENIED or + ACCESS_GRANTED. + + There are three AccessDecisionManagers + provided with the Acegi Security System for Spring that tally the + votes. The ConsensusBased implementation will grant + or deny access based on the consensus of non-abstain votes. Properties + are provided to control behavior in the event of an equality of votes + or if all votes are abstain. The AffirmativeBased + implementation will grant access if one or more + ACCESS_GRANTED votes were received (ie a deny vote + will be ignored, provided there was at least one grant vote). Like the + ConsensusBased implementation, there is a parameter + that controls the behavior if all voters abstain. The + UnanimousBased provider will deny access if there + was any ACCESS_DENIED result. Like the other + implementations, there is a parameter that controls the behaviour if + all voters abstain. + + It is possible to implement a custom + AccessDecisionManager that tallies votes + differently. For example, votes from a particular + AccessDecisionVoter might receive additional + weighting, whilst a deny vote from a particular voter would have a + veto effect. + + There is one concrete AccessDecisionVoter + implementation provided with the Acegi Security System for Spring. The + RoleVoter class will vote if any ConfigAttribute + begins with ROLE_. It will vote to grant access if + there is a GrantedAuthority which returns a + String representation (via the + getAuthority() method) exactly equal to one or more + ConfigAttributes starting with + ROLE_. If there is no exact match of any + ConfigAttribute starting with + ROLE_, the RoleVoter will vote + to deny access. If no ConfigAttribute begins with + ROLE_, the voter will abstain. + RoleVoter is case sensitive on comparisons as well + as the ROLE_ prefix. + + It is possible to implement a custom + AccessDecisionVoter. Several examples are provided + in the Acegi Security System for Spring unit tests, including + BankSecurityVoter and XVoter. + The BankSecurityVoter abstains from voting + decisions where the BANKSECURITY_CUSTOMER + ConfigAttribute is not found. If voting, it queries + the MethodInvocation to extract the account number + subject of the method call. It votes to grant access if the account + number matches a GrantedAuthority.getAuthority() of + ACCOUNT_xxxx where xxxx is the + account number subject of the method call. All of this is achieved + with relatively few lines of code and demonstrates the flexibility of + the authorization model. + + Note that an AccessDecisionManager or + AccessDecisionVoter can also support complex + GrantedAuthority implementations that cannot + represent themselves as a String via the + getAuthority() method. In our + BankSecurityVoter example, we could have it ignore + the String representations of + GrantedAuthority objects but instead processed any + AccountHolderGrantedAuthority objects. This complex + granted authority could have conveyed more information than simply an + account number, such as the maximum amount the principal is permitted + to deposit. The BankSecurityVoter could then detect + a deposit value via the MethodInvocation and grant + or deny access accordingly. + + + + Authorization Recommendations + + Given there are several ways to achieve similar authorization + outcomes in the Acegi Security System for Spring, the following + general recommendations are made: + + + + Grant authorities using + GrantedAuthorityImpl where possible. Because it + is already supported by the Acegi Security System for Spring, you + avoid the need to create custom + AuthenticationManager or + AuthenticationProvider implementations simply + to populate the Authentication object with a + custom GrantedAuthority. + + + + Most authorization decision rules can be easily satisfied by + writing an AccessDecisionVoter implementation + and using either ConsensusBased or + AffirmativeBased as the + AccessDecisionManager. + + + + + + + Run-As Authentication Replacement + + + Purpose + + The SecurityInterceptor is able to temporarily replace the + Authentication object in the + ContextHolder during a method invocation. This only + occurs if the original Authentication object was + successfully processed by the AuthenticationManager + and AccessDecisionManager. The + RunAsManager will indicate the replacement + Authentication object (if any) that should be used + during the method invocation. + + By temporarily replacing the Authentication + object during a method invocation, the method invocation will be able + to call other objects which require different authentication and + authorization credentials. It will also be able to perform any + internal security checks for specific + GrantedAuthority objects. + + + + Usage + + A RunAsManager interface is provided by the + Acegi Security System for Spring: + + public Authentication buildRunAs(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config); +public boolean supports(ConfigAttribute attribute); + + The first method returns the Authentication + object that should replace the existing + Authentication object for the duration of the + method invocation. If the method returns null, it + indicates no replacement should be made. The second method is used by + the SecurityInterceptor as part of its startup + validation of configuration attributes. + + One concrete implementation of a RunAsManager + is provided with the Acegi Security System for Spring. The + RunAsManagerImpl class returns a replacement + RunAsUserToken if any + ConfigAttribute starts with + RUN_AS_. If any such + ConfigAttribute is found, the replacement + RunAsUserToken will contain the same principal, + credentials and granted authorities as the original + Authentication object, along with a new + GrantedAuthorityImpl for each + RUN_AS_ ConfigAttribute. Each + new GrantedAuthorityImpl will be prefixed with + ROLE_, followed by the RUN_AS + ConfigAttribute. For example, a + RUN_AS_SERVER will result in the replacement + RunAsUserToken containing a + ROLE_RUN_AS_SERVER granted authority. + + The replacement RunAsUserToken is just like + any other Authentication object. It needs to be + authenticated by the AuthenticationManager, + probably via delegation to a suitable + AuthenticationProvider. The + RunAsImplAuthenticationProvider performs such + authentication. It simply accepts as valid whatever + RunAsUserToken is presented. + + To ensure malicious code does not create a + RunAsUserToken and presents it for guaranteed + acceptance by the RunAsImplAuthenticationProvider, + the hash of a key is stored in all generated tokens. The + RunAsManagerImpl and + RunAsImplAuthenticationProvider is created in the + bean context with the same key: + + <bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl"> + <property name="key"><value>my_run_as_password</value></property> +</bean><bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider"> + <property name="key"><value>my_run_as_password</value></property> +</bean> + + By using the same key, each RunAsUserToken + can be validated it was created by an approved + RunAsManagerImpl. The + RunAsUserToken is immutable after creation for + security reasons. + + + + + Container Adapters + + + Overview + + A very large proportion of Spring applications are web-based. + The Acegi Security System for Spring supports integration with + containers that host such applications. This integration means that + applications can continue to leverage the authentication and + authorization capabilities built into containers (such as + isUserInRole() and form-based or basic + authentication), whilst benefiting from the enhanced bean-level + security capabilities provided by the Acegi Security System for + Spring. + + The integration between a container and the Acegi Security + System for Spring is achieved through an adapter. The adapter provides + a container-compatible user authentication provider, and often needs + to return a container-compatible user object. + + The adapter is instantiated by the container and is defined in a + container-specific configuration file. The adapter then loads a Spring + bean context which defines the normal authentication manager settings, + such as the authentication providers that can be used to authenticate + the request. The bean context is usually named + acegisecurity.xml and is placed in a + container-specific location. + + The Acegi Security System for Spring currently supports Jetty, + Catalina (Tomcat), JBoss and Resin. Additional container adapters can + easily be written. + + + + Filter Integration + + Web applications wishing to use container adapters should define + the standard <security-constraint> and + <login-config> entries in their + web.xml file. These will cause the container + authentication to occur, which will delegate to the Acegi Security + System for Spring provided adapter. + + The adapter will return a container-compatible user object that + also implements the Authentication interface. The + container then makes this returned user object available from a + container-specific well-known location. + + The AbstractIntegrationFilter and its + subclasses finalise the adapter integration. These classes are + standard filters, and at the start of each request they will attempt + to extract the Authentication object from the + container's well-known location. The Authentication + object will then be associated with the + ContextHolder for the duration of the request, and + be removed when the request is finished. Three concrete subclasses of + AbstractIntegrationFilter are provided with the + Acegi Security System for Spring: + + + + HttpRequestIntegrationFilter is used + with Catalina, Jetty and Resin. It extracts the authentication + information from + HttpServletRequest.getUserPrincipal(). + + + + JbossIntegrationFilter is used with + JBoss. It extracts the authentication from + java:comp/env/security/subject. + + + + AutoIntegrationFilter automatically + determines which filter to use. This makes a web application WAR + file more portable, as the web.xml is not + hard-coded to a container-specific + AbstractIntegrationFilter. + + + + Once in the ContextHolder, the standard Acegi + Security System for Spring classes can be used. Because + ContextHolder is a standard object which is + populated using a filter at the container level, JSPs and Servlets do + not need to use Spring's MVC packages. This enables those applications + that use other MVC frameworks to still leverage Spring's other + capabilities, with full authentication and authorization support. The + debug.jsp page provided with the sample application + demonstrates accessing the ContextHolder + independent of Spring's MVC packages. + + + + Adapter Authentication Provider + + As is always the case, the container adapter generated + Authentication object still needs to be + authenticated by an AuthenticationManager when + requested to do so by the SecurityInterceptor. The + AuthenticationManager needs to be certain the + adapter-provided Authentication object is valid and + was actually authenticated by a trusted adapter. + + Adapters create Authentication objects which + are immutable and implement the AuthByAdapter + interface. These objects store the hash of a key that is defined by + the adapter. This allows the Authentication object + to be validated by the AuthByAdapterProvider. This + authentication provider is defined as follows: + + <bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider"> + <property name="key"><value>my_password</value></property> +</bean> + + The key must match the key that is defined in the + container-specific configuration file that starts the adapter. The + AuthByAdapterProvider automatically accepts as + valid any AuthByAdapter implementation that returns + the expected hash of the key. + + To reiterate, this means the adapter will perform the initial + authentication using providers such as + DaoAuthenticationProvider, returning an + AuthByAdapter instance that contains a hash code of + the key. Later, when an application calls a + SecurityInterceptor managed bean, the + AuthByAdapter instance in the + ContextHolder will be tested by the application's + AuthByAdapterProvider. There is no requirement for + additional authentication providers such as + DaoAuthenticationProvider within the + application-specific bean context, as the only type of + Authentication instance that will be presented by + the application is from the container adapter. + + Classloader issues are frequent with containers and the use of + container adapters illustrates this further. Each container requires a + very specific configuration. The installation instructions are + provided below. Once installed, please take the time to try the sample + application to ensure your container adapter is properly + configured. + + + + Catalina (Tomcat) Installation + + The following was tested with Jakarta Tomcat 5.0.19. We + automatically test the following directions using our container + integration test system and this version of Catalina (Tomcat). + + $CATALINA_HOME refers to the root of your + Catalina (Tomcat) installation. + + Edit your $CATALINA_HOME/conf/server.xml file + so the <Engine> section contains only one + active <Realm> entry. An example realm + entry: + + <Realm className="net.sf.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm" + appContextLocation="conf/acegisecurity.xml" + key="my_password" /> + + Be sure to remove any other <Realm> + entry from your <Engine> section. + + Copy acegisecurity.xml into + $CATALINA_HOME/conf. + + Copy acegi-security-catalina-server.jar into + $CATALINA_HOME/server/lib. + + Copy the following files into + $CATALINA_HOME/common/lib: + + + + aopalliance.jar + + + + spring.jar + + + + acegi-security-catalina-common.jar + + + + None of the above JAR files (or + acegi-security.jar) should be in your application's + WEB-INF/lib. The realm name indicated in your + web.xml does not matter with Catalina. + + + + Jetty Installation + + The following was tested with Jetty 4.2.18. We automatically + test the following directions using our container integration test + system and this version of Jetty. + + $JETTY_HOME refers to the root of your Jetty + installation. + + Edit your $JETTY_HOME/etc/jetty.xml file so + the <Configure class> section has a new + addRealm call: + + <Call name="addRealm"> + <Arg> + <New class="net.sf.acegisecurity.adapters.jetty.JettyAcegiUserRealm"> + <Arg>Spring Powered Realm</Arg> + <Arg>my_password</Arg> + <Arg>/etc/acegisecurity.xml</Arg> + </New> + </Arg> + </Call> + + Copy acegisecurity.xml into + $JETTY_HOME/etc. + + Copy the following files into + $JETTY_HOME/ext: + + aopalliance.jar + + + + commons-logging.jar + + + + spring.jar + + + + acegi-security-jetty-ext.jar + + + + None of the above JAR files (or + acegi-security.jar) should be in your application's + WEB-INF/lib. The realm name indicated in your + web.xml does matter with Jetty. The + web.xml must express the same + <realm-name> as your + jetty.xml (in the example above, "Spring Powered + Realm"). + + + + JBoss Installation + + The following was tested with JBoss 3.2.3. We automatically test + the following directions using our container integration test system + and this version of JBoss. + + $JBOSS_HOME refers to the root of your JBoss + installation. + + Edit your + $JBOSS_HOME/server/your_config/conf/login-config.xml + file so that it contains a new entry under the + <Policy> section: + + <application-policy name = "SpringPoweredRealm"> + <authentication> + <login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule" + flag = "required"> + <module-option name = "appContextLocation">acegisecurity.xml</module-option> + <module-option name = "key">my_password</module-option> + </login-module> + </authentication> + </application-policy> + + Copy acegisecurity.xml into + $JBOSS_HOME/server/your_config/conf. + + Copy the following files into + $JBOSS_HOME/server/your_config/lib: + + aopalliance.jar + + + + spring.jar + + + + acegi-security-jboss-lib.jar + + + + None of the above JAR files (or + acegi-security.jar) should be in your application's + WEB-INF/lib. The realm name indicated in your + web.xml does not matter with JBoss. However, your + web application's WEB-INF/jboss-web.xml must + express the same <security-domain> as your + login-config.xml. For example, to match the above + example, your jboss-web.xml would look like + this: + + <jboss-web> + <security-domain>java:/jaas/SpringPoweredRealm</security-domain> +</jboss-web> + + + + Resin Installation + + The following was tested with Resin 3.0.6. + + $RESIN_HOME refers to the root of your Resin + installation. + + Resin provides several ways to support the container adapter. In + the instructions below we have elected to maximise consistency with + other container adapter configurations. This will allow Resin users to + simply deploy the sample application and confirm correct + configuration. Developers comfortable with Resin are naturally able to + use its capabilities to package the JARs with the web application + itself, and/or support single sign-on. + + Copy the following files into + $RESIN_HOME/lib: + + aopalliance.jar + + + + commons-logging.jar + + + + spring.jar + + + + acegi-security-resin-lib.jar + + + + Unlike the container-wide acegisecurity.xml + files used by other container adapters, each Resin web application + will contain its own + WEB-INF/resin-acegisecurity.xml file. Each web + application will also contain a resin-web.xml file + which Resin uses to start the container adapter: + + <web-app> + <authenticator> + <type>net.sf.acegisecurity.adapters.resin.ResinAcegiAuthenticator</type> + <init> + <app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location> + <key>my_password</key> + </init> + </authenticator> +</web-app> + + With the basic configuration provided above, none of the JAR + files listed (or acegi-security.jar) should be in + your application's WEB-INF/lib. The realm name + indicated in your web.xml does not matter with + Resin, as the relevant authentication class is indicated by the + <authenticator> setting. + + + + + Sample Application + + Included with the Acegi Security System for Spring is a very + simple application that can demonstrate the basic security facilities + provided by the system and confirm your container adapter is properly + configured. + + To install, configure your container as described in the Container + Adapters section of this chapter. Do not modify + acegisecurity.xml. It contains a very basic in-memory + authentication configuration that is compatible with the sample + application. Next, copy the contacts.war file from + the Acegi Security System for Spring distribution into your container’s + webapps directory. + + After starting your container, check the application can load. + Visit http://localhost:8080/contacts (or whichever + URL is appropriate for your web container). A random contact should be + displayed. Click "Refresh" several times and you will see different + contacts. The business method that provides this random contact is not + secured. + + Next, click "Debug". You will be prompted to authenticate, and a + series of usernames and passwords are suggested on that page. Simply + authenticate with any of these and view the resulting page. It should + contain a success message similar to the following: + +
+ Context on ContextHolder is of type: + net.sf.acegisecurity.context.SecureContextImpl + + The Context implements SecureContext. + + Authentication object is of type: + net.sf.acegisecurity.adapters.PrincipalAcegiUserToken + + Authentication object as a String: + net.sf.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2: + Username: marissa; Password: [PROTECTED]; Authenticated: true; Granted + Authorities: ROLE_TELLER, ROLE_SUPERVISOR + + Authentication object holds the following granted + authorities: + + ROLE_TELLER (getAuthority(): ROLE_TELLER) + + ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR) + + SUCCESS! Your container adapter appears to be properly + configured! +
+ + If you receive a different message, check you have properly + configured your container adapter. Refer to the instructions provided + above. + + Once you successfully receive the above message, return to the + sample application's home page and click "Manage". You can then try out + the application. Notice that only the contacts belonging to the + currently logged on user are displayed, and only users with + ROLE_SUPERVISOR are granted access to delete their + contacts. Behind the scenes, the SecurityInterceptor + is securing the business objects. +
+ + + Become Involved + + We welcome you to become involved in the Acegi Security System for + Spring project. There are many ways of contributing, including reading + the mailing list and responding to questions from other people, writing + new code, improving existing code, assisting with documentation, or + simply making suggestions. + + SourceForge provides CVS services for the project, allowing + anybody to access the latest code. If you wish to contribute new code, + please observe the following requirements. These exist to maintain the + quality and consistency of the project: + + + + Run the Ant format task to convert your + code into the project's consistent style + + + + Ensure your code does not break any unit tests (run the Ant + tests target) + + + + Please use the container integration test system to test your + code in the project's officially supported containers + + + + When writing a new container adapter, expand the container + integration test system to properly test it + + + + If you have added new code, please provide suitable unit + tests + + + + Add a CVS $Id$ tag to the JavaDocs for any + new class you create + + + + Mentioned above is our container integration test system, which + aims to test the Acegi Security System for Spring container adapters + with current, production versions of each container. Some containers + might not be supported due to difficulties with starting or stopping the + container within an Ant target. You will need to download the container + release files as specified in the integration test + readme.txt file. These files are intentionally + excluded from CVS due to their large size. + + + + Further Information + + Questions and comments on the Acegi Security System for Spring are + welcome. Please direct comments to the Spring Users mailing list or + ben.alex@acegi.com.au. Our project home page (where you can obtain the + latest release of the project and access to CVS) is at + http://acegisecurity.sourceforge.net. + +
+
\ No newline at end of file diff --git a/docs/reference/styles/fopdf.xsl b/docs/reference/styles/fopdf.xsl new file mode 100644 index 0000000000..0327283fc6 --- /dev/null +++ b/docs/reference/styles/fopdf.xsl @@ -0,0 +1,459 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + Version: + + + + + + + + + + + + + + + + + + + + + + + + -5em + -5em + + + + + + + + + + + + + + + Acegi Security System for Spring + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bold + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 0 + 1 + + 1 + + + + + + book toc + + + + 2 + + + + + + + + + + 0 + 0 + 0 + + + 5mm + 10mm + 10mm + + 15mm + 10mm + 0mm + + 18mm + 18mm + + + 0pc + + + + + 11 + 8 + + + 1.4 + + + + + + + 0.8em + + + + + + 17.4cm + + + + 4pt + 4pt + 4pt + 4pt + + + + 0.1pt + 0.1pt + + + + + 1 + + + + + + + + left + bold + + + pt + + + + + + + + + + + + + + + 0.8em + 0.8em + 0.8em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.6em + 0.6em + 0.6em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.4em + 0.4em + 0.4em + + + pt + + 0.1em + 0.1em + 0.1em + + + + + bold + + + pt + + false + 0.4em + 0.6em + 0.8em + + + + + + + + + pt + + + + + 1em + 1em + 1em + + + #444444 + solid + 0.1pt + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + + + + 1 + + #F0F0F0 + + + + + + 0 + 1 + + + 90 + + + + + '1' + &admon_gfx_path; + + + + + + figure after + example before + equation before + table before + procedure before + + + + 1 + + + + 0.8em + 0.8em + 0.8em + 0.1em + 0.1em + 0.1em + + + diff --git a/docs/reference/styles/html.css b/docs/reference/styles/html.css new file mode 100644 index 0000000000..2e4fb0a42e --- /dev/null +++ b/docs/reference/styles/html.css @@ -0,0 +1,132 @@ +A { + color: #003399; +} + +A:active { + color: #003399; +} + +A:visited { + color: #888888; +} + +P, DL, DT, DD, BLOCKQUOTE { + color: #000000; + margin-bottom: 3px; + margin-top: 3px; + padding-top: 0px; + /*border: 1px solid black;*/ +} + +OL, UL, P { + margin-top: 6px; + margin-bottom: 6px; +} + +P, BLOCKQUOTE { + font-size: 80%; +} + +td { + font-size: 80%; + + +TD, TH, SPAN { + color: #000000; +} + +BLOCKQUOTE { + margin-right: 0px; +} + + +H1, H2, H3, H4, H5, H6 { + color: #000000; + font-weight:500; + margin-top:0px; + padding-top:14px; + font-family: Arial, helvetica, sans-serif; + margin-bottom: 0px; +} + +TABLE { + border-collapse: collapse; + border-spacing:0; + border: 1px thin black; + empty-cells: hide; +} + +TD { + padding: 4pt; +} + +H1 { + font-size: 130%; +} +H2 { + font-size: 110%; +} +H3 { + font-size: 100%; font-weight: bold; +} +H4 { + font-size: 90%; font-weight: bold; +} +H5 { + font-size: 90%; font-style: italic; +} +H6 { + font-size: 100%; font-style: italic; +} + +TT { +font-size: 90%; + font-family: "Courier New", Courier, monospace; + color: #000000; +} + +.navheader, .navfooter { + background-color: #e4eff3; +} + +PRE { + font-size: 70%; + padding: 5px; + border-style: solid; + border-width: 1px; + border-color: #CCCCCC; + background-color: #F4F4F4; +} + +UL, OL, LI { + list-style: disc; +} + +HR { + width: 100%; + height: 1px; + background-color: #CCCCCC; + border-width: 0px; + padding: 0px; + color: #CCCCCC; +} + +.variablelist { + padding-top: 10; + padding-bottom:10; + margin:0; +} + +/*(.itemizedlist, UL { + padding-top: 0; + padding-bottom:0; + margin:0; +}*/ + +.term { + font-weight:bold; +} + + + + diff --git a/docs/reference/styles/html.xsl b/docs/reference/styles/html.xsl new file mode 100644 index 0000000000..247cadcaee --- /dev/null +++ b/docs/reference/styles/html.xsl @@ -0,0 +1,94 @@ + + + + + + + +]> + + + + + + + + ../styles/html.css + + + 1 + 0 + 1 + 0 + + + + + + book toc + + + + 3 + + + + + 1 + + + + + + + 1 + &callout_gfx_path; + + + 90 + + + + + '1' + &admon_gfx_path; + + + + + + figure after + example before + equation before + table before + procedure before + + + diff --git a/docs/reference/styles/html_chunk.xsl b/docs/reference/styles/html_chunk.xsl new file mode 100644 index 0000000000..c6f12b557e --- /dev/null +++ b/docs/reference/styles/html_chunk.xsl @@ -0,0 +1,96 @@ + + + + + + + +]> + + + + + + + + '5' + '1' + ../styles/html.css + + + 1 + 0 + 1 + 0 + + + + + + book toc + + + + 3 + + + + + 1 + + + + + + + 1 + &callout_gfx_path; + + + 90 + + + + + '1' + &admon_gfx_path; + + + + + + figure after + example before + equation before + table before + procedure before + + + diff --git a/extractor/.cvsignore b/extractor/.cvsignore new file mode 100644 index 0000000000..0476d368d7 --- /dev/null +++ b/extractor/.cvsignore @@ -0,0 +1,2 @@ +temporary + diff --git a/extractor/build.xml b/extractor/build.xml new file mode 100644 index 0000000000..a9051aa607 --- /dev/null +++ b/extractor/build.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extractor/project.properties b/extractor/project.properties new file mode 100644 index 0000000000..a499bf3e17 --- /dev/null +++ b/extractor/project.properties @@ -0,0 +1,35 @@ +# Ant properties for running the lib file extractor. + +# Values in this file will be overriden by any values with the same name +# in the user-created build.properties file. + +# $Id$ + +name=acegi-security-lib-extractor +extractor-version=0.3 + +tmp.dir=${basedir}/temporary + +# This is where extracted JARs are built (ie directly into the main lib dir) +# WARNING: This directory and subdirs will be deleted each time build is run +dest.dir=${basedir}/../lib/extracted + +source.dir.jboss=${basedir}/source/jboss +source.license.jboss=${basedir}/source/jboss/LICENSE.txt +dest.dir.jboss=${dest.dir}/jboss +extract.info.jboss=JBoss 3.2.3 see http://www.jboss.org + +source.dir.jetty=${basedir}/source/jetty +source.license.jetty=${basedir}/source/jetty/LICENSE.html +dest.dir.jetty=${dest.dir}/jetty +extract.info.jetty=Jetty 4.2.18 see http://jetty.mortbay.org + +source.dir.catalina=${basedir}/source/catalina +source.license.catalina=${basedir}/source/catalina/LICENSE +dest.dir.catalina=${dest.dir}/catalina +extract.info.catalina=Jakarta Tomcat 5.0.19 see http://jakarta.apache.org/tomcat/ + +source.dir.resin=${basedir}/source/resin +source.license.resin=${basedir}/source/resin/LICENSE +dest.dir.resin=${dest.dir}/resin +extract.info.resin=Resin 3.0.6 see http://www.caucho.com diff --git a/extractor/readme.txt b/extractor/readme.txt new file mode 100644 index 0000000000..52adfea07c --- /dev/null +++ b/extractor/readme.txt @@ -0,0 +1,45 @@ +=============================================================================== + ACEGI SECURITY SYSTEM FOR SPRING - EXTRACTOR +=============================================================================== + +*** OVERVIEW *** + +To compile container adapters, it is necessary to have classes from each +container on the classpath. Because container JAR files are usually quite +large, including them in the "with dependencies" release ZIPs would rapidly +bloat the file size. + +Under this solution, the extractor Ant build file takes a container JAR file +and extracts only those classes required by the Acegi Security System for +Spring. The full container JARs will be provided by the relevant container at +deployment time. + +Of course, the classes are extracted from specific versions of the container +JAR files. The resulting "extracted" JAR files (named in the format +container-extracted.jar), include in their manifest file various information +about the source JAR. A copy of the container license is also provided. + +If you run a different container version than those the extracted JARs were +built from, you can create a build.properties that specifies your +source.dir.container. Running "ant extract-container" will then cause your +exact container JAR file to be used to build the extracted JAR, which will be +written to the Acegi Security System for Spring main lib directory. You can +then recompile the Acegi Security System for Spring and you should end up +with compatible versions. + +Two unavoidable issues from doing this include your version might package +required classes differently (so the files referred to by the Ant build file +are incorrect) or your container JAR might implement different inheritance +orders, interface requirements or method signatures than those the Acegi +Security System for Spring was coded for. In such cases, please let us know or +contribute a patch that supports your container version. + +*** THE "SOURCE" DIRECTORY *** + +The "source" directory contains the full container JAR files that the +container-extracted.jar files are created from. We do not include these in the +"with dependencies" releases. If you need these files, please download them +from the container vendor sites (refer to project.properties for URLs) or +checkout the project from CVS. + +$Id$ diff --git a/extractor/source/catalina/LICENSE b/extractor/source/catalina/LICENSE new file mode 100644 index 0000000000..68a22dc936 --- /dev/null +++ b/extractor/source/catalina/LICENSE @@ -0,0 +1,61 @@ +/* ========================================================================= * + * * + * The Apache Software License, Version 1.1 * + * * + * Copyright (c) 1999, 2000 The Apache Software Foundation. * + * All rights reserved. * + * * + * ========================================================================= * + * * + * Redistribution and use in source and binary forms, with or without modi- * + * fication, are permitted provided that the following conditions are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. The end-user documentation included with the redistribution, if any, * + * must include the following acknowlegement: * + * * + * "This product includes software developed by the Apache Software * + * Foundation ." * + * * + * Alternately, this acknowlegement may appear in the software itself, if * + * and wherever such third-party acknowlegements normally appear. * + * * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * + * Foundation" must not be used to endorse or promote products derived * + * from this software without prior written permission. For written * + * permission, please contact . * + * * + * 5. Products derived from this software may not be called "Apache" nor may * + * "Apache" appear in their names without prior written permission of the * + * Apache Software Foundation. * + * * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES * + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * + * THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * + * POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= * + * * + * This software consists of voluntary contributions made by many indivi- * + * duals on behalf of the Apache Software Foundation. For more information * + * on the Apache Software Foundation, please see . * + * * + * ========================================================================= */ + +/* CVS information: $Revision: 1.2 $ $Date: 2003/12/24 19:53:47 $ + * $Source: /home/cvs/jakarta-tomcat-5/LICENSE,v $ + * $Author: markt $ + */ diff --git a/extractor/source/jboss/LICENSE.txt b/extractor/source/jboss/LICENSE.txt new file mode 100644 index 0000000000..3b204400cf --- /dev/null +++ b/extractor/source/jboss/LICENSE.txt @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/extractor/source/jetty/LICENSE.html b/extractor/source/jetty/LICENSE.html new file mode 100644 index 0000000000..0196cc71a8 --- /dev/null +++ b/extractor/source/jetty/LICENSE.html @@ -0,0 +1,159 @@ + + + Jetty License + + + +
Jetty License
+
$Revision$
+ +Preamble:

+ +The intent of this document is to state the conditions under which the +Jetty Package may be copied, such that the Copyright Holder maintains some +semblance of control over the development of the package, while giving the +users of the package the right to use, distribute and make reasonable +modifications to the Package in accordance with the goals and ideals of +the Open Source concept as described at +http://www.opensource.org. +

+It is the intent of this license to allow commercial usage of the Jetty +package, so long as the source code is distributed or suitable visible +credit given or other arrangements made with the copyright holders. + +

Definitions:

+ +

    +
  • "Jetty" refers to the collection of Java classes that are + distributed as a HTTP server with servlet capabilities and + associated utilities.

    + +

  • "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification.

    + +

  • "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder.

    + +

  • "Copyright Holder" is whoever is named in the copyright or + copyrights for the package.
    + Mort Bay Consulting Pty. Ltd. (Australia) is the "Copyright + Holder" for the Jetty package.

    + +

  • "You" is you, if you're thinking about copying or distributing + this Package.

    + +

  • "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.)

    + +

  • "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it.

    +

+ +0. The Jetty Package is Copyright (c) Mort Bay Consulting Pty. Ltd. +(Australia) and others. Individual files in this package may contain +additional copyright notices. The javax.servlet packages are copyright +Sun Microsystems Inc.

+ +1. The Standard Version of the Jetty package is +available from http://jetty.mortbay.org.

+ +2. You may make and distribute verbatim copies of the source form +of the Standard Version of this Package without restriction, provided that +you include this license and all of the original copyright notices +and associated disclaimers.

+ +3. You may make and distribute verbatim copies of the compiled form of the +Standard Version of this Package without restriction, provided that you +include this license.

+ +4. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version.

+ +5. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following:

+ +

+a) Place your modifications in the Public Domain or otherwise make them +Freely Available, such as by posting said modifications to Usenet or +an equivalent medium, or placing the modifications on a major archive +site such as ftp.uu.net, or by allowing the Copyright Holder to include +your modifications in the Standard Version of the Package.

+ +b) Use the modified Package only within your corporation or organization.

+ +c) Rename any non-standard classes so the names do not conflict +with standard classes, which must also be provided, and provide +a separate manual page for each non-standard class that clearly +documents how it differs from the Standard Version.

+ +d) Make other arrangements with the Copyright Holder.

+

+ +6. You may distribute modifications or subsets of this Package in source +code or compiled form, provided that you do at least ONE of the following:

+ +

+a) Distribute this license and all original copyright messages, together +with instructions (in the about dialog, manual page or equivalent) on where +to get the complete Standard Version.

+ +b) Accompany the distribution with the machine-readable source of +the Package with your modifications. The modified package must include +this license and all of the original copyright notices and associated +disclaimers, together with instructions on where to get the complete +Standard Version.

+ +c) Make other arrangements with the Copyright Holder.

+

+ +7. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you meet the other distribution requirements +of this license.

+ +8. Input to or the output produced from the programs of this Package +do not automatically fall under the copyright of this Package, but +belong to whomever generated them, and may be sold commercially, and +may be aggregated with this Package.

+ +9. Any program subroutines supplied by you and linked into this Package +shall not be considered part of this Package.

+ +10. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written +permission.

+ +11. This license may change with each release of a Standard Version of +the Package. You may choose to use the license associated with version +you are using or the license of the latest Standard Version.

+ +12. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ +13. If any superior law implies a warranty, the sole remedy under such shall +be , at the Copyright Holders option either a) return of any price paid or +b) use or reasonable endeavours to repair or replace the software.

+ +14. This license shall be read under the laws of Australia.

+ +

The End
+ +
This license was derived from the Artistic license published +on http://www.opensource.com
+
+ + diff --git a/extractor/source/resin/LICENSE b/extractor/source/resin/LICENSE new file mode 100644 index 0000000000..da8c851005 --- /dev/null +++ b/extractor/source/resin/LICENSE @@ -0,0 +1,65 @@ + Caucho Developer Source License + version 1.1 + +Caucho Technology, Inc. ("Caucho") permits use of the accompanying software +and documentation ("the Software") provided that the conditions of the +Caucho Developer Source License ("the License") are met: + +1. You must not alter or remove any copyright or trademark notices + in the Software. + +2. You may use the Software to develop, evaluate, and demonstrate + applications. + +3. Provided all the following conditions are met, you may use + the Software to deploy an application: + a) You are not paid to use the Software. + b) You are not paying anyone else to use the Software. + +4. Caucho reserves all rights to the Software not explicitly + granted by the License. + +5. Each copy of the Software in source or binary form must include + an unmodified copy of the License in a plain ASCII text file + named LICENSE. + +6. Caucho reserves all rights to its names, trademarks and logos. + In particular, the names "Resin" and "Caucho" are trademarks of + Caucho and may not be used to endorse products derived from + this software. "Resin" and "Caucho" may not appear in + the names of products derived from this software. + +7. If you transmit any improvement or modification of the Software to + Caucho, you agree to assign the copyright of the improvement or + modification to Caucho. + +8. The License will terminate immediately without notice from Caucho + if you fail to comply with any provision of the License. + Upon such termination, you must destroy all copies and + derived works of the Software. You may terminate the License at + any time by destroying all copies and derived works of the Software. + +9. You acknowledge that you are solely responsible for the use you + make of the Software. Accordingly, you agrees to indemnify and + hold Caucho harmless for any demands, claims, or suits by a third party + for loss, damages or expenses (including attorneys' fees) arising out + of, or related to, use of the Software by you or any other + individuals or entities. + +10. The Software is provided "AS IS," without a warranty of any kind. + ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + +11. CAUCHO AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + SUFFERED BY YOU OR ANY THIRD PARTY AS A RESULT OF USING OR DISTRIBUTING + THE SOFTWARE. IN NO EVENT WILL CAUCHO TECHNOLOGY OR ITS LICENSORS BE + LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + INABILITY TO USE THE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + +12. Any action related to the License will be governed by California + law and controlling U.S. federal law. No choice of law rules of + any jurisdiction will apply. diff --git a/hsqldb/acegisecurity.properties b/hsqldb/acegisecurity.properties new file mode 100644 index 0000000000..dde30c4d94 --- /dev/null +++ b/hsqldb/acegisecurity.properties @@ -0,0 +1,16 @@ +#HSQL database +#Wed Mar 10 03:15:01 GMT 2004 +sql.strict_fk=true +readonly=false +sql.strong_fk=true +hsqldb.version=1.7.1 +version=1.7.1 +hsqldb.cache_scale=14 +sql.compare_in_locale=false +sql.month=true +hsqldb.log_size=200 +modified=no +hsqldb.cache_version=1.7.0 +hsqldb.original_version=1.7.1 +hsqldb.compatible_version=1.7.0 +sql.enforce_size=false diff --git a/hsqldb/acegisecurity.script b/hsqldb/acegisecurity.script new file mode 100644 index 0000000000..7719fc0e1c --- /dev/null +++ b/hsqldb/acegisecurity.script @@ -0,0 +1,83 @@ +CREATE TABLE USERS(USERNAME VARCHAR(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR(50) NOT NULL,ENABLED BIT NOT NULL) +CREATE TABLE AUTHORITIES(USERNAME VARCHAR(50) NOT NULL,AUTHORITY VARCHAR(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME)) +CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY) +GRANT ALL ON CLASS "org.hsqldb.Library" TO PUBLIC +GRANT ALL ON CLASS "java.lang.Math" TO PUBLIC +CREATE USER SA PASSWORD "" ADMIN +CREATE ALIAS DAYNAME FOR "org.hsqldb.Library.dayname" +CREATE ALIAS SPACE FOR "org.hsqldb.Library.space" +CREATE ALIAS SUBSTRING FOR "org.hsqldb.Library.substring" +CREATE ALIAS HEXTORAW FOR "org.hsqldb.Library.hexToRaw" +CREATE ALIAS SQRT FOR "java.lang.Math.sqrt" +CREATE ALIAS ABS FOR "org.hsqldb.Library.abs" +CREATE ALIAS POWER FOR "java.lang.Math.pow" +CREATE ALIAS CHAR FOR "org.hsqldb.Library.character" +CREATE ALIAS CONCAT FOR "org.hsqldb.Library.concat" +CREATE ALIAS PI FOR "org.hsqldb.Library.pi" +CREATE ALIAS RAWTOHEX FOR "org.hsqldb.Library.rawToHex" +CREATE ALIAS SECOND FOR "org.hsqldb.Library.second" +CREATE ALIAS TRUNCATE FOR "org.hsqldb.Library.truncate" +CREATE ALIAS MONTH FOR "org.hsqldb.Library.month" +CREATE ALIAS LOWER FOR "org.hsqldb.Library.lcase" +CREATE ALIAS ATAN2 FOR "java.lang.Math.atan2" +CREATE ALIAS REPEAT FOR "org.hsqldb.Library.repeat" +CREATE ALIAS DAYOFMONTH FOR "org.hsqldb.Library.dayofmonth" +CREATE ALIAS TAN FOR "java.lang.Math.tan" +CREATE ALIAS RADIANS FOR "java.lang.Math.toRadians" +CREATE ALIAS FLOOR FOR "java.lang.Math.floor" +CREATE ALIAS NOW FOR "org.hsqldb.Library.now" +CREATE ALIAS ACOS FOR "java.lang.Math.acos" +CREATE ALIAS DAYOFWEEK FOR "org.hsqldb.Library.dayofweek" +CREATE ALIAS CEILING FOR "java.lang.Math.ceil" +CREATE ALIAS DAYOFYEAR FOR "org.hsqldb.Library.dayofyear" +CREATE ALIAS LCASE FOR "org.hsqldb.Library.lcase" +CREATE ALIAS WEEK FOR "org.hsqldb.Library.week" +CREATE ALIAS SOUNDEX FOR "org.hsqldb.Library.soundex" +CREATE ALIAS ASIN FOR "java.lang.Math.asin" +CREATE ALIAS LOCATE FOR "org.hsqldb.Library.locate" +CREATE ALIAS EXP FOR "java.lang.Math.exp" +CREATE ALIAS MONTHNAME FOR "org.hsqldb.Library.monthname" +CREATE ALIAS YEAR FOR "org.hsqldb.Library.year" +CREATE ALIAS LEFT FOR "org.hsqldb.Library.left" +CREATE ALIAS ROUNDMAGIC FOR "org.hsqldb.Library.roundMagic" +CREATE ALIAS BITOR FOR "org.hsqldb.Library.bitor" +CREATE ALIAS LTRIM FOR "org.hsqldb.Library.ltrim" +CREATE ALIAS COT FOR "org.hsqldb.Library.cot" +CREATE ALIAS COS FOR "java.lang.Math.cos" +CREATE ALIAS MOD FOR "org.hsqldb.Library.mod" +CREATE ALIAS SIGN FOR "org.hsqldb.Library.sign" +CREATE ALIAS DEGREES FOR "java.lang.Math.toDegrees" +CREATE ALIAS LOG FOR "java.lang.Math.log" +CREATE ALIAS SIN FOR "java.lang.Math.sin" +CREATE ALIAS CURTIME FOR "org.hsqldb.Library.curtime" +CREATE ALIAS DIFFERENCE FOR "org.hsqldb.Library.difference" +CREATE ALIAS INSERT FOR "org.hsqldb.Library.insert" +CREATE ALIAS SUBSTR FOR "org.hsqldb.Library.substring" +CREATE ALIAS DATABASE FOR "org.hsqldb.Library.database" +CREATE ALIAS MINUTE FOR "org.hsqldb.Library.minute" +CREATE ALIAS HOUR FOR "org.hsqldb.Library.hour" +CREATE ALIAS IDENTITY FOR "org.hsqldb.Library.identity" +CREATE ALIAS QUARTER FOR "org.hsqldb.Library.quarter" +CREATE ALIAS CURDATE FOR "org.hsqldb.Library.curdate" +CREATE ALIAS BITAND FOR "org.hsqldb.Library.bitand" +CREATE ALIAS USER FOR "org.hsqldb.Library.user" +CREATE ALIAS UCASE FOR "org.hsqldb.Library.ucase" +CREATE ALIAS RTRIM FOR "org.hsqldb.Library.rtrim" +CREATE ALIAS LOG10 FOR "org.hsqldb.Library.log10" +CREATE ALIAS RIGHT FOR "org.hsqldb.Library.right" +CREATE ALIAS ATAN FOR "java.lang.Math.atan" +CREATE ALIAS UPPER FOR "org.hsqldb.Library.ucase" +CREATE ALIAS ASCII FOR "org.hsqldb.Library.ascii" +CREATE ALIAS RAND FOR "java.lang.Math.random" +CREATE ALIAS LENGTH FOR "org.hsqldb.Library.length" +CREATE ALIAS ROUND FOR "org.hsqldb.Library.round" +CREATE ALIAS REPLACE FOR "org.hsqldb.Library.replace" +INSERT INTO USERS VALUES('dianne','emu',true) +INSERT INTO USERS VALUES('marissa','koala',true) +INSERT INTO USERS VALUES('peter','opal',false) +INSERT INTO USERS VALUES('scott','wombat',true) +INSERT INTO AUTHORITIES VALUES('marissa','ROLE_TELLER') +INSERT INTO AUTHORITIES VALUES('marissa','ROLE_SUPERVISOR') +INSERT INTO AUTHORITIES VALUES('dianne','ROLE_TELLER') +INSERT INTO AUTHORITIES VALUES('scott','ROLE_TELLER') +INSERT INTO AUTHORITIES VALUES('peter','ROLE_TELLER') diff --git a/hsqldb/dbinit.txt b/hsqldb/dbinit.txt new file mode 100644 index 0000000000..c24184dd71 --- /dev/null +++ b/hsqldb/dbinit.txt @@ -0,0 +1,26 @@ +--- $Id$ + +CREATE TABLE users ( + username VARCHAR(50) NOT NULL PRIMARY KEY, + password VARCHAR(50) NOT NULL, + enabled BIT NOT NULL +); + +CREATE TABLE authorities ( + username VARCHAR(50) NOT NULL, + authority VARCHAR(50) NOT NULL +); +CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority ); + +ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users(username); + +INSERT INTO users VALUES ('marissa', 'koala', true); +INSERT INTO users VALUES ('dianne', 'emu', true); +INSERT INTO users VALUES ('scott', 'wombat', true); +INSERT INTO users VALUES ('peter', 'opal', false); + +INSERT INTO authorities VALUES ('marissa', 'ROLE_TELLER'); +INSERT INTO authorities VALUES ('marissa', 'ROLE_SUPERVISOR'); +INSERT INTO authorities VALUES ('dianne', 'ROLE_TELLER'); +INSERT INTO authorities VALUES ('scott', 'ROLE_TELLER'); +INSERT INTO authorities VALUES ('peter', 'ROLE_TELLER'); diff --git a/hsqldb/manager.bat b/hsqldb/manager.bat new file mode 100644 index 0000000000..28e6c0387c --- /dev/null +++ b/hsqldb/manager.bat @@ -0,0 +1,2 @@ +java -classpath ..\lib\hsqldb\hsqldb.jar org.hsqldb.util.DatabaseManager + diff --git a/hsqldb/manager.sh b/hsqldb/manager.sh new file mode 100644 index 0000000000..978addb31a --- /dev/null +++ b/hsqldb/manager.sh @@ -0,0 +1 @@ +java -cp ../lib/hsqldb/hsqldb.jar org.hsqldb.util.DatabaseManager diff --git a/hsqldb/server.bat b/hsqldb/server.bat new file mode 100644 index 0000000000..c253bad03d --- /dev/null +++ b/hsqldb/server.bat @@ -0,0 +1 @@ +java -classpath ..\lib\hsqldb\hsqldb.jar org.hsqldb.Server -database acegisecurity diff --git a/hsqldb/server.sh b/hsqldb/server.sh new file mode 100644 index 0000000000..4faf9b4e06 --- /dev/null +++ b/hsqldb/server.sh @@ -0,0 +1 @@ +java -classpath ../lib/hsqldb/hsqldb.jar org.hsqldb.Server -database acegisecurity diff --git a/integration-test/.cvsignore b/integration-test/.cvsignore new file mode 100644 index 0000000000..6b4f97312b --- /dev/null +++ b/integration-test/.cvsignore @@ -0,0 +1,6 @@ +classes +reports +temporary +containers +build.properties + diff --git a/integration-test/build.xml b/integration-test/build.xml new file mode 100644 index 0000000000..d5ba87b6ac --- /dev/null +++ b/integration-test/build.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/integration-test/container-configs/catalina-5.0.19/server.xml b/integration-test/container-configs/catalina-5.0.19/server.xml new file mode 100644 index 0000000000..6bd555f8bc --- /dev/null +++ b/integration-test/container-configs/catalina-5.0.19/server.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + factory + org.apache.catalina.users.MemoryUserDatabaseFactory + + + pathname + conf/tomcat-users.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/integration-test/container-configs/jboss-3.2.3/login-config.xml b/integration-test/container-configs/jboss-3.2.3/login-config.xml new file mode 100644 index 0000000000..c3f41a6034 --- /dev/null +++ b/integration-test/container-configs/jboss-3.2.3/login-config.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + guest + jboss.mq:service=StateManager + + + + + + + + acegisecurity.xml + my_password + + + + + + + + + sa + sa + + jboss.jca:service=LocalTxCM,name=DefaultDS + + + + + + + + sysdba + sysdba + masterkey + jboss.jca:service=XaTxCM,name=FirebirdDS + + + + + + + + guest + guest + guest + jboss.jca:service=TxCM,name=JmsXA + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/integration-test/container-configs/jetty-4.2.18/jetty.xml b/integration-test/container-configs/jetty-4.2.18/jetty.xml new file mode 100644 index 0000000000..82950aa790 --- /dev/null +++ b/integration-test/container-configs/jetty-4.2.18/jetty.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + 5 + 50 + 30000 + 1000 + 8443 + 8443 + main + + + + + + + + + /logs/yyyy_mm_dd.jetty.log + 90 + true + true + true + false + false + GMT + + + + + + + + + + + + + + + + + + root + + + /webapps/ + /etc/webdefault.xml + true + + + + + + 2000 + false + + + + + Spring Powered Realm + my_password + /etc/acegisecurity.xml + + + + + diff --git a/integration-test/lib/LICENSE b/integration-test/lib/LICENSE new file mode 100644 index 0000000000..f5695ed513 --- /dev/null +++ b/integration-test/lib/LICENSE @@ -0,0 +1,4 @@ +All of the JARs included in this lib directory were obtained from the +HttpUnit distribution archive. See http://httpunit.sourceforge.net. + +$Id$ diff --git a/integration-test/project.properties b/integration-test/project.properties new file mode 100644 index 0000000000..348db888c3 --- /dev/null +++ b/integration-test/project.properties @@ -0,0 +1,27 @@ +# Ant properties for running the integration test. + +# Values in this file will be overriden by any values with the same name +# in the user-created build.properties file. + +# $Id$ + +name=acegi-security-integration-tests + +tmp.dir=${basedir}/temporary +httpunit.lib.dir=${basedir}/lib +containers.dir=${basedir}/containers +config.dir=${basedir}/container-configs + +lib.dir=${basedir}/../lib +dist.lib.dir=${basedir}/../dist +contacts.war=${basedir}/../samples/contacts/dist/contacts.war + +acegisecurity.xml=../src/net/sf/acegisecurity/adapters/acegisecurity.xml +jalopy.xml=${basedir}/../jalopy.xml + +src.dir=src +build.dir=classes +reports.dir=reports + +test.includes=**/*TestSuite.class **/*Tests.class +test.excludes=**/Abstract* diff --git a/integration-test/readme.txt b/integration-test/readme.txt new file mode 100644 index 0000000000..26ed6cc686 --- /dev/null +++ b/integration-test/readme.txt @@ -0,0 +1,24 @@ +=============================================================================== + ACEGI SECURITY SYSTEM FOR SPRING - INTEGRATION TESTS +=============================================================================== + +This directory allows execution of "in container" integration tests. To run +the tests, the original distribution files for various containers are required +to be placed into the containers directory. These are not included in CVS or +ZIP releases due to their large size. + +To execute these tests: + +1. The following files should be placed into the containers directory: + + Jetty-4.2.18-all.zip (see http://mortbay.jetty.org) + jakarta-tomcat-5-0.19.zip (see http://jakarta.apache.org/tomcat) + jboss-3.2.3.zip (see http://www.jboss.org) + +2. Shutdown any container or service bound to port 8080. + +3. Run "ant tests" (you can safely ignore the console output). + +4. Review the reports directory and confirm each container passed all tests. + +$Id$ diff --git a/integration-test/src/net/sf/acegisecurity/integrationtests/web/ContactsWarTests.java b/integration-test/src/net/sf/acegisecurity/integrationtests/web/ContactsWarTests.java new file mode 100644 index 0000000000..95eaa4c7ad --- /dev/null +++ b/integration-test/src/net/sf/acegisecurity/integrationtests/web/ContactsWarTests.java @@ -0,0 +1,271 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package net.sf.acegisecurity.integrationtests.web; + +import com.meterware.httpunit.GetMethodWebRequest; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebForm; +import com.meterware.httpunit.WebLink; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + +import junit.framework.TestCase; + +import java.net.URL; + + +/** + * Tests the Contacts sample application and container integration from a HTTP + * user's perspective. + * + *

+ * NB: Assumes a default container configuration concerning the usernames and + * passwords in acegisecurity.xml. Also assumes default + * configuration in terms of password and username case sensitivity. + * Importantly, the Contacts application is expected to be started "clean", in + * that all default contacts data is present, without any additional data. + * This means it is necessary to restart the Contacts application between + * successive test runs. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class ContactsWarTests extends TestCase { + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ContactsWarTests.class); + } + + public void testHelloPageAccessible() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse response = conversation.getResponse(request); + assertEquals("Contacts Security Demo", response.getTitle()); + assertEquals(2, response.getLinks().length); // debug and manage links + assertTrue(response.getText().lastIndexOf("sample.contact.Contact@") != -1); + } + + public void testLoginNameCaseSensitive() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink debugLink = helloPage.getLinkWith("Debug"); + WebResponse loginPage = debugLink.click(); + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "mArIsSA"); + loginForm.setParameter("j_password", "koala"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertTrue(loginOutcome.getText().lastIndexOf("SUCCESS! Your container adapter appears to be properly configured!") != -1); + } + + public void testLoginPasswordCaseSensitive() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink debugLink = helloPage.getLinkWith("Debug"); + WebResponse loginPage = debugLink.click(); + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "dianne"); + loginForm.setParameter("j_password", "EmU"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertEquals("Login", loginOutcome.getTitle()); + } + + public void testLoginSuccess() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink debugLink = helloPage.getLinkWith("Debug"); + WebResponse loginPage = debugLink.click(); + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "marissa"); + loginForm.setParameter("j_password", "koala"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertTrue(loginOutcome.getText().lastIndexOf("SUCCESS! Your container adapter appears to be properly configured!") != -1); + } + + public void testLoginUnknownUsername() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink debugLink = helloPage.getLinkWith("Debug"); + WebResponse loginPage = debugLink.click(); + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "angella"); + loginForm.setParameter("j_password", "echidna"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertEquals("Login", loginOutcome.getTitle()); + } + + public void testSessionAsMarissa() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink manageLink = helloPage.getLinkWith("Manage"); + WebResponse loginPage = manageLink.click(); + manageLink = null; + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "marissa"); + loginForm.setParameter("j_password", "koala"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertEquals("Your Contacts", loginOutcome.getTitle()); + assertTrue(loginOutcome.getText().lastIndexOf("marissa's Contacts") != -1); + assertEquals(4, loginOutcome.getTables()[0].getRowCount()); // 3 contacts + header + assertEquals(5, loginOutcome.getLinks().length); // 3 contacts + add + logoff + + WebLink addLink = loginOutcome.getLinkWith("Add"); + loginOutcome = null; + + WebResponse addPage = addLink.click(); + WebForm addForm = addPage.getForms()[0]; + addPage = null; + + addForm.setParameter("name", ""); + addForm.setParameter("email", ""); + + WebResponse addOutcomeFail = conversation.getResponse(addForm + .getRequest("execute")); + + assertEquals(new URL("http://localhost:8080/contacts/secure/add.htm"), + addOutcomeFail.getURL()); + assertTrue(addOutcomeFail.getText().lastIndexOf("Please fix all errors!") != -1); + addOutcomeFail = null; + + addForm.setParameter("name", "somebody"); + addForm.setParameter("email", "them@somewhere.com"); + + WebResponse addOutcomeSuccess = conversation.getResponse(addForm + .getRequest("execute")); + + assertEquals("Your Contacts", addOutcomeSuccess.getTitle()); + assertTrue(addOutcomeSuccess.getText().lastIndexOf("marissa's Contacts") != -1); + assertEquals(5, addOutcomeSuccess.getTables()[0].getRowCount()); // 4 contacts + header + assertEquals(6, addOutcomeSuccess.getLinks().length); // 4 contacts + add + logoff + + WebLink logout = addOutcomeSuccess.getLinkWith("Logoff"); + addOutcomeSuccess = null; + + WebResponse loggedOut = logout.click(); + assertEquals("Contacts Security Demo", loggedOut.getTitle()); + + WebLink debugLink = loggedOut.getLinkWith("Debug"); + loggedOut = null; + + WebResponse loginAgainPage = debugLink.click(); + assertEquals("Login", loginAgainPage.getTitle()); + } + + public void testSessionAsScott() throws Exception { + WebConversation conversation = new WebConversation(); + WebRequest request = new GetMethodWebRequest( + "http://localhost:8080/contacts"); + + WebResponse helloPage = conversation.getResponse(request); + WebLink manageLink = helloPage.getLinkWith("Manage"); + WebResponse loginPage = manageLink.click(); + manageLink = null; + assertEquals(1, loginPage.getForms()[0].getSubmitButtons().length); + + WebForm loginForm = loginPage.getForms()[0]; + loginPage = null; + + loginForm.setParameter("j_username", "scott"); + loginForm.setParameter("j_password", "wombat"); + + WebResponse loginOutcome = conversation.getResponse(loginForm + .getRequest("submit")); + + assertEquals("Your Contacts", loginOutcome.getTitle()); + assertTrue(loginOutcome.getText().lastIndexOf("scott's Contacts") != -1); + assertEquals(3, loginOutcome.getTables()[0].getRowCount()); // 2 contacts + header + assertEquals(2, loginOutcome.getLinks().length); // add + logoff only + + WebLink addLink = loginOutcome.getLinkWith("Add"); + loginOutcome = null; + + WebResponse addPage = addLink.click(); + WebForm addForm = addPage.getForms()[0]; + addPage = null; + + addForm.setParameter("name", "somebody"); + addForm.setParameter("email", "them@somewhere.com"); + + WebResponse addOutcomeSuccess = conversation.getResponse(addForm + .getRequest("execute")); + + assertEquals("Your Contacts", addOutcomeSuccess.getTitle()); + assertTrue(addOutcomeSuccess.getText().lastIndexOf("scott's Contacts") != -1); + assertEquals(4, addOutcomeSuccess.getTables()[0].getRowCount()); // 3 contacts + header + assertEquals(2, addOutcomeSuccess.getLinks().length); // add + logoff only + + WebLink logout = addOutcomeSuccess.getLinkWith("Logoff"); + addOutcomeSuccess = null; + + WebResponse loggedOut = logout.click(); + assertEquals("Contacts Security Demo", loggedOut.getTitle()); + + WebLink debugLink = loggedOut.getLinkWith("Debug"); + loggedOut = null; + + WebResponse loginAgainPage = debugLink.click(); + assertEquals("Login", loginAgainPage.getTitle()); + } +} diff --git a/jalopy.xml b/jalopy.xml new file mode 100644 index 0000000000..6255338800 --- /dev/null +++ b/jalopy.xml @@ -0,0 +1,378 @@ + + + + + 14 + + + + + true + + + [A-Z][a-zA-Z0-9]+ + [A-Z][a-zA-Z0-9]+ + + + [a-z][\w]+ + [a-z][\w]+ + [a-zA-Z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-zA-Z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-zA-Z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-zA-Z][\w]+ + + [A-Z][a-zA-Z0-9]+ + \w+ + + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + [a-z][\w]+ + + [a-z]+(?:\.[a-z]+)* + + [a-z][\w]+ + [a-z][\w]+ + + [a-z][\w]* + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + + + + 6 + + + + 30000 + 30000 + 30000 + 30000 + 30000 + 30000 + + true + + + 1 + + + + true + false + true + false + false + + + bak + 0 + + + + 1 + 0 + 1 + 0 +
1
+
1
+ 1 + 2 + 1 + 1 +
+ + 1 + 0 + 1 + + 1 + 1 + 1 + + 1 + 1 +
0
+
0
+
+ 1 +
+ + + true + false + + + true + true + true + true + + + true + false + false + false + false + + + false + false + + + + true + true + + + + true + + + + false + true + true + + true + + 1 + 0 + 0 + 0 + + true + + + @@SecurityConfig + + + + */ + * @throws $exceptionType$ DOCUMENT ME! + * @param $paramType$ DOCUMENT ME! + * @return DOCUMENT ME! + /**| * DOCUMENT ME! + + + + + false + false + false + + + = + true + false + + Inner Classes + Constructors + Instance fields + Instance initializers + Inner Interfaces + Methods + Static fields/initializers + + + + +
+ + 0 + false +
+
+ Created on|To change the template for this generated|Apache Software License + 0 + /*| * The Acegi Security System for Spring is published under the terms| * of the Apache Software License.| *| * Visit http://acegisecurity.sourceforge.net for further details.| */ + true +
+ + disabled + + + + 3 + *:0|gnu:2|java:2|javax:2 + + disabled + true + + + false + + false + false + + false + + + false + + + 1 + 1 + 0 + 1 + 4 + 55 + -1 + 4 + -1 + 0 + 8 + -1 + 1 + + + false + false + + + + false + false + true + true + true + false + + + + true + true + true + true + true + static|field|initializer|constructor|method|interface|class + true + + + false + public|protected|private|abstract|static|final|synchronized|transient|volatile|native|strictfp + + + + + true + true + true + + + true + false + false + false + + false + + + false + false + true + + + + false + false + + true + true + true + true + true + true + + false + false + + + + + + 2147483647 + false + false + false + + false + + false + false + + false + + + false + false + false + false + + + false + false + false + + + + true + true + 80 + + + + false + false + false + + false + false + false + + + + false + + false + + +
+
+ diff --git a/lib/LICENSE b/lib/LICENSE new file mode 100644 index 0000000000..7915358960 --- /dev/null +++ b/lib/LICENSE @@ -0,0 +1,5 @@ +Unless an alternate license file is provided, all of the included lib JARs were +obtained from the Spring Framework "with dependencies" ZIP file. + +$Id$ + diff --git a/lib/extracted/catalina/LICENSE b/lib/extracted/catalina/LICENSE new file mode 100644 index 0000000000..68a22dc936 --- /dev/null +++ b/lib/extracted/catalina/LICENSE @@ -0,0 +1,61 @@ +/* ========================================================================= * + * * + * The Apache Software License, Version 1.1 * + * * + * Copyright (c) 1999, 2000 The Apache Software Foundation. * + * All rights reserved. * + * * + * ========================================================================= * + * * + * Redistribution and use in source and binary forms, with or without modi- * + * fication, are permitted provided that the following conditions are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. The end-user documentation included with the redistribution, if any, * + * must include the following acknowlegement: * + * * + * "This product includes software developed by the Apache Software * + * Foundation ." * + * * + * Alternately, this acknowlegement may appear in the software itself, if * + * and wherever such third-party acknowlegements normally appear. * + * * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * + * Foundation" must not be used to endorse or promote products derived * + * from this software without prior written permission. For written * + * permission, please contact . * + * * + * 5. Products derived from this software may not be called "Apache" nor may * + * "Apache" appear in their names without prior written permission of the * + * Apache Software Foundation. * + * * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES * + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * + * THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY * + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * + * POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= * + * * + * This software consists of voluntary contributions made by many indivi- * + * duals on behalf of the Apache Software Foundation. For more information * + * on the Apache Software Foundation, please see . * + * * + * ========================================================================= */ + +/* CVS information: $Revision: 1.2 $ $Date: 2003/12/24 19:53:47 $ + * $Source: /home/cvs/jakarta-tomcat-5/LICENSE,v $ + * $Author: markt $ + */ diff --git a/lib/extracted/jboss/LICENSE.txt b/lib/extracted/jboss/LICENSE.txt new file mode 100644 index 0000000000..3b204400cf --- /dev/null +++ b/lib/extracted/jboss/LICENSE.txt @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/lib/extracted/jetty/LICENSE.html b/lib/extracted/jetty/LICENSE.html new file mode 100644 index 0000000000..0196cc71a8 --- /dev/null +++ b/lib/extracted/jetty/LICENSE.html @@ -0,0 +1,159 @@ + + + Jetty License + + + +
Jetty License
+
$Revision$
+ +Preamble:

+ +The intent of this document is to state the conditions under which the +Jetty Package may be copied, such that the Copyright Holder maintains some +semblance of control over the development of the package, while giving the +users of the package the right to use, distribute and make reasonable +modifications to the Package in accordance with the goals and ideals of +the Open Source concept as described at +http://www.opensource.org. +

+It is the intent of this license to allow commercial usage of the Jetty +package, so long as the source code is distributed or suitable visible +credit given or other arrangements made with the copyright holders. + +

Definitions:

+ +

    +
  • "Jetty" refers to the collection of Java classes that are + distributed as a HTTP server with servlet capabilities and + associated utilities.

    + +

  • "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification.

    + +

  • "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder.

    + +

  • "Copyright Holder" is whoever is named in the copyright or + copyrights for the package.
    + Mort Bay Consulting Pty. Ltd. (Australia) is the "Copyright + Holder" for the Jetty package.

    + +

  • "You" is you, if you're thinking about copying or distributing + this Package.

    + +

  • "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.)

    + +

  • "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it.

    +

+ +0. The Jetty Package is Copyright (c) Mort Bay Consulting Pty. Ltd. +(Australia) and others. Individual files in this package may contain +additional copyright notices. The javax.servlet packages are copyright +Sun Microsystems Inc.

+ +1. The Standard Version of the Jetty package is +available from http://jetty.mortbay.org.

+ +2. You may make and distribute verbatim copies of the source form +of the Standard Version of this Package without restriction, provided that +you include this license and all of the original copyright notices +and associated disclaimers.

+ +3. You may make and distribute verbatim copies of the compiled form of the +Standard Version of this Package without restriction, provided that you +include this license.

+ +4. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version.

+ +5. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following:

+ +

+a) Place your modifications in the Public Domain or otherwise make them +Freely Available, such as by posting said modifications to Usenet or +an equivalent medium, or placing the modifications on a major archive +site such as ftp.uu.net, or by allowing the Copyright Holder to include +your modifications in the Standard Version of the Package.

+ +b) Use the modified Package only within your corporation or organization.

+ +c) Rename any non-standard classes so the names do not conflict +with standard classes, which must also be provided, and provide +a separate manual page for each non-standard class that clearly +documents how it differs from the Standard Version.

+ +d) Make other arrangements with the Copyright Holder.

+

+ +6. You may distribute modifications or subsets of this Package in source +code or compiled form, provided that you do at least ONE of the following:

+ +

+a) Distribute this license and all original copyright messages, together +with instructions (in the about dialog, manual page or equivalent) on where +to get the complete Standard Version.

+ +b) Accompany the distribution with the machine-readable source of +the Package with your modifications. The modified package must include +this license and all of the original copyright notices and associated +disclaimers, together with instructions on where to get the complete +Standard Version.

+ +c) Make other arrangements with the Copyright Holder.

+

+ +7. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you meet the other distribution requirements +of this license.

+ +8. Input to or the output produced from the programs of this Package +do not automatically fall under the copyright of this Package, but +belong to whomever generated them, and may be sold commercially, and +may be aggregated with this Package.

+ +9. Any program subroutines supplied by you and linked into this Package +shall not be considered part of this Package.

+ +10. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written +permission.

+ +11. This license may change with each release of a Standard Version of +the Package. You may choose to use the license associated with version +you are using or the license of the latest Standard Version.

+ +12. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ +13. If any superior law implies a warranty, the sole remedy under such shall +be , at the Copyright Holders option either a) return of any price paid or +b) use or reasonable endeavours to repair or replace the software.

+ +14. This license shall be read under the laws of Australia.

+ +

The End
+ +
This license was derived from the Artistic license published +on http://www.opensource.com
+
+ + diff --git a/lib/extracted/resin/LICENSE b/lib/extracted/resin/LICENSE new file mode 100644 index 0000000000..da8c851005 --- /dev/null +++ b/lib/extracted/resin/LICENSE @@ -0,0 +1,65 @@ + Caucho Developer Source License + version 1.1 + +Caucho Technology, Inc. ("Caucho") permits use of the accompanying software +and documentation ("the Software") provided that the conditions of the +Caucho Developer Source License ("the License") are met: + +1. You must not alter or remove any copyright or trademark notices + in the Software. + +2. You may use the Software to develop, evaluate, and demonstrate + applications. + +3. Provided all the following conditions are met, you may use + the Software to deploy an application: + a) You are not paid to use the Software. + b) You are not paying anyone else to use the Software. + +4. Caucho reserves all rights to the Software not explicitly + granted by the License. + +5. Each copy of the Software in source or binary form must include + an unmodified copy of the License in a plain ASCII text file + named LICENSE. + +6. Caucho reserves all rights to its names, trademarks and logos. + In particular, the names "Resin" and "Caucho" are trademarks of + Caucho and may not be used to endorse products derived from + this software. "Resin" and "Caucho" may not appear in + the names of products derived from this software. + +7. If you transmit any improvement or modification of the Software to + Caucho, you agree to assign the copyright of the improvement or + modification to Caucho. + +8. The License will terminate immediately without notice from Caucho + if you fail to comply with any provision of the License. + Upon such termination, you must destroy all copies and + derived works of the Software. You may terminate the License at + any time by destroying all copies and derived works of the Software. + +9. You acknowledge that you are solely responsible for the use you + make of the Software. Accordingly, you agrees to indemnify and + hold Caucho harmless for any demands, claims, or suits by a third party + for loss, damages or expenses (including attorneys' fees) arising out + of, or related to, use of the Software by you or any other + individuals or entities. + +10. The Software is provided "AS IS," without a warranty of any kind. + ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + +11. CAUCHO AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + SUFFERED BY YOU OR ANY THIRD PARTY AS A RESULT OF USING OR DISTRIBUTING + THE SOFTWARE. IN NO EVENT WILL CAUCHO TECHNOLOGY OR ITS LICENSORS BE + LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + INABILITY TO USE THE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + +12. Any action related to the License will be governed by California + law and controlling U.S. federal law. No choice of law rules of + any jurisdiction will apply. diff --git a/lib/jalopy/license-antlr.html b/lib/jalopy/license-antlr.html new file mode 100644 index 0000000000..5d486a3eeb --- /dev/null +++ b/lib/jalopy/license-antlr.html @@ -0,0 +1,47 @@ + + + + + Appendix C. ANTLR SOFTWARE RIGHTS + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix C. ANTLR SOFTWARE RIGHTS

+ANTLR 1989-2000 Developed by jGuru.com (MageLang Institute), +http://www.ANTLR.org and +http://www.jGuru.com +

+We reserve no legal rights to the ANTLR -- it is fully in the +public domain. An individual or company may do whatever +they wish with source code distributed with ANTLR or the +code generated by ANTLR, including the incorporation of +ANTLR, or its output, into commerical software. +

+We encourage users to develop software with ANTLR. However, +we do ask that credit is given to us for developing +ANTLR. By "credit", we mean that if you use ANTLR or +incorporate any source code into one of your programs +(commercial product, research project, or otherwise) that +you acknowledge this fact somewhere in the documentation, +research report, etc... If you like ANTLR and have +developed a nice tool with the output, please mention that +you developed it using ANTLR. In addition, we ask that the +headers remain intact in our source code. As long as these +guidelines are kept, we expect to continue enhancing this +system and expect to make other tools available as they are +completed. +

+The primary ANTLR guy: +

+Terence Parr +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-apache.html b/lib/jalopy/license-apache.html new file mode 100644 index 0000000000..3097a507c1 --- /dev/null +++ b/lib/jalopy/license-apache.html @@ -0,0 +1,62 @@ + + + + + Appendix D. The Apache Software License, Version 1.1 + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix D. The Apache Software License, Version 1.1

+Copyright (C) 1999 The Apache Software Foundation. All rights reserved. +

+Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +

  1. +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +

  2. +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +

  3. +The end-user documentation included with the redistribution, if any, must +include the following acknowledgment: "This product includes software +developed by the Apache Software Foundation (http://www.apache.org/)." +Alternately, this acknowledgment may appear in the software itself, if +and wherever such third-party acknowledgments normally appear. +

  4. +The names "Ant" and "Apache Software Foundation" must not be used to +endorse or promote products derived from this software without prior +written permission. For written permission, please contact +apache@apache.org. +

  5. +Products derived from this software may not be called "Apache", nor may +"Apache" appear in their name, without prior written permission of the +Apache Software Foundation. +

+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +

+ This software consists of voluntary contributions made by many individuals + on behalf of the Apache Software Foundation. For more information on the + Apache Software Foundation, please see + http://www.apache.org. +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-bsd.html b/lib/jalopy/license-bsd.html new file mode 100644 index 0000000000..f6ac77669c --- /dev/null +++ b/lib/jalopy/license-bsd.html @@ -0,0 +1,33 @@ + + + + + Appendix B. The Jalopy BSD License + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix B. The Jalopy BSD License

+Copyright (c) 2001-2002, Marco Hunsicker. All rights reserved. +

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +

  • +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +

  • +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +

  • +Neither the name of the Jalopy Group nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-common-public.html b/lib/jalopy/license-common-public.html new file mode 100644 index 0000000000..e79140edce --- /dev/null +++ b/lib/jalopy/license-common-public.html @@ -0,0 +1,81 @@ + + + + + Appendix G. Common Public License Version 1.0 + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix G. Common Public License Version 1.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

+"Contribution" means: +

+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and +

b) in the case of each subsequent Contributor:

i) changes to the Program, and

ii) additions to the Program;

+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. +

+"Contributor" means any person or entity that distributes the Program. +

+"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. +

+"Program" means the Contributions distributed in accordance with this Agreement. +

+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. +

2. GRANT OF RIGHTS

+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. +

+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +

+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +

+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +

3. REQUIREMENTS

+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +

+a) it complies with the terms and conditions of this Agreement; and +

b) its license agreement:

+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +

+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +

+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and +

+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. +

+When the Program is made available in source code form: +

+a) it must be made available under this Agreement; and +

+b) a copy of this Agreement must be included with each copy of the Program. +

+Contributors may not remove or alter any copyright notices contained within the Program. +

+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. +

4. COMMERCIAL DISTRIBUTION

+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. +

+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. +

5. NO WARRANTY

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. +

6. DISCLAIMER OF LIABILITY

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +

7. GENERAL

+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +

+If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. +

+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. +

+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. +

+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-gnu-doc.html b/lib/jalopy/license-gnu-doc.html new file mode 100644 index 0000000000..1232403ca1 --- /dev/null +++ b/lib/jalopy/license-gnu-doc.html @@ -0,0 +1,374 @@ + + + + + Appendix F. GNU Free Documentation License Version 1.1, March 2000 + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix F. GNU Free Documentation License Version 1.1, March 2000

+ Copyright (C) 2000 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +

+ Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. +

+0. PREAMBLE +

+The purpose of this License is to make a manual, textbook, or other +written document "free" in the sense of freedom: to assure everyone +the effective freedom to copy and redistribute it, with or without +modifying it, either commercially or noncommercially. Secondarily, +this License preserves for the author and publisher a way to get +credit for their work, while not being considered responsible for +modifications made by others. +

+This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. +

+We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. +

+1. APPLICABILITY AND DEFINITIONS +

+This License applies to any manual or other work that contains a +notice placed by the copyright holder saying it can be distributed +under the terms of this License. The "Document", below, refers to any +such manual or work. Any member of the public is a licensee, and is +addressed as "you". +

+A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. +

+A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (For example, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. +

+The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. +

+The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. +

+A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, whose contents can be viewed and edited directly and +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup has been designed to thwart or discourage +subsequent modification by readers is not Transparent. A copy that is +not "Transparent" is called "Opaque". +

+Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML designed for human modification. Opaque formats include +PostScript, PDF, proprietary formats that can be read and edited only +by proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML produced by some word processors for output +purposes only. +

+The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. +

+2. VERBATIM COPYING +

+You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. +

+You may also lend copies, under the same conditions stated above, and +you may publicly display copies. +

+3. COPYING IN QUANTITY +

+If you publish printed copies of the Document numbering more than 100, +and the Document's license notice requires Cover Texts, you must enclose +the copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. +

+If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. +

+If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a publicly-accessible computer-network location containing a complete +Transparent copy of the Document, free of added material, which the +general network-using public has access to download anonymously at no +charge using public-standard network protocols. If you use the latter +option, you must take reasonably prudent steps, when you begin +distribution of Opaque copies in quantity, to ensure that this +Transparent copy will remain thus accessible at the stated location +until at least one year after the last time you distribute an Opaque +copy (directly or through your agents or retailers) of that edition to +the public. +

+It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. +

+4. MODIFICATIONS +

+You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: +

  1. + Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +

  2. + List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has less than five). +

  3. + State on the Title page the name of the publisher of the + Modified Version, as the publisher. +

  4. +Preserve all the copyright notices of the Document. +

  5. + Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +

  6. + Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +

  7. + Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +

  8. + Include an unaltered copy of this License. +

  9. + Preserve the section entitled "History", and its title, and add to + it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +

  10. + Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +

  11. + In any section entitled "Acknowledgements" or "Dedications", + preserve the section's title, and preserve in the section all the + substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +

  12. + Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +

  13. + Delete any section entitled "Endorsements". Such a section + may not be included in the Modified Version. +

  14. + Do not retitle any existing section as "Endorsements" + or to conflict in title with any Invariant Section. +

+If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. +

+You may add a section entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. +

+You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. +

+The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. +

+5. COMBINING DOCUMENTS +

+You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice. +

+The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. +

+In the combination, you must combine any sections entitled "History" +in the various original documents, forming one section entitled +"History"; likewise combine any sections entitled "Acknowledgements", +and any sections entitled "Dedications". You must delete all sections +entitled "Endorsements." +

+6. COLLECTIONS OF DOCUMENTS +

+You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. +

+You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. +

+7. AGGREGATION WITH INDEPENDENT WORKS +

+A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, does not as a whole count as a Modified Version +of the Document, provided no compilation copyright is claimed for the +compilation. Such a compilation is called an "aggregate", and this +License does not apply to the other self-contained works thus compiled +with the Document, on account of their being thus compiled, if they +are not themselves derivative works of the Document. +

+If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one quarter +of the entire aggregate, the Document's Cover Texts may be placed on +covers that surround only the Document within the aggregate. +Otherwise they must appear on covers around the whole aggregate. +

+8. TRANSLATION +

+Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License provided that you also include the +original English version of this License. In case of a disagreement +between the translation and the original English version of this +License, the original English version will prevail. +

+9. TERMINATION +

+You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. +

+10. FUTURE REVISIONS OF THIS LICENSE +

+The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +http://www.gnu.org/copyleft. +

+Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. +

+ADDENDUM: How to use this License for your documents +

+To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: +

+ Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + A copy of the license is included in the section entitled "GNU + Free Documentation License". +

+If you have no Invariant Sections, write "with no Invariant Sections" +instead of saying which ones are invariant. If you have no +Front-Cover Texts, write "no Front-Cover Texts" instead of +"Front-Cover Texts being LIST"; likewise for Back-Cover Texts. +

+If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-gnu.html b/lib/jalopy/license-gnu.html new file mode 100644 index 0000000000..50e714fdbd --- /dev/null +++ b/lib/jalopy/license-gnu.html @@ -0,0 +1,356 @@ + + + + + Appendix E. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix E. GNU GENERAL PUBLIC LICENSE Version 2, June 1991

+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +

+Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +

+Preamble +

+The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. +

+When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. +

+To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. +

+For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. +

+We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. +

+Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. +

+Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. +

+The precise terms and conditions for copying, distribution and +modification follow. +

+ GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +

+0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". +

+Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. +

+1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. +

+You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. +

+2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: +

+ a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. +

+ b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. +

+ c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) +

+These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. +

+Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. +

+In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. +

+3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +

+ a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, +

+ b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, +

+ c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) +

+The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. +

+If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. +

+4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. +

+5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. +

+6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. +

+7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. +

+If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. +

+It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. +

+This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. +

+8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. +

+9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. +

+Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. +

+10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. +

+ NO WARRANTY +

+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. +

+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. +

+ END OF TERMS AND CONDITIONS +

+ How to Apply These Terms to Your New Programs +

+If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. +

+To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. +

+ <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> +

+ This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +

+ This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +

+ You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +

+Also add information on how to contact you by electronic and paper mail. +

+If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: +

+ Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. +

+The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. +

+You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: +

+Yoyodyne, Inc., hereby disclaims all copyright interest in the program +`Gnomovision' (which makes passes at compilers) written by James Hacker. +

+<signature of Ty Coon>, 1 April 1989 +Ty Coon, President of Vice +

+This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. +

to top

\ No newline at end of file diff --git a/lib/jalopy/license-sun-public.html b/lib/jalopy/license-sun-public.html new file mode 100644 index 0000000000..4d3d954ef4 --- /dev/null +++ b/lib/jalopy/license-sun-public.html @@ -0,0 +1,47 @@ + + + + + Appendix H. SUN PUBLIC LICENSE Version 1.0 + + +
Overview • + Download • + Documentation • + Plug-ins • + Links • + Contact
Features | + History | + Manual | + FAQ | + Javadoc
+ This page generated: November 14 2002

Appendix H. SUN PUBLIC LICENSE Version 1.0

  1. +Definitions. +

    1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party.

    1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications.

    1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor.

    1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof and corresponding documentation released with the source code.

    1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data.

    1.5. "Executable" means Covered Code in any form other than Source Code.

    1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A.

    1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License.

    1.8. "License" means this document.

    1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.

    1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is:

    1. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications.

    2. Any new file that contains any part of the Original Code or previous Modifications.

    1.10. "Original Code"../ means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License.

    1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.

    1.11. "Source Code"../ means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated documentation, interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge.

    1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control"../ means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.

  2. +Source Code License. +

    2.1 The Initial Developer Grant.

    The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:

    (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and

    (b) under Patent Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof).

    (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License.

    (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices.

    2.2. Contributor Grant.

    Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license

    (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and

    b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).

    (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code.

    (d) notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor.

  3. Distribution Obligations.

    3.1. Application of License.

    The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5.

    3.2. Availability of Source Code.

    Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party.

    3.3. Description of Modifications.

    You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code.

    3.4. Intellectual Property Matters.

    (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "../LEGAL'' which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained.

    (b) Contributor APIs.

    If Contributor's Modifications include an application programming interface ("API"../) and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file.

    (c) Representations.

    Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License.

    3.5. Required Notices.

    You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.

    3.6. Distribution of Executable Versions.

    You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.

    3.7. Larger Works.

    You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code.

  4. Inability to Comply Due to Statute or Regulation.

    +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. +

  5. Application of this License.

    +This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. +

  6. Versions of the License.

    6.1. New Versions.

    Sun Microsystems, Inc. ("Sun") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number.

    6.2. Effect of New Versions.

    Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Sun. No one other than Sun has the right to modify the terms applicable to Covered Code created under this License.

    6.3. Derivative Works.

    If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must: (a) rename Your license so that the phrases "Sun," "Sun Public License," or "SPL"../ or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Sun Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.)

  7. DISCLAIMER OF WARRANTY.

    COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.

  8. TERMINATION.

    8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.

    8.2. If You initiate litigation by asserting a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that:

    (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above.

    (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant.

    8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license.

    8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination.

  9. LIMITATION OF LIABILITY.

    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.

  10. U.S. GOVERNMENT END USERS. +

    The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation,"../ as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein.

  11. MISCELLANEOUS. +

    This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License.

  12. RESPONSIBILITY FOR CLAIMS.

    As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.

  13. MULTIPLE-LICENSED CODE.

    Initial Developer may designate portions of the Covered Code as ?Multiple-Licensed?. ?Multiple-Licensed? means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A.

Exhibit A - Sun Public License Notice.

The contents of this file are subject to the Sun Public License +Version 1.0 (the License); you may not use this file except in +compliance with the License. A copy of the License is available at +http://www.sun.com/ +

The Original Code is _________________. The Initial Developer of the +Original Code is ___________. Portions created by ______ are Copyright +(C)_________. All Rights Reserved.

Contributor(s): ______________________________________.

Alternatively, the contents of this file may be used under the terms +of the _____ license (the ?[___] License?), in which case the +provisions of [______] License are applicable instead of those above. +If you wish to allow use of your version of this file only under the +terms of the [____] License and not to allow others to use your +version of this file under the SPL, indicate your decision by deleting +the provisions above and replace them with the notice and other +provisions required by the [___] License. If you do not delete the +provisions above, a recipient may use your version of this file under +either the SPL or the [___] License.

[NOTE: The text of this Exhibit A may differ slightly from the text of +the notices in the Source Code files of the Original Code. You should +use the text of this Exhibit A rather than the text found in the +Original Code Source Code for Your Modifications.]

to top

\ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000000..82aac31ef3 --- /dev/null +++ b/license.txt @@ -0,0 +1,58 @@ +/* + * All source code, binaries, documentation and other files distributed + * with the Acegi Security System for Spring (except the third-party libraries + * in the "lib" directories, included in the "-with-dependencies" download) + * are subject to the following license terms, and are held under the + * following copyright notice. + * + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 2004 The Acegi Security System for Spring Project. + * All rights reserved. The Acegi Security System for Spring Project is + * represented by Ben Alex . + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Acegi Security System for Spring Project + * (http://acegisecurity.sourceforge.net)." Alternately, this acknowledgment + * may appear in the software itself, if and wherever such third-party + * acknowledgments normally appear. + * + * 4. The names "Acegi" and "Acegi Security System for Spring" must not be used + * to endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * . + * + * 5. Products derived from this software may not be called "Acegi", nor may + * "Acegi" appear in their name, without prior written permission of + * Acegi Technology Pty Limited (www.acegi.com.au). + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * ACEGI SECURITY SYSTEM FOR SPRING PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Acegi Security System for Spring Project. For more + * information on the Acegi Security System for Spring Project, please see + * . + */ diff --git a/project.properties b/project.properties new file mode 100644 index 0000000000..0f3d1d39e8 --- /dev/null +++ b/project.properties @@ -0,0 +1,80 @@ +# Ant properties for building the Acegi Security System for Spring. + +# Values in this file will be overriden by any values with the same name +# in the user-created build.properties file. + +# $Id$ + +# Project version +acegi-security-version=0.3 + +# Project name +name=acegi-security-system-for-spring + +# Compile with debug code +debug=on + +# With the exception of 'dist' and 'docs/api', all artifacts produced by +# the build go somewhere underneath the target dir +target.dir=${basedir}/target + +# Main source tree will be compiled into this directory tree +target.classes.dir=${target.dir}/classes + +# Test tree will be compiled into this directory tree +target.testclasses.dir=${target.dir}/test-classes + +# Names of distribution jar files +acegi-security.jar=acegi-security.jar + +# Name of Zip file containing all project sources +acegi-security-src.zip=acegi-security-src.zip + +# Library directory within project. Where third party jars reside. +lib.dir=${basedir}/lib + +# Source directory under the current root +src.dir=${basedir}/src + +# Directory for generated API documentation --> +javadocs.dir=${basedir}/docs/api + +# Test directory under the current root +test.dir=${basedir}/test + +# Wildcards to be matched by JUnit tests +# Convention is that our JUnit test classes have names like XXXXTestSuite or XXXTests +test.includes=**/*TestSuite.class **/*Tests.class + +# Wildcards to exclude among JUnit tests +test.excludes=**/Abstract* + +# Directory where JUnit test reports are written +target.junit.reports.dir=${target.dir}/test-reports + +# Directory we generate distribution units such as jars and zips to +dist.dir=dist + +# Directory for release ZIPs +target.release.dir=${target.dir}/release + +# ZIP file that gets created for a release +release.zip=acegi-security-${acegi-security-version}.zip +release-with-dependencies.zip=acegi-security-${acegi-security-version}-with-dependencies.zip + +# Path prefix within the ZIP file +release.path=acegi-security-${acegi-security-version} + +# This is only used by the ant build to kill this directory, where IDEs may +# place other class files (for samples, etc.) +target.otherclasses.dir=${target.dir}/other-classes + +# Where to find code formatting rules +jalopy.xml=jalopy.xml + +# ------------------------------------------------------------------------ +# docbook reference documentation +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +doc.dir=docs +doc.ref.dir=docs/reference +dist.ref.dir=docs/reference diff --git a/roadmap.txt b/roadmap.txt new file mode 100644 index 0000000000..ec6b568f5e --- /dev/null +++ b/roadmap.txt @@ -0,0 +1,40 @@ +=============================================================================== + ACEGI SECURITY SYSTEM FOR SPRING - ROADMAP +=============================================================================== + +The following changes/enhancements are proposed. We are not actively working +towards any of these, but they're provided so those interested in contributing +to the project have some ideas on where they could potentially add value. + +- Extend integration tests to support Resin (Ant startup/shutdown approach + needed) + +- Tablib that can query Authentication object in ContextHolder and hide links + if the user does not hold a required authority + +- Extend Spring remoting classes to transparently transport the Context + +- Sample application that demonstrates EJB remote method invocation with Acegi + security system as login module on server side + +- Single sign on (SSO) web application that uses cookies and redirects (user + accesses secured page, container FORM shown, container FORM redirs to SSO + web app with target page passed as variable, SSO queries cookie to see if + user already logged in, SSO completes user login, SSO redirects to container + login page with Authentication being j_username etc, container logs user in + and redirects to original secured page as per normal) + +- Unit tests for JDBC authentication provider + +- Web application to administer the JDBC authentication repository, so people + don't need to write their own or rely on RDBMS tools to manage users etc + +The following are non-goals: + +- Orion container adapter. I did write a suitable adapter, but found the + unresolved taglib support issue detailed at + http://bugs.orionserver.com/issue/view.jsp?id=1081 prevented the sample + application from being tested. + + +$Id$ diff --git a/samples/attributes/.cvsignore b/samples/attributes/.cvsignore new file mode 100644 index 0000000000..580538218c --- /dev/null +++ b/samples/attributes/.cvsignore @@ -0,0 +1,4 @@ +classes +generated +reports + diff --git a/samples/attributes/build.xml b/samples/attributes/build.xml new file mode 100644 index 0000000000..f98ab38682 --- /dev/null +++ b/samples/attributes/build.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/attributes/project.properties b/samples/attributes/project.properties new file mode 100644 index 0000000000..8579fbd472 --- /dev/null +++ b/samples/attributes/project.properties @@ -0,0 +1,13 @@ +# Ant properties for building the Attributes sample application. +# $Id$ + +name=attributes +src.dir=src +src.generated.dir=generated +lib.dir=${basedir}/../../lib +dist.lib.dir=${basedir}/../../dist +build.dir=classes +jalopy.xml=${basedir}/../../jalopy.xml +reports.dir=reports +test.includes=**/*TestSuite.class **/*Tests.class +test.excludes=**/Abstract* diff --git a/samples/attributes/src/applicationContext.xml b/samples/attributes/src/applicationContext.xml new file mode 100644 index 0000000000..7480623702 --- /dev/null +++ b/samples/attributes/src/applicationContext.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + my_run_as_password + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + securityInterceptor + + + + + + + bankService + + + + + diff --git a/samples/attributes/src/main/java/sample/attributes/BankService.java b/samples/attributes/src/main/java/sample/attributes/BankService.java new file mode 100644 index 0000000000..13d6dfbfe1 --- /dev/null +++ b/samples/attributes/src/main/java/sample/attributes/BankService.java @@ -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 sample.attributes; + +/** + * DOCUMENT ME! + * + * @author Cameron Braid + * @author Ben Alex + * @version $Id$ + * + * @@SecurityConfig("ROLE_TELLER") + */ +public interface BankService { + //~ Methods ================================================================ + + /** + * The SecurityConfig below will be merged with the interface-level + * SecurityConfig above by Commons Attributes. ie: this is equivalent to + * defining BankService=ROLE_TELLER,ROLE_PERMISSION_BALANACE in the bean + * context. + * + * @return DOCUMENT ME! + * + * @@SecurityConfig("ROLE_PERMISSION_BALANCE") + */ + public float balance(String accountNumber); + + /** + * The SecurityConfig below will be merged with the interface-level + * SecurityConfig above by Commons Attributes. ie: this is equivalent to + * defining BankService=ROLE_TELLER,ROLE_PERMISSION_LIST in the bean + * context. + * + * @return DOCUMENT ME! + * + * @@SecurityConfig("ROLE_PERMISSION_LIST") + */ + public String[] listAccounts(); +} diff --git a/samples/attributes/src/main/java/sample/attributes/BankServiceImpl.java b/samples/attributes/src/main/java/sample/attributes/BankServiceImpl.java new file mode 100644 index 0000000000..393ec85416 --- /dev/null +++ b/samples/attributes/src/main/java/sample/attributes/BankServiceImpl.java @@ -0,0 +1,27 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.attributes; + +/** + * DOCUMENT ME! + * + * @author Cameron Braid + * @author Ben Alex + * @version $Id$ + */ +public class BankServiceImpl implements BankService { + //~ Methods ================================================================ + + public float balance(String accountNumber) { + return 42000000; + } + + public String[] listAccounts() { + return new String[] {"1", "2", "3"}; + } +} diff --git a/samples/attributes/src/main/java/sample/attributes/BankTests.java b/samples/attributes/src/main/java/sample/attributes/BankTests.java new file mode 100644 index 0000000000..8a3e90aa86 --- /dev/null +++ b/samples/attributes/src/main/java/sample/attributes/BankTests.java @@ -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 sample.attributes; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.AccessDeniedException; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.providers.TestingAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Tests security objects. + * + * @author Ben Alex + * @version $Id$ + */ +public class BankTests extends TestCase { + //~ Instance fields ======================================================== + + private BankService service; + private ClassPathXmlApplicationContext ctx; + + //~ Constructors =========================================================== + + public BankTests() { + super(); + } + + public BankTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); + service = (BankService) ctx.getBean("bankService"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(BankTests.class); + } + + public void testDeniedAccess() throws Exception { + createSecureContext(); + + try { + service.balance("1"); + fail("Should have thrown AccessDeniedException"); + } catch (AccessDeniedException expected) { + assertTrue(true); + } + + destroySecureContext(); + } + + public void testListAccounts() throws Exception { + createSecureContext(); + service.listAccounts(); + destroySecureContext(); + } + + private static void createSecureContext() { + TestingAuthenticationToken auth = new TestingAuthenticationToken("test", + "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"), new GrantedAuthorityImpl("ROLE_PERMISSION_LIST")}); + + SecureContextImpl secureContext = new SecureContextImpl(); + secureContext.setAuthentication(auth); + ContextHolder.setContext(secureContext); + } + + private static void destroySecureContext() { + ContextHolder.setContext(null); + } +} diff --git a/samples/attributes/src/main/java/sample/attributes/Main.java b/samples/attributes/src/main/java/sample/attributes/Main.java new file mode 100644 index 0000000000..797980ce78 --- /dev/null +++ b/samples/attributes/src/main/java/sample/attributes/Main.java @@ -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 sample.attributes; + +import net.sf.acegisecurity.AccessDeniedException; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.providers.TestingAuthenticationToken; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * DOCUMENT ME! + * + * @author Cameron Braid + * @author Ben Alex + * @version $Id$ + */ +public class Main { + //~ Methods ================================================================ + + public static void main(String[] args) throws Exception { + createSecureContext(); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); + BankService service = (BankService) context.getBean("bankService"); + + // will succeed + service.listAccounts(); + + // will fail + try { + System.out.println("We expect an AccessDeniedException now, as we do not hold the ROLE_PERMISSION_BALANCE granted authority, and we're using a unanimous access decision manager... "); + service.balance("1"); + } catch (AccessDeniedException e) { + e.printStackTrace(); + } + + destroySecureContext(); + } + + /** + * This can be done in a web app by using a filter or + * SpringMvcIntegrationInterceptor. + */ + private static void createSecureContext() { + TestingAuthenticationToken auth = new TestingAuthenticationToken("test", + "test", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"), new GrantedAuthorityImpl("ROLE_PERMISSION_LIST")}); + + SecureContextImpl secureContext = new SecureContextImpl(); + secureContext.setAuthentication(auth); + ContextHolder.setContext(secureContext); + } + + private static void destroySecureContext() { + ContextHolder.setContext(null); + } +} diff --git a/samples/contacts/.cvsignore b/samples/contacts/.cvsignore new file mode 100644 index 0000000000..31132cffb4 --- /dev/null +++ b/samples/contacts/.cvsignore @@ -0,0 +1,5 @@ +classes +dist +api +build.properties + diff --git a/samples/contacts/build.xml b/samples/contacts/build.xml new file mode 100644 index 0000000000..eda142ecbc --- /dev/null +++ b/samples/contacts/build.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Acegi Security System for Spring Contacts Sample]]> + Acegi Security System for Spring Project]]> + + + + + + + + + + diff --git a/samples/contacts/project.properties b/samples/contacts/project.properties new file mode 100644 index 0000000000..df6527080a --- /dev/null +++ b/samples/contacts/project.properties @@ -0,0 +1,12 @@ +# Ant properties for building the Contacts sample application. +# $Id$ + +name=contacts +src.dir=src +war.dir=war +lib.dir=${basedir}/../../lib +dist.lib.dir=${basedir}/../../dist +build.dir=classes +dist.dir=dist +javadocs.dir=api +jalopy.xml=${basedir}/../../jalopy.xml diff --git a/samples/contacts/src/main/java/sample/contact/Contact.java b/samples/contacts/src/main/java/sample/contact/Contact.java new file mode 100644 index 0000000000..4c53b375d6 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/Contact.java @@ -0,0 +1,107 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +/** + * Represents a contact. + * + *

+ * id and owner are immutable. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class Contact { + //~ Instance fields ======================================================== + + private Integer id; + private String email; + private String name; + private String owner; + + //~ Constructors =========================================================== + + public Contact(Integer id, String name, String email, String owner) { + this.id = id; + this.name = name; + this.email = email; + this.owner = owner; + } + + private Contact() { + super(); + } + + //~ Methods ================================================================ + + /** + * DOCUMENT ME! + * + * @param email The email to set. + */ + public void setEmail(String email) { + this.email = email; + } + + /** + * DOCUMENT ME! + * + * @return Returns the email. + */ + public String getEmail() { + return email; + } + + /** + * DOCUMENT ME! + * + * @return Returns the id. + */ + public Integer getId() { + return id; + } + + /** + * DOCUMENT ME! + * + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * DOCUMENT ME! + * + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * DOCUMENT ME! + * + * @return Returns the owner. + */ + public String getOwner() { + return owner; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(super.toString() + ": "); + sb.append("Id: " + this.getId() + "; "); + sb.append("Name: " + this.getName() + "; "); + sb.append("Email: " + this.getEmail() + "; "); + sb.append("Owner: " + this.getOwner()); + + return sb.toString(); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/ContactManager.java b/samples/contacts/src/main/java/sample/contact/ContactManager.java new file mode 100644 index 0000000000..3ecce67edb --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/ContactManager.java @@ -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 sample.contact; + +/** + * Iterface for the application's business object. + * + * @author Ben Alex + * @version $Id$ + */ +public interface ContactManager { + //~ Methods ================================================================ + + public Contact[] getAllByOwner(String owner); + + public Contact getById(Integer id); + + public Integer getNextId(); + + public Contact getRandomContact(); + + public void delete(Contact contact); + + public void save(Contact contact); +} diff --git a/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java b/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java new file mode 100644 index 0000000000..348aaed3de --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java @@ -0,0 +1,168 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Vector; + + +/** + * Backend business object that manages the contacts. + * + *

+ * As a backend, it never faces the public callers. It is always accessed via + * the {@link ContactManagerFacade}. + *

+ * + *

+ * This facade approach is not really necessary in this application, and is + * done simply to demonstrate granting additional authorities via the + * RunAsManager. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class ContactManagerBackend implements ContactManager { + //~ Instance fields ======================================================== + + private Map contacts; + + //~ Constructors =========================================================== + + public ContactManagerBackend() { + this.contacts = new HashMap(); + save(new Contact(this.getNextId(), "John Smith", "john@somewhere.com", + "marissa")); + save(new Contact(this.getNextId(), "Michael Citizen", + "michael@xyz.com", "marissa")); + save(new Contact(this.getNextId(), "Joe Bloggs", "joe@demo.com", + "marissa")); + save(new Contact(this.getNextId(), "Karen Sutherland", + "karen@sutherland.com", "dianne")); + save(new Contact(this.getNextId(), "Mitchell Howard", + "mitchell@abcdef.com", "dianne")); + save(new Contact(this.getNextId(), "Rose Costas", "rose@xyz.com", + "scott")); + save(new Contact(this.getNextId(), "Amanda Smith", "amanda@abcdef.com", + "scott")); + } + + //~ Methods ================================================================ + + /** + * Security system expects ROLE_RUN_AS_SERVER + * + * @param owner DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Contact[] getAllByOwner(String owner) { + List list = new Vector(); + Iterator iter = this.contacts.keySet().iterator(); + + while (iter.hasNext()) { + Integer contactId = (Integer) iter.next(); + Contact contact = (Contact) this.contacts.get(contactId); + + if (contact.getOwner().equals(owner)) { + list.add(contact); + } + } + + Contact[] resultType = {new Contact(new Integer(1), "holder", "holder", + "holder")}; + + if (list.size() == 0) { + return null; + } else { + return (Contact[]) list.toArray(resultType); + } + } + + /** + * Security system expects ROLE_RUN_AS_SERVER + * + * @param id DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Contact getById(Integer id) { + return (Contact) this.contacts.get(id); + } + + /** + * Public method + * + * @return DOCUMENT ME! + */ + public Integer getNextId() { + int max = 0; + Iterator iter = this.contacts.keySet().iterator(); + + while (iter.hasNext()) { + Integer id = (Integer) iter.next(); + + if (id.intValue() > max) { + max = id.intValue(); + } + } + + return new Integer(max + 1); + } + + /** + * This is a public method, meaning a client could call this method + * directly (ie not via a facade). If this was an issue, the public method + * on the facade should not be public but secure. Quite possibly an + * AnonymousAuthenticationToken and associated provider could be used on a + * secure method, thus allowing a RunAsManager to protect the backend. + * + * @return DOCUMENT ME! + */ + public Contact getRandomContact() { + Random rnd = new Random(); + int getNumber = rnd.nextInt(this.contacts.size()) + 1; + Iterator iter = this.contacts.keySet().iterator(); + int i = 0; + + while (iter.hasNext()) { + i++; + + Integer id = (Integer) iter.next(); + + if (i == getNumber) { + return (Contact) this.contacts.get(id); + } + } + + return null; + } + + /** + * Security system expects ROLE_RUN_AS_SERVER + * + * @param contact DOCUMENT ME! + */ + public void delete(Contact contact) { + this.contacts.remove(contact.getId()); + } + + /** + * Security system expects ROLE_RUN_AS_SERVER + * + * @param contact DOCUMENT ME! + */ + public void save(Contact contact) { + this.contacts.put(contact.getId(), contact); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java b/samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java new file mode 100644 index 0000000000..3ef3d9a486 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java @@ -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 sample.contact; + +import net.sf.acegisecurity.AccessDeniedException; +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.SecureContext; + +import org.springframework.beans.factory.InitializingBean; + + +/** + * This is the public facade to the application's main business object. + * + *

+ * Used to demonstrate security configuration in a multi-tier application. Most + * methods of this class are secured via standard security definitions in the + * bean context. There is one method that supplements these security checks. + * All methods delegate to a "backend" object. The "backend" object relies on + * the facade's RunAsManager assigning an additional + * GrantedAuthority that is required to call its methods. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class ContactManagerFacade implements ContactManager, InitializingBean { + //~ Instance fields ======================================================== + + private ContactManager backend; + + //~ Methods ================================================================ + + /** + * Security system will ensure the owner parameter equals the currently + * logged in user. + * + * @param owner DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Contact[] getAllByOwner(String owner) { + return backend.getAllByOwner(owner); + } + + public void setBackend(ContactManager backend) { + this.backend = backend; + } + + public ContactManager getBackend() { + return backend; + } + + /** + * Security system will ensure logged in user has ROLE_TELLER. + * + *

+ * Security system cannot ensure that only the owner can get the contact, + * as doing so would require it to specifically open the contact. Whilst + * possible, this would be expensive as the operation would be performed + * both by the security system as well as the implementation. Instead the + * facade will confirm the contact.getOwner() matches what is on the + * ContextHolder. + *

+ * + * @param id DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws AccessDeniedException DOCUMENT ME! + */ + public Contact getById(Integer id) { + Contact result = backend.getById(id); + Authentication auth = ((SecureContext) ContextHolder.getContext()) + .getAuthentication(); + + if (auth.getPrincipal().toString().equals(result.getOwner())) { + return result; + } else { + throw new AccessDeniedException("The requested id is not owned by the currently logged in user"); + } + } + + /** + * Public method. + * + * @return DOCUMENT ME! + */ + public Integer getNextId() { + return backend.getNextId(); + } + + /** + * Public method. + * + * @return DOCUMENT ME! + */ + public Contact getRandomContact() { + return backend.getRandomContact(); + } + + public void afterPropertiesSet() throws Exception { + if (backend == null) { + throw new IllegalArgumentException("A backend ContactManager implementation is required"); + } + } + + /** + * Security system will ensure logged in user has ROLE_SUPERVISOR. + * + * @param contact DOCUMENT ME! + */ + public void delete(Contact contact) { + backend.delete(contact); + } + + /** + * Security system will ensure the owner specified via contact.getOwner() + * equals the currently logged in user. + * + * @param contact DOCUMENT ME! + */ + public void save(Contact contact) { + backend.save(contact); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java b/samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java new file mode 100644 index 0000000000..652bbcbb63 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java @@ -0,0 +1,87 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.ConfigAttribute; +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.vote.AccessDecisionVoter; + +import org.aopalliance.intercept.MethodInvocation; + +import java.util.Iterator; + + +/** + * Implementation of an {@link AccessDecisionVoter} that provides + * application-specific security for the Contact application. + * + *

+ * If the {@link ConfigAttribute#getAttribute()} has a value of + * CONTACT_OWNED_BY_CURRENT_USER, the String or the + * Contact.getOwner() associated with the method call is compared with the + * Authentication.getPrincipal().toString() result. If it matches, the voter + * votes to grant access. If they do not match, it votes to deny access. + *

+ * + *

+ * All comparisons are case sensitive. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class ContactSecurityVoter implements AccessDecisionVoter { + //~ Methods ================================================================ + + public boolean supports(ConfigAttribute attribute) { + if ("CONTACT_OWNED_BY_CURRENT_USER".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 + String passedOwner = null; + + for (int i = 0; i < invocation.getArgumentCount(); i++) { + Class argClass = invocation.getArgument(i).getClass(); + + if (String.class.isAssignableFrom(argClass)) { + passedOwner = (String) invocation.getArgument(i); + } else if (Contact.class.isAssignableFrom(argClass)) { + passedOwner = ((Contact) invocation.getArgument(i)) + .getOwner(); + } + } + + if (passedOwner != null) { + // Check the authentication principal matches the passed owner + if (passedOwner.equals(authentication.getPrincipal() + .toString())) { + return ACCESS_GRANTED; + } + } + } + } + + return result; + } +} diff --git a/samples/contacts/src/main/java/sample/contact/DeleteController.java b/samples/contacts/src/main/java/sample/contact/DeleteController.java new file mode 100644 index 0000000000..baf453a3fb --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/DeleteController.java @@ -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 sample.contact; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * Controller to delete a contact page. + * + * @author Ben Alex + * @version $Id$ + */ +public class DeleteController implements Controller, InitializingBean { + //~ Instance fields ======================================================== + + private ContactManager contactManager; + + //~ Methods ================================================================ + + public void setContactManager(ContactManager contact) { + this.contactManager = contact; + } + + public ContactManager getContactManager() { + return contactManager; + } + + public void afterPropertiesSet() throws Exception { + if (contactManager == null) { + throw new IllegalArgumentException("A ContactManager implementation is required"); + } + } + + public ModelAndView handleRequest(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Integer id = new Integer(request.getParameter("id")); + Contact contact = contactManager.getById(id); + contactManager.delete(contact); + + return new ModelAndView("deleted", "contact", contact); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/PublicIndexController.java b/samples/contacts/src/main/java/sample/contact/PublicIndexController.java new file mode 100644 index 0000000000..7b4492589a --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/PublicIndexController.java @@ -0,0 +1,56 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * Controller for public index page (default web app home page). + * + * @author Ben Alex + * @version $Id$ + */ +public class PublicIndexController implements Controller, InitializingBean { + //~ Instance fields ======================================================== + + private ContactManager contactManager; + + //~ Methods ================================================================ + + public void setContactManager(ContactManager contact) { + this.contactManager = contact; + } + + public ContactManager getContactManager() { + return contactManager; + } + + public void afterPropertiesSet() throws Exception { + if (contactManager == null) { + throw new IllegalArgumentException("A ContactManager implementation is required"); + } + } + + public ModelAndView handleRequest(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Contact rnd = contactManager.getRandomContact(); + + return new ModelAndView("hello", "contact", rnd); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/SecureIndexController.java b/samples/contacts/src/main/java/sample/contact/SecureIndexController.java new file mode 100644 index 0000000000..3abb2323ed --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/SecureIndexController.java @@ -0,0 +1,82 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.SecureContext; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import java.io.IOException; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * Controller for secure index page. + * + * @author Ben Alex + * @version $Id$ + */ +public class SecureIndexController implements Controller, InitializingBean { + //~ Instance fields ======================================================== + + private ContactManager contactManager; + + //~ Methods ================================================================ + + public void setContactManager(ContactManager contact) { + this.contactManager = contact; + } + + public ContactManager getContactManager() { + return contactManager; + } + + public void afterPropertiesSet() throws Exception { + if (contactManager == null) { + throw new IllegalArgumentException("A ContactManager implementation is required"); + } + } + + public ModelAndView handleRequest(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Authentication currentUser = ((SecureContext) ContextHolder.getContext()) + .getAuthentication(); + + boolean supervisor = false; + GrantedAuthority[] granted = currentUser.getAuthorities(); + + for (int i = 0; i < granted.length; i++) { + if (granted[i].getAuthority().equals("ROLE_SUPERVISOR")) { + supervisor = true; + } + } + + Contact[] myContacts = contactManager.getAllByOwner(currentUser.getPrincipal() + .toString()); + + Map model = new HashMap(); + model.put("contacts", myContacts); + model.put("supervisor", new Boolean(supervisor)); + model.put("user", currentUser.getPrincipal().toString()); + + return new ModelAndView("index", "model", model); + } +} diff --git a/samples/contacts/src/main/java/sample/contact/WebContact.java b/samples/contacts/src/main/java/sample/contact/WebContact.java new file mode 100644 index 0000000000..8117c154a7 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/WebContact.java @@ -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 sample.contact; + +/** + * An object that represents user-editable sections of a {@link Contact}. + * + * @author Ben Alex + * @version $Id$ + */ +public class WebContact { + //~ Instance fields ======================================================== + + private String email; + private String name; + + //~ Methods ================================================================ + + public void setEmail(String email) { + this.email = email; + } + + public String getEmail() { + return email; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/samples/contacts/src/main/java/sample/contact/WebContactAddController.java b/samples/contacts/src/main/java/sample/contact/WebContactAddController.java new file mode 100644 index 0000000000..b5512381f7 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/WebContactAddController.java @@ -0,0 +1,68 @@ +/* + * The Acegi Security System for Spring is published under the terms + * of the Apache Software License. + * + * Visit http://acegisecurity.sourceforge.net for further details. + */ + +package sample.contact; + +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.SecureContext; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.SimpleFormController; +import org.springframework.web.servlet.view.RedirectView; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + + +/** + * Controller for adding a new contact. + * + * @author Ben Alex + * @version $Id$ + */ +public class WebContactAddController extends SimpleFormController { + //~ Instance fields ======================================================== + + private ContactManager contactManager; + + //~ Methods ================================================================ + + public void setContactManager(ContactManager contactManager) { + this.contactManager = contactManager; + } + + public ContactManager getContactManager() { + return contactManager; + } + + public ModelAndView onSubmit(Object command) throws ServletException { + String name = ((WebContact) command).getName(); + String email = ((WebContact) command).getEmail(); + String owner = ((SecureContext) ContextHolder.getContext()).getAuthentication() + .getPrincipal().toString(); + + Contact contact = new Contact(contactManager.getNextId(), name, email, + owner); + contactManager.save(contact); + + Map myModel = new HashMap(); + myModel.put("now", new Date()); + + return new ModelAndView(new RedirectView(getSuccessView())); + } + + protected Object formBackingObject(HttpServletRequest request) + throws ServletException { + WebContact wc = new WebContact(); + + return wc; + } +} diff --git a/samples/contacts/src/main/java/sample/contact/WebContactValidator.java b/samples/contacts/src/main/java/sample/contact/WebContactValidator.java new file mode 100644 index 0000000000..790c6be5f9 --- /dev/null +++ b/samples/contacts/src/main/java/sample/contact/WebContactValidator.java @@ -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 sample.contact; + +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; + + +/** + * Validates {@link WebContact}. + * + * @author Ben Alex + * @version $Id$ + */ +public class WebContactValidator implements Validator { + //~ Methods ================================================================ + + public boolean supports(Class clazz) { + return clazz.equals(WebContact.class); + } + + public void validate(Object obj, Errors errors) { + WebContact wc = (WebContact) obj; + + if ((wc.getName() == null) || (wc.getName().length() < 3)) { + errors.rejectValue("name", "not-used", null, "Name is required."); + } + + if ((wc.getEmail() == null) || (wc.getEmail().length() < 3)) { + errors.rejectValue("email", "not-used", null, "Email is required."); + } + } +} diff --git a/samples/contacts/war/WEB-INF/.cvsignore b/samples/contacts/war/WEB-INF/.cvsignore new file mode 100644 index 0000000000..86e9501ee1 --- /dev/null +++ b/samples/contacts/war/WEB-INF/.cvsignore @@ -0,0 +1,2 @@ +lib + diff --git a/samples/contacts/war/WEB-INF/contacts-servlet.xml b/samples/contacts/war/WEB-INF/contacts-servlet.xml new file mode 100644 index 0000000000..83dce57e89 --- /dev/null +++ b/samples/contacts/war/WEB-INF/contacts-servlet.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + publicIndexController + secureAddForm + secureIndexController + secureDeleteController + + + + + + + true + webContact + sample.contact.WebContact + + add + index.htm + + + + + + + /WEB-INF/jsp/ + .jsp + + + + + + + my_run_as_password + + + + + + + + + my_run_as_password + + + + + my_password + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + sample.contact.ContactManager.delete=ROLE_SUPERVISOR,RUN_AS_SERVER + sample.contact.ContactManager.getAllByOwner=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER + sample.contact.ContactManager.save=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER + sample.contact.ContactManager.getById=ROLE_TELLER,RUN_AS_SERVER + + + + + + + + + + + + sample.contact.ContactManager.delete=ROLE_RUN_AS_SERVER + sample.contact.ContactManager.getAllByOwner=ROLE_RUN_AS_SERVER + sample.contact.ContactManager.save=ROLE_RUN_AS_SERVER + sample.contact.ContactManager.getById=ROLE_RUN_AS_SERVER + + + + + + + + sample.contact.ContactManager + + + publicContactManagerSecurity + publicContactManagerTarget + + + + + + + + + + sample.contact.ContactManager + + + backendContactManagerSecurity + backendContactManagerTarget + + + + + + + diff --git a/samples/contacts/war/WEB-INF/jboss-web.xml b/samples/contacts/war/WEB-INF/jboss-web.xml new file mode 100644 index 0000000000..43a7c44e2e --- /dev/null +++ b/samples/contacts/war/WEB-INF/jboss-web.xml @@ -0,0 +1,6 @@ + + + java:/jaas/SpringPoweredRealm + diff --git a/samples/contacts/war/WEB-INF/jsp/add.jsp b/samples/contacts/war/WEB-INF/jsp/add.jsp new file mode 100644 index 0000000000..43e121732d --- /dev/null +++ b/samples/contacts/war/WEB-INF/jsp/add.jsp @@ -0,0 +1,40 @@ +<%@ include file="/WEB-INF/jsp/include.jsp" %> + +Add New Contact + +

Add Contact

+
+ + + + + + + + + + + + + + + +
Name: + "> + + +
Email: + "> + + +
+
+ + Please fix all errors! + +

+ +
+">Home + + diff --git a/samples/contacts/war/WEB-INF/jsp/deleted.jsp b/samples/contacts/war/WEB-INF/jsp/deleted.jsp new file mode 100644 index 0000000000..89a91b5198 --- /dev/null +++ b/samples/contacts/war/WEB-INF/jsp/deleted.jsp @@ -0,0 +1,13 @@ +<%@ include file="/WEB-INF/jsp/include.jsp" %> + + +Deletion completed + +

Deleted

+

+ + + +

Manage + + diff --git a/samples/contacts/war/WEB-INF/jsp/hello.jsp b/samples/contacts/war/WEB-INF/jsp/hello.jsp new file mode 100644 index 0000000000..c2c500f24d --- /dev/null +++ b/samples/contacts/war/WEB-INF/jsp/hello.jsp @@ -0,0 +1,24 @@ +<%@ include file="/WEB-INF/jsp/include.jsp" %> + + +Contacts Security Demo + +

Contacts Security Demo

+

This is a very simple application to demonstrate the Acegi Security System for Spring. +The application manages contacts, partitioned based on the user that owns them. +Users may only manage their own contacts, and only users with ROLE_SUPERVISOR +are allowed to delete their contacts. The application automatically extracts +the principal from the web container (which should be configured with a +suitable Acegi Security System for Spring adapter). It also demonstrates how to configure +server-side secure objects so they can only be accessed via a public facade. + +

This application also demonstrates a public method, which is used to select +the random contact that is shown below: +

+ + + +

+

Manage Debug + + diff --git a/samples/contacts/war/WEB-INF/jsp/include.jsp b/samples/contacts/war/WEB-INF/jsp/include.jsp new file mode 100644 index 0000000000..44714b507b --- /dev/null +++ b/samples/contacts/war/WEB-INF/jsp/include.jsp @@ -0,0 +1,4 @@ +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> + +<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> diff --git a/samples/contacts/war/WEB-INF/jsp/index.jsp b/samples/contacts/war/WEB-INF/jsp/index.jsp new file mode 100644 index 0000000000..c5b8f8e95b --- /dev/null +++ b/samples/contacts/war/WEB-INF/jsp/index.jsp @@ -0,0 +1,29 @@ +<%@ include file="/WEB-INF/jsp/include.jsp" %> + + +Your Contacts + +

's Contacts

+

+ + + + + + + + + + + + +
idNameEmail
+ + + + + + ">Del
+

Add Logoff + + diff --git a/samples/contacts/war/WEB-INF/resin-acegisecurity.xml b/samples/contacts/war/WEB-INF/resin-acegisecurity.xml new file mode 100644 index 0000000000..07c06dd4ee --- /dev/null +++ b/samples/contacts/war/WEB-INF/resin-acegisecurity.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR + dianne=emu,ROLE_TELLER + scott=wombat,ROLE_TELLER + peter=opal,disabled,ROLE_TELLER + + + + + + + + false + true + + + + + + + + + + + + diff --git a/samples/contacts/war/WEB-INF/resin-web.xml b/samples/contacts/war/WEB-INF/resin-web.xml new file mode 100644 index 0000000000..a1f4149c54 --- /dev/null +++ b/samples/contacts/war/WEB-INF/resin-web.xml @@ -0,0 +1,12 @@ + + + + net.sf.acegisecurity.adapters.resin.ResinSpringAuthenticator + + WEB-INF/resin-acegisecurity.xml + my_password + + + diff --git a/samples/contacts/war/WEB-INF/spring.tld b/samples/contacts/war/WEB-INF/spring.tld new file mode 100644 index 0000000000..c526a55fcb --- /dev/null +++ b/samples/contacts/war/WEB-INF/spring.tld @@ -0,0 +1,193 @@ + + + + + + 1.0 + + 1.2 + + Spring + + http://www.springframework.org/tags + + Spring Framework JSP Tag Library. Authors: Rod Johnson, Juergen Hoeller + + + + htmlEscape + org.springframework.web.servlet.tags.HtmlEscapeTag + JSP + + + Sets default HTML escape value for the current page. + + + + defaultHtmlEscape + true + true + + + + + + + message + org.springframework.web.servlet.tags.MessageTag + JSP + + + Retrieves the message with the given code, or text if code isn't resolvable. + + + + code + false + true + + + + text + false + true + + + + htmlEscape + false + true + + + + + + + theme + org.springframework.web.servlet.tags.ThemeTag + JSP + + + Retrieves the theme message with the given code, or text if code isn't resolvable. + + + + code + false + true + + + + text + false + true + + + + htmlEscape + false + true + + + + + + + hasBindErrors + org.springframework.web.servlet.tags.BindErrorsTag + JSP + + + Provides Errors instance in case of bind errors. + + + + + errors + org.springframework.validation.Errors + + + + + name + true + true + + + + htmlEscape + false + true + + + + + + + bind + org.springframework.web.servlet.tags.BindTag + JSP + + + Provides BindStatus instance for certain bind path. + + + + + status + org.springframework.web.servlet.tags.BindStatus + + + + + path + true + true + + + + htmlEscape + false + true + + + + + + + transform + org.springframework.web.servlet.tags.TransformTag + JSP + + + Provides transformation of variables to Strings using appropriate + Custom Editor from BindTag (can only be used inside BindTag) + + + + value + true + true + + + + var + false + true + + + + scope + false + true + + + + htmlEscape + false + true + + + + + diff --git a/samples/contacts/war/WEB-INF/web.xml b/samples/contacts/war/WEB-INF/web.xml new file mode 100644 index 0000000000..5827bd74d0 --- /dev/null +++ b/samples/contacts/war/WEB-INF/web.xml @@ -0,0 +1,100 @@ + + + + + + + + Contacts Sample Application + + + Example of an application secured using Acegi Security System for Spring. + + + + Acegi Security System for Spring + net.sf.acegisecurity.adapters.AutoIntegrationFilter + + + + Acegi Security System for Spring + /* + + + + + contacts + org.springframework.web.servlet.DispatcherServlet + 1 + + + + + contacts + *.htm + + + + index.jsp + + + + /spring + /WEB-INF/spring.tld + + + + Secured Area Security Constraint + + Secured Area + + /secure/* + + + + ROLE_TELLER + ROLE_SUPERVISOR + + + + + + + + + FORM + Spring Powered Realm + + /login.jsp + /login.jsp?login_error=1 + + + + + + ROLE_SUPERVISOR + + + ROLE_TELLER + + + diff --git a/samples/contacts/war/index.jsp b/samples/contacts/war/index.jsp new file mode 100644 index 0000000000..d724fd2101 --- /dev/null +++ b/samples/contacts/war/index.jsp @@ -0,0 +1,4 @@ +<%@ include file="/WEB-INF/jsp/include.jsp" %> + +<%-- Redirected because we can't set the welcome page to a virtual URL. --%> + diff --git a/samples/contacts/war/login.jsp b/samples/contacts/war/login.jsp new file mode 100644 index 0000000000..42fe26f94e --- /dev/null +++ b/samples/contacts/war/login.jsp @@ -0,0 +1,43 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %> + + + + Login + + + +

Login

+ +

If you've used the standard springsecurity.xml, try these users: +

+

username marissa, password koala (granted ROLE_SUPERVISOR) +

username dianne, password emu (not a supervisor) +

username scott, password wombat (not a supervisor) +

+ + <%-- this form-login-page form is also used as the + form-error-page to ask for a login again. + --%> + + + Your login attempt was not successful, try again. + + + +

+ + + + + + +
User:
Password:
+ + + +
+ + + diff --git a/samples/contacts/war/logoff.jsp b/samples/contacts/war/logoff.jsp new file mode 100644 index 0000000000..6384a8a022 --- /dev/null +++ b/samples/contacts/war/logoff.jsp @@ -0,0 +1,3 @@ +<%session.invalidate(); +response.sendRedirect("index.jsp"); +%> \ No newline at end of file diff --git a/samples/contacts/war/secure/debug.jsp b/samples/contacts/war/secure/debug.jsp new file mode 100644 index 0000000000..d48587e9c1 --- /dev/null +++ b/samples/contacts/war/secure/debug.jsp @@ -0,0 +1,48 @@ +<%@ page import="net.sf.acegisecurity.context.Context" %> +<%@ page import="net.sf.acegisecurity.context.ContextHolder" %> +<%@ page import="net.sf.acegisecurity.context.SecureContext" %> +<%@ page import="net.sf.acegisecurity.Authentication" %> +<%@ page import="net.sf.acegisecurity.GrantedAuthority" %> +<%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %> + +<% Context context = ContextHolder.getContext(); +if (context != null) { %> + Context on ContextHolder is of type: <%= context.getClass().getName() %>

+ +<% if (context instanceof SecureContext) { %> + The Context implements SecureContext.

+<% SecureContext sc = (SecureContext) context; + + Authentication auth = sc.getAuthentication(); + if (auth != null) { %> + Authentication object is of type: <%= auth.getClass().getName() %>

+ Authentication object as a String: <%= auth.toString() %>

+ + Authentication object holds the following granted authorities:

+<% GrantedAuthority[] granted = auth.getAuthorities(); + for (int i = 0; i < granted.length; i++) { %> + <%= granted[i].toString() %> (getAuthority(): <%= granted[i].getAuthority() %>)
+<% } + + if (auth instanceof AuthByAdapter) { %> +
SUCCESS! Your container adapter appears to be properly configured!

+<% } else { %> +
WARNING: Authentication object does not implement AuthByAdapter
+ This may point to an error with your adapter configuration, although can be ignored if intentional.

+<% } + + } else { %> + Authentication object is null.
+ This is an error and your container adapter will not operate properly until corrected.

+<% } + } else { %> + ContextHolder does not contain a SecureContext.
+ This is an error and your container adapter will not operate properly until corrected.

+<% } +} else { %> + ContextHolder on ContextHolder is null.
+ This indicates improper setup of the container adapter. Refer to the reference documentation.
+ Also ensure the correct subclass of AbstractMvcIntegrationInterceptor is being used for your container.
+<%} +%> +