diff --git a/cas-client-integration-tomcat-v8/NOTICE b/cas-client-integration-tomcat-v8/NOTICE
new file mode 100644
index 0000000..f5ce3c0
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/NOTICE
@@ -0,0 +1,30 @@
+Licensed to Apereo under one or more contributor license
+agreements. See the NOTICE file distributed with this work
+for additional information regarding copyright ownership.
+Apereo licenses this file to you under the Apache License,
+Version 2.0 (the "License"); you may not use this file
+except in compliance with the License. You may obtain a
+copy of the License at the following location:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+This project includes:
+ Jasig CAS Client for Java - Common Tomcat Integration Support under Apache License Version 2.0
+ Jasig CAS Client for Java - Core under Apache License Version 2.0
+ Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0
+ Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0
+ Java Servlet API under CDDL + GPLv2 with classpath exception
+ JCL 1.1.1 implemented over SLF4J under MIT License
+ Joda-Time under Apache 2
+ JUnit under Common Public License Version 1.0
+ SLF4J API Module under MIT License
+ SLF4J Simple Binding under MIT License
+ tomcat-catalina under Apache License, Version 2.0
+
diff --git a/cas-client-integration-tomcat-v8/pom.xml b/cas-client-integration-tomcat-v8/pom.xml
new file mode 100644
index 0000000..531abde
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/pom.xml
@@ -0,0 +1,70 @@
+
+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);
+ }
+
+ public boolean hasRole(final Principal principal, final String role) {
+ return getDelegate().hasRole(principal, role);
+ }
+
+ /**
+ * Tomcat 7.0.8 changed their APIs so {@link #hasRole(java.security.Principal, String)} is only valid for 7.0.7 and below.
+ */
+ public boolean hasRole(final Wrapper wrapper, final Principal principal, final String role) {
+ return 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(final 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-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java
new file mode 100644
index 0000000..4264c0d
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.valves.ValveBase;
+import org.jasig.cas.client.tomcat.LogoutHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for Container-managed log out. Removes the attributes
+ * from the session.
+ *
+ * @author Scott Battaglia
+ * @author Marvin S. Addison
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ */
+public abstract class AbstractLogoutValve extends ValveBase {
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ public final void invoke(final Request request, final Response response) throws IOException, ServletException {
+ if (getLogoutHandler().isLogoutRequest(request)) {
+ getLogoutHandler().logout(request, response);
+ // Do not proceed up valve chain
+ return;
+ }
+
+ logger.debug("URI is not a logout request: {}", request.getRequestURI());
+ getNext().invoke(request, response);
+ }
+
+ protected abstract LogoutHandler getLogoutHandler();
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java
new file mode 100644
index 0000000..422f48a
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+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 org.jasig.cas.client.validation.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-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java
new file mode 100644
index 0000000..a518343
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+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 protocol.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ */
+public final class Cas10CasAuthenticator extends AbstractCasAuthenticator {
+
+ public static final String AUTH_METHOD = "CAS10";
+
+ private static final String NAME = Cas10CasAuthenticator.class.getName();
+
+ private Cas10TicketValidator ticketValidator;
+
+ protected TicketValidator getTicketValidator() {
+ return this.ticketValidator;
+ }
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
+
+ protected String getName() {
+ return NAME;
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ this.ticketValidator = new Cas10TicketValidator(getCasServerUrlPrefix());
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java
new file mode 100644
index 0000000..86d40b4
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+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.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 static final String NAME = Cas20CasAuthenticator.class.getName();
+
+ private Cas20ServiceTicketValidator ticketValidator;
+
+ protected TicketValidator getTicketValidator() {
+ return this.ticketValidator;
+ }
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
+
+ protected String getName() {
+ return NAME;
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ this.ticketValidator = new Cas20ServiceTicketValidator(getCasServerUrlPrefix());
+ if (getEncoding() != null) {
+ this.ticketValidator.setEncoding(getEncoding());
+ }
+ this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl());
+ this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage());
+ this.ticketValidator.setRenew(isRenew());
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java
new file mode 100644
index 0000000..b5fa702
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+import org.apache.catalina.LifecycleException;
+import org.jasig.cas.client.util.CommonUtils;
+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 static final String NAME = Cas20ProxyCasAuthenticator.class.getName();
+
+ private Cas20ProxyTicketValidator ticketValidator;
+
+ private boolean acceptAnyProxy;
+
+ private String allowedProxyChains;
+
+ public void setAcceptAnyProxy(final boolean acceptAnyProxy) {
+ this.acceptAnyProxy = acceptAnyProxy;
+ }
+
+ public void setAllowedProxyChains(final String allowedProxyChains) {
+ this.allowedProxyChains = allowedProxyChains;
+ }
+
+ protected TicketValidator getTicketValidator() {
+ return this.ticketValidator;
+ }
+
+ protected String getAuthenticationMethod() {
+ return AUTH_METHOD;
+ }
+
+ protected String getName() {
+ return NAME;
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ this.ticketValidator = new Cas20ProxyTicketValidator(getCasServerUrlPrefix());
+ this.ticketValidator.setRenew(isRenew());
+ this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl());
+ this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage());
+ this.ticketValidator.setAcceptAnyProxy(this.acceptAnyProxy);
+ this.ticketValidator.setAllowedProxyChains(CommonUtils.createProxyList(this.allowedProxyChains));
+ if (getEncoding() != null) {
+ this.ticketValidator.setEncoding(getEncoding());
+ }
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java
new file mode 100644
index 0000000..9cbe8ea
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+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$ + * @since 3.1.12 + * + */ +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) { + this.delegate.setPropertiesFilePath(path); + } + + /** {@inheritDoc} */ + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.delegate.readProperties(); + } + + /** {@inheritDoc} */ + protected CasRealm getDelegate() { + return this.delegate; + } + +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java new file mode 100644 index 0000000..adc98cc --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java @@ -0,0 +1,90 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.ReflectUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles watching a url for the proxy callback. + *
+ * Because its tough to share state between valves, we expose the storage mechanism via a static variable. + *
+ * This valve should be ordered before the authentication valves.
+ *
+ * @author Scott Battaglia
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ */
+public final class ProxyCallbackValve extends ValveBase {
+
+ private static ProxyGrantingTicketStorage PROXY_GRANTING_TICKET_STORAGE;
+
+ /** Logger instance */
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private String proxyGrantingTicketStorageClass;
+
+ private String proxyCallbackUrl;
+
+ public static ProxyGrantingTicketStorage getProxyGrantingTicketStorage() {
+ return PROXY_GRANTING_TICKET_STORAGE;
+ }
+
+ public void setProxyGrantingTicketStorageClass(final String proxyGrantingTicketStorageClass) {
+ this.proxyGrantingTicketStorageClass = proxyGrantingTicketStorageClass;
+ }
+
+ public void setProxyCallbackUrl(final String proxyCallbackUrl) {
+ this.proxyCallbackUrl = proxyCallbackUrl;
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+
+ try {
+ CommonUtils.assertNotNull(this.proxyCallbackUrl, "the proxy callback url cannot be null");
+ CommonUtils.assertTrue(this.proxyCallbackUrl.startsWith("/"), "proxy callback url must start with \"/\"");
+
+ PROXY_GRANTING_TICKET_STORAGE = ReflectUtils.newInstance(proxyGrantingTicketStorageClass);
+ } catch (final Exception e) {
+ throw new LifecycleException(e);
+ }
+ logger.info("Startup completed.");
+ }
+
+ public void invoke(final Request request, final Response response) throws IOException, ServletException {
+ if (this.proxyCallbackUrl.equals(request.getRequestURI())) {
+ logger.debug("Processing proxy callback request.");
+ CommonUtils.readAndRespondToProxyReceptorRequest(request, response, PROXY_GRANTING_TICKET_STORAGE);
+ return;
+ }
+
+ getNext().invoke(request, response);
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java
new file mode 100644
index 0000000..fc8999f
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+import org.apache.catalina.LifecycleException;
+import org.jasig.cas.client.tomcat.LogoutHandler;
+import org.jasig.cas.client.tomcat.RegexUriLogoutHandler;
+
+/**
+ * Performs CAS logout when the request URI matches a regular expression.
+ *
+ * @author Scott Battaglia
+ * @author Marvin S. Addison
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ */
+public final class RegexUriLogoutValve extends AbstractLogoutValve {
+
+ private RegexUriLogoutHandler logoutHandler = new RegexUriLogoutHandler();
+
+ public void setRedirectUrl(final String redirectUrl) {
+ this.logoutHandler.setRedirectUrl(redirectUrl);
+ }
+
+ public void setLogoutUriRegex(final String regex) {
+ this.logoutHandler.setLogoutUriRegex(regex);
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ this.logoutHandler.init();
+ logger.info("Startup completed.");
+ }
+
+ /** {@inheritDoc} */
+ protected LogoutHandler getLogoutHandler() {
+ return this.logoutHandler;
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java
new file mode 100644
index 0000000..fc44569
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+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$
+ * @since 3.1.12
+ *
+ */
+public final class Saml11Authenticator extends AbstractAuthenticator {
+
+ public static final String AUTH_METHOD = "SAML11";
+
+ private static final String NAME = Saml11Authenticator.class.getName();
+
+ 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";
+ }
+
+ protected String getName() {
+ return NAME;
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java
new file mode 100644
index 0000000..02fe955
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.valves.ValveBase;
+import org.jasig.cas.client.session.SessionMappingStorage;
+import org.jasig.cas.client.session.SingleSignOutHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles logout request messages sent from the CAS server by ending the current
+ * HTTP session.
+ *
+ * @author Marvin S. Addison
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ *
+ */
+public class SingleSignOutValve extends ValveBase implements SessionListener {
+
+ /** Logger instance */
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final SingleSignOutHandler handler = new SingleSignOutHandler();
+
+ public void setArtifactParameterName(final String name) {
+ this.handler.setArtifactParameterName(name);
+ }
+
+ public void setLogoutParameterName(final String name) {
+ this.handler.setLogoutParameterName(name);
+ }
+
+ public void setFrontLogoutParameterName(final String name) {
+ this.handler.setFrontLogoutParameterName(name);
+ }
+
+ public void setRelayStateParameterName(final String name) {
+ this.handler.setRelayStateParameterName(name);
+ }
+
+ public void setCasServerUrlPrefix(final String casServerUrlPrefix) {
+ this.handler.setCasServerUrlPrefix(casServerUrlPrefix);
+ }
+
+ public void setSessionMappingStorage(final SessionMappingStorage storage) {
+ this.handler.setSessionMappingStorage(storage);
+ }
+
+ /** {@inheritDoc} */
+ public void invoke(final Request request, final Response response) throws IOException, ServletException {
+ if (this.handler.process(request, response)) {
+ getNext().invoke(request, response);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void sessionEvent(final SessionEvent event) {
+ if (Session.SESSION_DESTROYED_EVENT.equals(event.getType())) {
+ logger.debug("Cleaning up SessionMappingStorage on destroySession event");
+ this.handler.getSessionMappingStorage().removeBySessionById(event.getSession().getId());
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ logger.info("Starting...");
+ this.handler.init();
+ logger.info("Startup completed.");
+ }
+}
diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java
new file mode 100644
index 0000000..516f331
--- /dev/null
+++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at the following location:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jasig.cas.client.tomcat.v8;
+
+import org.apache.catalina.LifecycleException;
+import org.jasig.cas.client.tomcat.LogoutHandler;
+import org.jasig.cas.client.tomcat.StaticUriLogoutHandler;
+
+/**
+ * Monitors a specific request URI for logout requests.
+ *
+ * @author Scott Battaglia
+ * @author Marvin S. Addison
+ * @version $Revision$ $Date$
+ * @since 3.1.12
+ */
+public final class StaticUriLogoutValve extends AbstractLogoutValve {
+
+ private StaticUriLogoutHandler logoutHandler = new StaticUriLogoutHandler();
+
+ public void setRedirectUrl(final String redirectUrl) {
+ this.logoutHandler.setRedirectUrl(redirectUrl);
+ }
+
+ public void setLogoutUri(final String logoutUri) {
+ this.logoutHandler.setLogoutUri(logoutUri);
+ }
+
+ protected void startInternal() throws LifecycleException {
+ super.startInternal();
+ this.logoutHandler.init();
+ logger.info("Startup completed.");
+ }
+
+ /** {@inheritDoc} */
+ protected LogoutHandler getLogoutHandler() {
+ return this.logoutHandler;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 99bfe01..7a16ddc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -252,6 +252,7 @@