diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml
new file mode 100644
index 0000000..472c5c6
--- /dev/null
+++ b/cas-client-integration-tomcat-common/pom.xml
@@ -0,0 +1,27 @@
+
+
+ * Authentication always succeeds and simply returns the given principal.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public class AssertionCasRealmDelegate implements CasRealm {
+ /** Default role attribute name */
+ public static final String DEFAULT_ROLE_NAME = "role";
+
+ /** Log instance */
+ private final Log log = LogFactory.getLog(getClass());
+
+ /** Name of the role attribute in the principal's attributes */
+ private String roleAttributeName = DEFAULT_ROLE_NAME;
+
+
+ /**
+ * @param name Name of the attribute in the principal that contains role data.
+ */
+ public void setRoleAttributeName(final String name) {
+ this.roleAttributeName = name;
+ }
+
+ /** {@inheritDoc} */
+ public Principal authenticate(final Principal p) {
+ return p;
+ }
+
+ /** {@inheritDoc} */
+ public String[] getRoles(final Principal p) {
+ if (p instanceof AttributePrincipal) {
+ final Collection roles = getRoleCollection(p);
+ if (roles != null) {
+ final String[] array = new String[roles.size()];
+ roles.toArray(array);
+ return array;
+ } else {
+ return new String[0];
+ }
+ } else {
+ throw new IllegalArgumentException("Expected instance of AttributePrincipal but got " + p);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasRole(final Principal principal, final String role) {
+ final Collection roles = getRoleCollection(principal);
+ if (roles != null) {
+ return roles.contains(role);
+ } else {
+ return false;
+ }
+ }
+
+ private Collection getRoleCollection(final Principal p) {
+ if (p instanceof AttributePrincipal) {
+ final Collection attributes =
+ (Collection) ((AttributePrincipal) p).getAttributes().get(roleAttributeName);
+ if (attributes == null) {
+ log.debug(p + " has no attribute named " + roleAttributeName);
+ }
+ return attributes;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/AuthenticatorDelegate.java b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/AuthenticatorDelegate.java
new file mode 100644
index 0000000..c582e79
--- /dev/null
+++ b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/AuthenticatorDelegate.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.tomcat;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.cas.client.util.AbstractCasFilter;
+import org.jasig.cas.client.util.CommonUtils;
+import org.jasig.cas.client.validation.Assertion;
+import org.jasig.cas.client.validation.TicketValidationException;
+import org.jasig.cas.client.validation.TicketValidator;
+
+/**
+ * Version-agnostic authenticator which encapsulates the core CAS workflow of
+ * redirecting to CAS for unauthenticated sessions and validating service tickets
+ * when found in the request. Implementations of the Tomcat Authenticator
+ * class are expected to be thin wrappers that delegate most if not all authentication
+ * logic to this class.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public class AuthenticatorDelegate {
+ /** Log instance */
+ private final Log log = LogFactory.getLog(getClass());
+
+ private String serviceUrl;
+
+ private String serverName;
+
+ private String casServerLoginUrl;
+
+ private String artifactParameterName;
+
+ private String serviceParameterName;
+
+ private TicketValidator ticketValidator;
+
+ private CasRealm realm;
+
+
+ /**
+ * Performs CAS authentication on the given request and returns the principal
+ * determined by the configured {@link CasRealm} on success.
+ *
+ * @param request HTTP request.
+ * @param response HTTP response.
+ *
+ * @return The authenticated principal on authentication success, otherwise
+ * null. In the case where authentication explicitly fails, either due to
+ * ticket validation failure or realm authentication failure, a 403 status
+ * code is set on the response. In cases where no existing CAS session exists,
+ * a 302 redirect is set on the response to redirect to the CAS server for
+ * authentication.
+ */
+ public final Principal authenticate(final HttpServletRequest request, final HttpServletResponse response) {
+ Assertion assertion = null;
+ HttpSession session = request.getSession();
+ if (session != null) {
+ assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
+ }
+ if (assertion == null) {
+ log.debug("CAS assertion not found in session -- authentication required.");
+ final String token = request.getParameter(this.artifactParameterName);
+ final String service = CommonUtils.constructServiceUrl(request, response, this.serviceUrl, this.serverName, this.artifactParameterName, true);
+ if (CommonUtils.isBlank(token)) {
+ final String redirectUrl = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.serviceParameterName, service, false, false);
+ log.debug("Redirecting to " + redirectUrl);
+ try {
+ response.sendRedirect(redirectUrl);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot redirect to " + redirectUrl, e);
+ }
+ return null;
+ }
+ try {
+ log.debug("Attempting to validate " + token + " for " + service);
+ assertion = this.ticketValidator.validate(token, service);
+ log.debug("CAS authentication succeeded.");
+ if (session == null) {
+ session = request.getSession(true);
+ }
+ session.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion);
+ } catch (final TicketValidationException e) {
+ setUnauthorized(response, e.getMessage());
+ return null;
+ }
+ }
+ Principal p = realm.authenticate(assertion.getPrincipal());
+ if (p == null) {
+ log.debug(assertion.getPrincipal().getName() + " failed to authenticate to " + realm);
+ setUnauthorized(response, null);
+ }
+ return p;
+ }
+
+ /**
+ * @return the serviceUrl
+ */
+ public String getServiceUrl() {
+ return serviceUrl;
+ }
+
+ /**
+ * @param serviceUrl the serviceUrl to set
+ */
+ public void setServiceUrl(final String serviceUrl) {
+ this.serviceUrl = serviceUrl;
+ }
+
+ /**
+ * @return the serverName
+ */
+ public String getServerName() {
+ return serverName;
+ }
+
+ /**
+ * @param serverName the serverName to set
+ */
+ public void setServerName(final String serverName) {
+ this.serverName = serverName;
+ }
+
+ /**
+ * @return the casServerLoginUrl
+ */
+ public String getCasServerLoginUrl() {
+ return casServerLoginUrl;
+ }
+
+ /**
+ * @param casServerLoginUrl the casServerLoginUrl to set
+ */
+ public void setCasServerLoginUrl(final String casServerLoginUrl) {
+ this.casServerLoginUrl = casServerLoginUrl;
+ }
+
+ /**
+ * @return the ticketValidator
+ */
+ public TicketValidator getTicketValidator() {
+ return ticketValidator;
+ }
+
+ /**
+ * @param artifactParameterName the artifactParameterName to set
+ */
+ public void setArtifactParameterName(final String artifactParameterName) {
+ this.artifactParameterName = artifactParameterName;
+ }
+
+ /**
+ * @param serviceParameterName the serviceParameterName to set
+ */
+ public void setServiceParameterName(final String serviceParameterName) {
+ this.serviceParameterName = serviceParameterName;
+ }
+
+ /**
+ * @param ticketValidator the ticketValidator to set
+ */
+ public void setTicketValidator(final TicketValidator ticketValidator) {
+ this.ticketValidator = ticketValidator;
+ }
+
+ /**
+ * @param realm the realm to set
+ */
+ public void setRealm(final CasRealm realm) {
+ this.realm = realm;
+ }
+
+ private void setUnauthorized(final HttpServletResponse response, final String message) {
+ try {
+ if (message != null) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message);
+ } else {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Error setting 403 status.", e);
+ }
+ }
+}
diff --git a/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java
new file mode 100644
index 0000000..1fceae4
--- /dev/null
+++ b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/CasRealm.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.tomcat;
+
+import java.security.Principal;
+
+/**
+ * Describes Tomcat Realm implementations that do not require password
+ * for authentication.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public interface CasRealm {
+ /**
+ * Authenticates the given principal.
+ *
+ * @param p Principal to authenticate.
+ *
+ * @return New principal.
+ */
+ Principal authenticate(Principal p);
+
+ /**
+ * Gets the roles defined for the given principal.
+ *
+ * @return Roles for given principal or empty array if none exist.
+ */
+ String[] getRoles(Principal p);
+
+ /**
+ * Determines whether the given principal possesses the given role.
+ *
+ * @param principal Principal to evaluate.
+ * @param role Role to test for possession.
+ *
+ * @return True if principal has given role, false otherwise.
+ */
+ boolean hasRole(Principal principal, String role);
+}
diff --git a/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegate.java b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegate.java
new file mode 100644
index 0000000..ca3e843
--- /dev/null
+++ b/cas-client-integration-tomcat-common/src/main/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegate.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.tomcat;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.HashSet;
+
+import org.jasig.cas.client.util.CommonUtils;
+
+/**
+ * {@link CasRealm} implementation with users and roles defined by a properties
+ * file with the following format:
+ *
+ * username1=role1,role2,role3 + * username2=role1 + * username3=role2,role3 + *+ * User authentication succeeds if the name of the given principal exists as + * a username in the properties file. + * + * @author Middleware + * @version $Revision$ + * + */ +public class PropertiesCasRealmDelegate implements CasRealm { + /** Path to backing properties file */ + private String propertiesFilePath; + + /** Map of usernames to roles */ + private Map roleMap; + + /** + * @param path Path to properties file container username/role data. + */ + public void setPropertiesFilePath(final String path) { + propertiesFilePath = path; + } + + /** {@inheritDoc} */ + public void readProperties() + { + CommonUtils.assertNotNull(propertiesFilePath, "PropertiesFilePath not set."); + File file = new File(propertiesFilePath); + if (!file.isAbsolute()) { + file = new File(System.getProperty("catalina.base"), propertiesFilePath); + } + CommonUtils.assertTrue(file.exists(), "File not found " + file); + CommonUtils.assertTrue(file.canRead(), "Cannot read " + file); + final Properties properties = new Properties(); + try { + properties.load(new BufferedInputStream(new FileInputStream(file))); + } catch (IOException e) { + throw new IllegalStateException("Error loading users/roles from " + file, e); + } + roleMap = new HashMap(properties.size()); + final Iterator keys = properties.keySet().iterator(); + while (keys.hasNext()) { + final String user = (String) keys.next(); + // Use TreeSet to sort roles + final Set roleSet = new HashSet(); + final String[] roles = properties.getProperty(user).split(",\\s*"); + for (int i = 0; i < roles.length; i++) { + roleSet.add(roles[i]); + } + roleMap.put(user, roleSet); + } + } + + /** {@inheritDoc} */ + public Principal authenticate(final Principal p) { + if (roleMap.get(p.getName()) != null) { + return p; + } else { + return null; + } + } + + /** {@inheritDoc} */ + public String[] getRoles(final Principal p) { + final Set roleSet = (Set) roleMap.get(p.getName()); + final String[] roles = new String[roleSet.size()]; + roleSet.toArray(roles); + return roles; + } + + /** {@inheritDoc} */ + public boolean hasRole(final Principal principal, final String role) { + final Set roles = (Set) roleMap.get(principal.getName()); + if (roles != null) { + return roles.contains(role); + } else { + return false; + } + } +} diff --git a/cas-client-integration-tomcat-common/src/test/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegateTests.java b/cas-client-integration-tomcat-common/src/test/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegateTests.java new file mode 100644 index 0000000..6aad839 --- /dev/null +++ b/cas-client-integration-tomcat-common/src/test/java/org/jasig/cas/client/tomcat/PropertiesCasRealmDelegateTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license + * distributed with this file and available online at + * http://www.ja-sig.org/products/cas/overview/license/index.html + */ +package org.jasig.cas.client.tomcat; + +import java.security.Principal; + +import junit.framework.TestCase; + +import org.jasig.cas.client.authentication.AttributePrincipalImpl; + +/** + * Unit test for {@link PropertiesCasRealmDelegate} class. + * + * @author Middleware + * @version $Revision$ + * + */ +public class PropertiesCasRealmDelegateTests extends TestCase { + private PropertiesCasRealmDelegate realm = new PropertiesCasRealmDelegate(); + + /** {@inheritDoc} */ + protected void setUp() throws Exception { + super.setUp(); + realm.setPropertiesFilePath("src/test/resources/org/jasig/cas/client/tomcat/user-roles.properties"); + realm.readProperties(); + } + + public void testAuthenticate() { + final Principal p = new AttributePrincipalImpl("rosencrantz"); + assertTrue(p == realm.authenticate(p)); + } + + public void testGetRoles() { + final Principal p = new AttributePrincipalImpl("rosencrantz"); + final String[] expected = new String[] {"admins", "users"}; + final String[] actual = realm.getRoles(p); + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], actual[i]); + } + } + + public void testHasRole() { + assertTrue(realm.hasRole(new AttributePrincipalImpl("rosencrantz"), "admins")); + assertTrue(realm.hasRole(new AttributePrincipalImpl("rosencrantz"), "users")); + assertTrue(realm.hasRole(new AttributePrincipalImpl("guildenstern"), "users")); + } +} diff --git a/cas-client-integration-tomcat-common/src/test/resources/org/jasig/cas/client/tomcat/user-roles.properties b/cas-client-integration-tomcat-common/src/test/resources/org/jasig/cas/client/tomcat/user-roles.properties new file mode 100644 index 0000000..5e7558d --- /dev/null +++ b/cas-client-integration-tomcat-common/src/test/resources/org/jasig/cas/client/tomcat/user-roles.properties @@ -0,0 +1,2 @@ +rosencrantz=users,admins +guildenstern=users diff --git a/cas-client-integration-tomcat/pom.xml b/cas-client-integration-tomcat-v7/pom.xml similarity index 71% rename from cas-client-integration-tomcat/pom.xml rename to cas-client-integration-tomcat-v7/pom.xml index 76d487d..fc8e9de 100644 --- a/cas-client-integration-tomcat/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -10,11 +10,18 @@
Realm implementation for all CAS realms.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public abstract class AbstractCasRealm extends RealmBase implements CasRealm {
+ /** {@inheritDoc} */
+ public Principal authenticate(final Principal p) {
+ return getDelegate().authenticate(p);
+ }
+
+ /** {@inheritDoc} */
+ public String[] getRoles(final Principal p) {
+ return getDelegate().getRoles(p);
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasRole(final Principal principal, final String role) {
+ return getDelegate().hasRole(principal, role);
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return getName();
+ }
+
+ /** {@inheritDoc} */
+ public String getInfo() {
+ return getClass().getName() + "/1.0";
+ }
+
+ /** {@inheritDoc} */
+ protected String getName() {
+ return getClass().getSimpleName();
+ }
+
+ /** {@inheritDoc} */
+ protected String getPassword(final String username) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ protected Principal getPrincipal(String username) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @return Delegate that all {@link CasRealm} operations are delegated to.
+ */
+ protected abstract CasRealm getDelegate();
+}
diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractLogoutValveBase.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AbstractLogoutValveBase.java
similarity index 98%
rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractLogoutValveBase.java
rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AbstractLogoutValveBase.java
index 461a0ba..6eb30b9 100644
--- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractLogoutValveBase.java
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AbstractLogoutValveBase.java
@@ -3,7 +3,7 @@
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
-package org.jasig.cas.client.tomcat;
+package org.jasig.cas.client.tomcat.v7;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
diff --git a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AssertionCasRealm.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AssertionCasRealm.java
new file mode 100644
index 0000000..02b3cfe
--- /dev/null
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/AssertionCasRealm.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.tomcat.v7;
+
+import org.jasig.cas.client.tomcat.AssertionCasRealmDelegate;
+import org.jasig.cas.client.tomcat.CasRealm;
+
+/**
+ * Tomcat Realm that implements {@link CasRealm} for principal and
+ * role data backed by the CAS {@link Assertion}.
+ *
+ * Authentication always succeeds and simply returns the given principal.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$
+ *
+ */
+public class AssertionCasRealm extends AbstractCasRealm {
+ private final AssertionCasRealmDelegate delegate = new AssertionCasRealmDelegate();
+
+ /**
+ * @param name Name of the attribute in the principal that contains role data.
+ */
+ public void setRoleAttributeName(final String name) {
+ delegate.setRoleAttributeName(name);
+ }
+
+ /** {@inheritDoc} */
+ protected CasRealm getDelegate() {
+ return delegate;
+ }
+}
diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas10CasAuthenticator.java
similarity index 74%
rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java
rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas10CasAuthenticator.java
index d5503df..a162bd5 100644
--- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas10CasAuthenticator.java
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas10CasAuthenticator.java
@@ -3,30 +3,34 @@
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
-package org.jasig.cas.client.tomcat;
+package org.jasig.cas.client.tomcat.v7;
import org.apache.catalina.LifecycleException;
import org.jasig.cas.client.validation.Cas10TicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
/**
- * Authenticator that handles CAS 1.0 responses.
+ * Authenticator that handles CAS 1.0 protocol.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1.12
*/
public class Cas10CasAuthenticator extends AbstractCasAuthenticator {
+ public static final String AUTH_METHOD = "CAS10";
- private TicketValidator ticketValidator;
+ private Cas10TicketValidator ticketValidator;
protected TicketValidator getTicketValidator() {
return this.ticketValidator;
}
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
protected void startInternal() throws LifecycleException {
super.startInternal();
-
this.ticketValidator = new Cas10TicketValidator(getCasServerUrlPrefix());
}
}
diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20CasAuthenticator.java
similarity index 83%
rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java
rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20CasAuthenticator.java
index aa6e094..051fb32 100644
--- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20CasAuthenticator.java
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20CasAuthenticator.java
@@ -3,26 +3,31 @@
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
-package org.jasig.cas.client.tomcat;
+package org.jasig.cas.client.tomcat.v7;
import org.apache.catalina.LifecycleException;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
/**
- * Authenticator that handles the CAS 2 protocol.
+ * Authenticator that handles the CAS 2.0 protocol.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1.12
*/
public final class Cas20CasAuthenticator extends AbstractCasAuthenticator {
-
+ public static final String AUTH_METHOD = "CAS20";
+
private Cas20ServiceTicketValidator ticketValidator;
protected TicketValidator getTicketValidator() {
return this.ticketValidator;
}
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
protected void startInternal() throws LifecycleException {
super.startInternal();
diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20ProxyCasAuthenticator.java
similarity index 86%
rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java
rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20ProxyCasAuthenticator.java
index da21299..7b8b618 100644
--- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/Cas20ProxyCasAuthenticator.java
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Cas20ProxyCasAuthenticator.java
@@ -3,7 +3,7 @@
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/index.html
*/
-package org.jasig.cas.client.tomcat;
+package org.jasig.cas.client.tomcat.v7;
import org.apache.catalina.LifecycleException;
import org.jasig.cas.client.util.CommonUtils;
@@ -11,14 +11,17 @@ import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
/**
+ * Authenticator that handles the CAS 2.0 protocol with proxying support.
+ *
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1.12
*/
public final class Cas20ProxyCasAuthenticator extends AbstractCasAuthenticator {
+ public static final String AUTH_METHOD = "CAS20-PROXY";
private Cas20ProxyTicketValidator ticketValidator;
-
+
private boolean acceptAnyProxy;
private String allowedProxyChains;
@@ -34,10 +37,13 @@ public final class Cas20ProxyCasAuthenticator extends AbstractCasAuthenticator {
protected TicketValidator getTicketValidator() {
return this.ticketValidator;
}
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
protected void startInternal() throws LifecycleException {
super.startInternal();
-
this.ticketValidator = new Cas20ProxyTicketValidator(getCasServerUrlPrefix());
this.ticketValidator.setRenew(isRenew());
this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl());
diff --git a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/PropertiesCasRealm.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/PropertiesCasRealm.java
new file mode 100644
index 0000000..289fee7
--- /dev/null
+++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/PropertiesCasRealm.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license
+ * distributed with this file and available online at
+ * http://www.ja-sig.org/products/cas/overview/license/index.html
+ */
+package org.jasig.cas.client.tomcat.v7;
+
+import org.apache.catalina.LifecycleException;
+import org.jasig.cas.client.tomcat.CasRealm;
+import org.jasig.cas.client.tomcat.PropertiesCasRealmDelegate;
+
+/**
+ * Tomcat Realm that implements {@link CasRealm} backed by properties file
+ * containing usernames/and roles of the following format:
+ *
+ * username1=role1,role2,role3 + * username2=role1 + * username3=role2,role3 + *+ * User authentication succeeds if the name of the given principal exists as + * a username in the properties file. + * + * @author Marvin S. Addison + * @version $Revision$ + * + */ +public class PropertiesCasRealm extends AbstractCasRealm { + private final PropertiesCasRealmDelegate delegate = new PropertiesCasRealmDelegate(); + + /** + * @param path Path to properties file container username/role data. + */ + public void setPropertiesFilePath(final String path) { + delegate.setPropertiesFilePath(path); + } + + /** {@inheritDoc} */ + protected void startInternal() throws LifecycleException { + super.startInternal(); + delegate.readProperties(); + } + + /** {@inheritDoc} */ + protected CasRealm getDelegate() { + return delegate; + } + +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/ProxyCallbackValve.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/ProxyCallbackValve.java similarity index 98% rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/ProxyCallbackValve.java rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/ProxyCallbackValve.java index 5ed5035..378bc2a 100644 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/ProxyCallbackValve.java +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/ProxyCallbackValve.java @@ -3,7 +3,7 @@ * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/index.html */ -package org.jasig.cas.client.tomcat; +package org.jasig.cas.client.tomcat.v7; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/RegExpBasedLogoutValue.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/RegExpBasedLogoutValue.java similarity index 97% rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/RegExpBasedLogoutValue.java rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/RegExpBasedLogoutValue.java index 6f2f75b..06c15b9 100644 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/RegExpBasedLogoutValue.java +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/RegExpBasedLogoutValue.java @@ -3,7 +3,7 @@ * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/index.html */ -package org.jasig.cas.client.tomcat; +package org.jasig.cas.client.tomcat.v7; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; diff --git a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Saml11Authenticator.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Saml11Authenticator.java new file mode 100644 index 0000000..d4b84c6 --- /dev/null +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/Saml11Authenticator.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 The JA-SIG Collaborative. All rights reserved. See license + * distributed with this file and available online at + * http://www.ja-sig.org/products/cas/overview/license/index.html + */ +package org.jasig.cas.client.tomcat.v7; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Saml11TicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * CAS authenticator that uses the SAML 1.1 protocol. + * + * @author Marvin S. Addison + * @version $Revision$ + * + */ +public class Saml11Authenticator extends AbstractAuthenticator { + public static final String AUTH_METHOD = "SAML11"; + + private Saml11TicketValidator ticketValidator; + + /** SAML protocol clock drift tolerance in ms */ + private int tolerance = -1; + + + /** + * @param ms SAML clock drift tolerance in milliseconds. + */ + public void setTolerance(final int ms) { + this.tolerance = ms; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Saml11TicketValidator(getCasServerUrlPrefix()); + if (this.tolerance > -1) { + this.ticketValidator.setTolerance(this.tolerance); + } + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + this.ticketValidator.setRenew(isRenew()); + } + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected String getAuthenticationMethod() { + return AUTH_METHOD; + } + + /** {@inheritDoc} */ + protected String getArtifactParameterName() { + return "SAMLart"; + } + + /** {@inheritDoc} */ + protected String getServiceParameterName() { + return "TARGET"; + } + +} diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/UrlBasedLogoutValve.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/UrlBasedLogoutValve.java similarity index 97% rename from cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/UrlBasedLogoutValve.java rename to cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/UrlBasedLogoutValve.java index 737198d..42af52e 100644 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/UrlBasedLogoutValve.java +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/UrlBasedLogoutValve.java @@ -3,7 +3,7 @@ * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/index.html */ -package org.jasig.cas.client.tomcat; +package org.jasig.cas.client.tomcat.v7; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; diff --git a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java b/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java deleted file mode 100644 index 3cf0702..0000000 --- a/cas-client-integration-tomcat/src/main/java/org/jasig/cas/client/tomcat/AbstractAuthenticator.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license - * distributed with this file and available online at - * http://www.ja-sig.org/products/cas/overview/license/index.html - */ -package org.jasig.cas.client.tomcat; - -import org.apache.catalina.LifecycleException; -import org.apache.catalina.authenticator.AuthenticatorBase; -import org.apache.catalina.authenticator.Constants; -import org.apache.catalina.connector.Request; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jasig.cas.client.util.AbstractCasFilter; -import org.jasig.cas.client.util.CommonUtils; -import org.jasig.cas.client.validation.Assertion; -import org.jasig.cas.client.validation.TicketValidationException; -import org.jasig.cas.client.validation.TicketValidator; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.security.Principal; - -/** - * @author Scott Battaglia - * @version $Revision$ $Date$ - * @since 3.1.12 - */ -public abstract class AbstractAuthenticator extends AuthenticatorBase { - - private static final String INFO = "org.jasig.cas.client.tomcat.AbstractAuthenticator/1.0"; - - private static final Log log = LogFactory.getLog(AbstractAuthenticator.class); - - private String casServerLoginUrl; - - private String casServerUrlPrefix; - - private boolean encode; - - private boolean renew; - - protected abstract String getArtifactParameterName(); - - protected abstract String getServiceParameterName(); - - protected abstract TicketValidator getTicketValidator(); - - private String serverName; - - private String serviceUrl; - - protected final String getCasServerUrlPrefix() { - return this.casServerUrlPrefix; - } - - protected void startInternal() throws LifecycleException { - super.startInternal(); - try { - CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); - CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null."); - CommonUtils.assertTrue(this.serverName != null || this.serviceUrl != null, "either serverName or serviceUrl must be set."); - - } catch (final Exception e) { - throw new LifecycleException(e); - } - } - - public final void setCasServerUrlPrefix(final String casServerUrlPrefix) { - this.casServerUrlPrefix = casServerUrlPrefix; - } - - public final void setCasServerLoginUrl(final String casServerLoginUrl) { - this.casServerLoginUrl = casServerLoginUrl; - } - - public final boolean isEncode() { - return this.encode; - } - - public final void setEncode(final boolean encode) { - this.encode = encode; - } - - protected final boolean isRenew() { - return this.renew; - } - - public void setRenew(final boolean renew) { - this.renew = renew; - } - - - public final void setServerName(final String serverName) { - this.serverName = serverName; - } - - public final void setServiceUrl(final String serviceUrl) { - this.serviceUrl = serviceUrl; - } - - public final String getInfo() { - return INFO; - } - - public final boolean authenticate(final Request request, final HttpServletResponse response, final LoginConfig loginConfig) throws IOException { - final Principal principal = request.getUserPrincipal(); - final String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - - if (principal != null && ssoId != null) { - associate(ssoId, request.getSessionInternal(true)); - return true; - } - - if (ssoId != null && reauthenticateFromSSO(ssoId, request)) { - return true; - } - - - final String token = request.getParameter(getArtifactParameterName()); - final String service = CommonUtils.constructServiceUrl(request, response, this.serviceUrl, this.serverName, getArtifactParameterName(), true); - - if (CommonUtils.isBlank(token)) { - final String redirectUrl = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), service, false, false); - response.sendRedirect(redirectUrl); - return false; - } - - try { - final Assertion newAssertion = getTicketValidator().validate(token, service); - request.getSession(true).setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, newAssertion); - final Principal p = context.getRealm().authenticate(newAssertion.getPrincipal().getName(), null); - - if (p != null) { - register(request, response, p, Constants.SINGLE_SIGN_ON_COOKIE, p.getName(), null); - return true; - } - } catch (final TicketValidationException e) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); - return false; - } - - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - return false; - } -} diff --git a/pom.xml b/pom.xml index cfa095a..e16d992 100644 --- a/pom.xml +++ b/pom.xml @@ -139,7 +139,8 @@