From b4fbf23361af5cca70a85f5fa69c872402c65ab8 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 6 May 2014 22:12:59 -0400 Subject: [PATCH 01/57] CASC-224 Public API Method Removed without Deprecation Problem: Previous versions of the CAS Client remove a public API method without sufficient deprecation time resulting in problems for clients who want to upgrade. Solution: Add Method back and mark it as deprecated. --- .../org/jasig/cas/client/util/CommonUtils.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index b483c56..2e96283 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.ssl.HttpURLConnectionFactory; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; import org.jasig.cas.client.validation.ProxyList; import org.jasig.cas.client.validation.ProxyListEditor; import org.slf4j.Logger; @@ -55,6 +56,8 @@ public final class CommonUtils { */ private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId"; + private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory(); + private CommonUtils() { // nothing to do } @@ -348,6 +351,19 @@ public final class CommonUtils { return safeGetParameter(request, parameter, Arrays.asList("logoutRequest")); } + + /** + * Contacts the remote URL and returns the response. + * + * @param constructedUrl the url to contact. + * @param encoding the encoding to use. + * @return the response. + */ + @Deprecated + public static String getResponseFromServer(final URL constructedUrl, final String encoding) { + return getResponseFromServer(constructedUrl, DEFAULT_URL_CONNECTION_FACTORY, encoding); + } + /** * Contacts the remote URL and returns the response. * From 2c9090155afba75b9f2d94717e97e666e896b686 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 6 May 2014 22:35:55 -0400 Subject: [PATCH 02/57] CASC-223 SingleSignOutFilter requires init method to be called which changes the contract with previous versions Problem: Some clients such as Spring Security configure the filter via Spring configuration, meaning the handler's init method is not called vai the Filter#init method. Solution: For now, have an atomic boolean to determine if init was called or not and call it if necessary as part of the flow. --- .../client/session/SingleSignOutFilter.java | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index 33b2094..c9243e9 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -19,6 +19,7 @@ package org.jasig.cas.client.session; import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -34,49 +35,52 @@ import org.jasig.cas.client.util.AbstractConfigurationFilter; */ public final class SingleSignOutFilter extends AbstractConfigurationFilter { - private static final SingleSignOutHandler handler = new SingleSignOutHandler(); + private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler(); + + private AtomicBoolean handlerInitialized = new AtomicBoolean(false); public void init(final FilterConfig filterConfig) throws ServletException { if (!isIgnoreInitConfiguration()) { - handler.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", + HANDLER.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME)); - handler.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName", + HANDLER.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName", SingleSignOutHandler.DEFAULT_LOGOUT_PARAMETER_NAME)); - handler.setFrontLogoutParameterName(getPropertyFromInitParams(filterConfig, "frontLogoutParameterName", + HANDLER.setFrontLogoutParameterName(getPropertyFromInitParams(filterConfig, "frontLogoutParameterName", SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME)); - handler.setRelayStateParameterName(getPropertyFromInitParams(filterConfig, "relayStateParameterName", + HANDLER.setRelayStateParameterName(getPropertyFromInitParams(filterConfig, "relayStateParameterName", SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME)); - handler.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null)); - handler.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig, + HANDLER.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null)); + HANDLER.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig, "artifactParameterOverPost", "false"))); - handler.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig, + HANDLER.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig, "eagerlyCreateSessions", "true"))); } - handler.init(); + HANDLER.init(); + handlerInitialized.set(true); } public void setArtifactParameterName(final String name) { - handler.setArtifactParameterName(name); + HANDLER.setArtifactParameterName(name); } public void setLogoutParameterName(final String name) { - handler.setLogoutParameterName(name); + HANDLER.setLogoutParameterName(name); } public void setFrontLogoutParameterName(final String name) { - handler.setFrontLogoutParameterName(name); + HANDLER.setFrontLogoutParameterName(name); } public void setRelayStateParameterName(final String name) { - handler.setRelayStateParameterName(name); + HANDLER.setRelayStateParameterName(name); } public void setCasServerUrlPrefix(final String casServerUrlPrefix) { - handler.setCasServerUrlPrefix(casServerUrlPrefix); + HANDLER.setCasServerUrlPrefix(casServerUrlPrefix); } public void setSessionMappingStorage(final SessionMappingStorage storage) { - handler.setSessionMappingStorage(storage); + HANDLER.setSessionMappingStorage(storage); } public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, @@ -84,7 +88,15 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; - if (handler.process(request, response)) { + /** + *

Workaround for now for the fact that Spring Security will fail since it doesn't call {@link #init(javax.servlet.FilterConfig)}.

+ *

Ultimately we need to allow deployers to actually inject their fully-initialized {@link org.jasig.cas.client.session.SingleSignOutHandler}.

+ */ + if (!this.handlerInitialized.getAndSet(true)) { + HANDLER.init(); + } + + if (HANDLER.process(request, response)) { filterChain.doFilter(servletRequest, servletResponse); } } @@ -94,6 +106,6 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { } protected static SingleSignOutHandler getSingleSignOutHandler() { - return handler; + return HANDLER; } } From a4e984e4ea9e98d6b7bc014c20a11c5b5b7583d8 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 6 May 2014 22:53:05 -0400 Subject: [PATCH 03/57] Synchronize the init method in case we have multiple concurrent requests at the same time. --- .../client/session/SingleSignOutHandler.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index c93d9b3..5f8b46c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -132,18 +132,20 @@ public final class SingleSignOutHandler { /** * Initializes the component for use. */ - public void init() { - CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null."); - CommonUtils.assertNotNull(this.logoutParameterName, "logoutParameterName cannot be null."); - CommonUtils.assertNotNull(this.frontLogoutParameterName, "frontLogoutParameterName cannot be null."); - CommonUtils.assertNotNull(this.sessionMappingStorage, "sessionMappingStorage cannot be null."); - CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null."); - CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); + public synchronized void init() { + if (this.safeParameters == null) { + CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null."); + CommonUtils.assertNotNull(this.logoutParameterName, "logoutParameterName cannot be null."); + CommonUtils.assertNotNull(this.frontLogoutParameterName, "frontLogoutParameterName cannot be null."); + CommonUtils.assertNotNull(this.sessionMappingStorage, "sessionMappingStorage cannot be null."); + CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null."); + CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); - if (this.artifactParameterOverPost) { - this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName); - } else { - this.safeParameters = Arrays.asList(this.logoutParameterName); + if (this.artifactParameterOverPost) { + this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName); + } else { + this.safeParameters = Arrays.asList(this.logoutParameterName); + } } } From a44b4c1229ff6e9b584b6c2b139d74dbbcfd1261 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 6 May 2014 23:17:32 -0400 Subject: [PATCH 04/57] Removed no-longer valid test. --- .../jasig/cas/client/session/SingleSignOutFilterTests.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java index 64114f9..7c91f8f 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java @@ -60,12 +60,6 @@ public class SingleSignOutFilterTests { response = new MockHttpServletResponse(); filterChain = new MockFilterChain(); } - - @Test(expected = IllegalArgumentException.class) - public void initWithoutCasServerUrlPrefix() throws ServletException { - filter = new SingleSignOutFilter(); - filter.init(new MockFilterConfig()); - } @Test public void tokenRequest() throws IOException, ServletException { From 9de2be91a2ed4f013900cb1facd4036c2f34d051 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Tue, 24 Jun 2014 18:44:45 -0400 Subject: [PATCH 05/57] CASC-228 URL Encode Paramaters Passed to Server via Validate Problem: We currently don't pass encoded values to the server, possibly resolving in parsing/extraction errors. Solution: URL Encode all values instead of just the service url. QA Notes: Added unit test. --- .../AbstractUrlBasedTicketValidator.java | 5 +++-- .../validation/Cas20ServiceTicketValidator.java | 2 +- .../validation/Cas10TicketValidatorTests.java | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index 3ea31bd..fab0581 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -110,7 +110,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator logger.debug("Placing URL parameters in map."); urlParameters.put("ticket", ticket); - urlParameters.put("service", encodeUrl(serviceUrl)); + urlParameters.put("service", serviceUrl); if (this.renew) { urlParameters.put("renew", "true"); @@ -144,7 +144,8 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator buffer.append(i++ == 0 ? "?" : "&"); buffer.append(key); buffer.append("="); - buffer.append(value); + final String encodedValue = encodeUrl(value); + buffer.append(encodedValue); } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java index 4380348..9ecc5b8 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java @@ -70,7 +70,7 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick * @param urlParameters the Map containing the existing parameters to send to the server. */ protected final void populateUrlAttributeMap(final Map urlParameters) { - urlParameters.put("pgtUrl", encodeUrl(this.proxyCallbackUrl)); + urlParameters.put("pgtUrl", this.proxyCallbackUrl); } protected String getUrlSuffix() { diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java index 7d07288..280e0eb 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidatorTests.java @@ -18,8 +18,7 @@ */ package org.jasig.cas.client.validation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.io.UnsupportedEncodingException; import org.jasig.cas.client.PublicTestHttpServer; import org.junit.Before; @@ -80,4 +79,15 @@ public final class Cas10TicketValidatorTests extends AbstractTicketValidatorTest // expected } } + + @Test + public void urlEncodedValues() { + final String ticket = "ST-1-owKEOtYJjg77iHcCQpkl-cas01.example.org%26%73%65%72%76%69%63%65%3d%68%74%74%70%25%33%41%25%32%46%25%32%46%31%32%37%2e%30%2e%30%2e%31%25%32%46%62%6f%72%69%6e%67%25%32%46%23"; + final String service = "foobar"; + final String url = this.ticketValidator.constructValidationUrl(ticket, service); + + final String encodedValue = this.ticketValidator.encodeUrl(ticket); + assertTrue(url.contains(encodedValue)); + assertFalse(url.contains(ticket)); + } } From 61a92c0e7f5adffdc2bffcf65e7d1f3124da8072 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Sun, 20 Jul 2014 20:31:35 -0400 Subject: [PATCH 06/57] CASC-224 Replace URL with String to remain compatible with Spring Security --- .../main/java/org/jasig/cas/client/util/CommonUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index 2e96283..3d99171 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -360,8 +360,12 @@ public final class CommonUtils { * @return the response. */ @Deprecated - public static String getResponseFromServer(final URL constructedUrl, final String encoding) { - return getResponseFromServer(constructedUrl, DEFAULT_URL_CONNECTION_FACTORY, encoding); + public static String getResponseFromServer(final String constructedUrl, final String encoding) { + try { + return getResponseFromServer(new URL(constructedUrl), DEFAULT_URL_CONNECTION_FACTORY, encoding); + } catch (final Exception e) { + throw new RuntimeException(e); + } } /** From d191ac8ee61229eeafe11275a3abc56f9b8ffe1a Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Sun, 3 Aug 2014 00:03:25 -0400 Subject: [PATCH 07/57] Added missing license header. --- .../client/session/LogoutMessageGenerator.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/LogoutMessageGenerator.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/LogoutMessageGenerator.java index 1ebc862..861fffc 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/LogoutMessageGenerator.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/LogoutMessageGenerator.java @@ -1,3 +1,21 @@ +/* + * 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.session; import java.nio.charset.Charset; From 112f068607571cd9106415605e219ab2b92edcf9 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Sun, 3 Aug 2014 00:22:14 -0400 Subject: [PATCH 08/57] [maven-release-plugin] prepare release cas-client-3.3.2 --- cas-client-core/pom.xml | 2 +- cas-client-integration-atlassian/pom.xml | 2 +- cas-client-integration-jboss/pom.xml | 2 +- cas-client-integration-tomcat-common/pom.xml | 2 +- cas-client-integration-tomcat-v6/pom.xml | 2 +- cas-client-integration-tomcat-v7/pom.xml | 2 +- cas-client-support-distributed-ehcache/pom.xml | 2 +- cas-client-support-distributed-memcached/pom.xml | 2 +- pom.xml | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 1482cc6..fb94ce2 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 83c039b..193ce9d 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index 6c5c96b..034f14f 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index 72be093..e2995f8 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 3ce7551..f209e9e 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 486d932..9dd454b 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index e6ee05f..9a9e6d6 100644 --- a/cas-client-support-distributed-ehcache/pom.xml +++ b/cas-client-support-distributed-ehcache/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 4.0.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index e20df13..7cd8132 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 4.0.0 diff --git a/pom.xml b/pom.xml index 8b08eb4..2201dd5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.3.2-SNAPSHOT + 3.3.2 cas-client pom @@ -26,7 +26,7 @@ scm:git:git@github.com:Jasig/java-cas-client.git scm:git:git@github.com:Jasig/java-cas-client.git https://github.com/Jasig/java-cas-client - HEAD + cas-client-3.3.2 2006 From aa3e07bd7959dd74e5772e07ce05536ce2584d41 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Sun, 3 Aug 2014 00:22:49 -0400 Subject: [PATCH 09/57] [maven-release-plugin] prepare for next development iteration --- cas-client-core/pom.xml | 2 +- cas-client-integration-atlassian/pom.xml | 2 +- cas-client-integration-jboss/pom.xml | 2 +- cas-client-integration-tomcat-common/pom.xml | 2 +- cas-client-integration-tomcat-v6/pom.xml | 2 +- cas-client-integration-tomcat-v7/pom.xml | 2 +- cas-client-support-distributed-ehcache/pom.xml | 2 +- cas-client-support-distributed-memcached/pom.xml | 2 +- pom.xml | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index fb94ce2..f37b084 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 193ce9d..d94bbd5 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index 034f14f..f2de056 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index e2995f8..e72e953 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index f209e9e..067fa1b 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 9dd454b..4139880 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index 9a9e6d6..d556557 100644 --- a/cas-client-support-distributed-ehcache/pom.xml +++ b/cas-client-support-distributed-ehcache/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT 4.0.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index 7cd8132..3143fdb 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 2201dd5..c51b43e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.3.2 + 3.3.3-SNAPSHOT cas-client pom @@ -26,7 +26,7 @@ scm:git:git@github.com:Jasig/java-cas-client.git scm:git:git@github.com:Jasig/java-cas-client.git https://github.com/Jasig/java-cas-client - cas-client-3.3.2 + HEAD 2006 From 42ce676ef079d97dc8a0f0a7e89d011712a4f86b Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Mon, 11 Aug 2014 22:09:27 -0400 Subject: [PATCH 10/57] CASC-225 Restore Removed Constructor for Backwards Compatibility Problem: We removed the two string constructor which breaks Spring Security compatibility. Solution: Add it back as deprecated so that Spring Security can upgrade. --- .../cas/client/proxy/Cas20ProxyRetriever.java | 13 ++++++++++++- .../org/jasig/cas/client/util/CommonUtils.java | 15 ++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java index 1146b48..e80304a 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java @@ -55,6 +55,11 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { /** Url connection factory to use when communicating with the server **/ private final HttpURLConnectionFactory urlConnectionFactory; + @Deprecated + public Cas20ProxyRetriever(final String casServerUrl, final String encoding) { + this(casServerUrl, encoding, null); + } + /** * Main Constructor. * @@ -75,7 +80,13 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { CommonUtils.assertNotNull(targetService, "targetService cannot be null."); final URL url = constructUrl(proxyGrantingTicketId, targetService); - final String response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding); + final String response; + + if (this.urlConnectionFactory != null) { + response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding); + } else { + response = CommonUtils.getResponseFromServer(url, this.encoding); + } final String error = XmlUtils.getTextForElement(response, "proxyFailure"); if (CommonUtils.isNotEmpty(error)) { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index 3d99171..555e601 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -361,11 +361,16 @@ public final class CommonUtils { */ @Deprecated public static String getResponseFromServer(final String constructedUrl, final String encoding) { - try { - return getResponseFromServer(new URL(constructedUrl), DEFAULT_URL_CONNECTION_FACTORY, encoding); - } catch (final Exception e) { - throw new RuntimeException(e); - } + try { + return getResponseFromServer(new URL(constructedUrl), DEFAULT_URL_CONNECTION_FACTORY, encoding); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + @Deprecated + public static String getResponseFromServer(final URL constructedUrl, final String encoding) { + return getResponseFromServer(constructedUrl, DEFAULT_URL_CONNECTION_FACTORY, encoding); } /** From b18dbfe0a93ce2393892d4e3bf88359bccc8abc6 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Mon, 11 Aug 2014 22:36:27 -0400 Subject: [PATCH 11/57] CASC-229 Make Front Channel SSO Optional so that backwards compatibility is maintained. Problem: Spring Security adopters will fail to be able to drop in a new version of CAS Client for Java if this feature is enabled by default/required. Solution: Force a fail-safe optional mode if the value is not provided. --- .../jasig/cas/client/session/SingleSignOutFilter.java | 2 +- .../cas/client/session/SingleSignOutHandler.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index c9243e9..bf91bf8 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -49,7 +49,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME)); HANDLER.setRelayStateParameterName(getPropertyFromInitParams(filterConfig, "relayStateParameterName", SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME)); - HANDLER.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null)); + HANDLER.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", "")); HANDLER.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig, "artifactParameterOverPost", "false"))); HANDLER.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig, diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index 5f8b46c..ee737d7 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -70,7 +70,7 @@ public final class SingleSignOutHandler { private String relayStateParameterName = DEFAULT_RELAY_STATE_PARAMETER_NAME; /** The prefix url of the CAS server */ - private String casServerUrlPrefix; + private String casServerUrlPrefix = ""; private boolean artifactParameterOverPost = false; @@ -141,6 +141,10 @@ public final class SingleSignOutHandler { CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null."); CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); + if (CommonUtils.isBlank(this.casServerUrlPrefix)) { + logger.warn("Front Channel single sign out redirects are disabled when the 'casServerUrlPrefix' value is not set."); + } + if (this.artifactParameterOverPost) { this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName); } else { @@ -176,14 +180,15 @@ public final class SingleSignOutHandler { } /** - * Determines whether the given request is a CAS front channel logout request. + * Determines whether the given request is a CAS front channel logout request. Front Channel log out requests are only supported + * when the 'casServerUrlPrefix' value is set. * * @param request HTTP request. * * @return True if request is logout request, false otherwise. */ private boolean isFrontChannelLogoutRequest(final HttpServletRequest request) { - return "GET".equals(request.getMethod()) + return "GET".equals(request.getMethod()) && CommonUtils.isNotBlank(this.casServerUrlPrefix) && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.frontLogoutParameterName)); } From a0f8845ecf5fcd19f4fdd0bb932b45c38041ac1c Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Mon, 11 Aug 2014 22:50:23 -0400 Subject: [PATCH 12/57] CASC-230 Call HttpServletRequest#logout() via Reflection to Improve Backwards Compatibility with Spring Security --- .../client/session/SingleSignOutHandler.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index 5f8b46c..07264c3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -18,11 +18,11 @@ */ package org.jasig.cas.client.session; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.zip.Inflater; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -78,6 +78,8 @@ public final class SingleSignOutHandler { private List safeParameters; + private Method httpRequestLogoutMethod = retrieveHttpRequestLogoutMethod(); + public void setSessionMappingStorage(final SessionMappingStorage storage) { this.sessionMappingStorage = storage; } @@ -306,11 +308,7 @@ public final class SingleSignOutHandler { } catch (final IllegalStateException e) { logger.debug("Error invalidating session.", e); } - try { - request.logout(); - } catch (final ServletException e) { - logger.debug("Error performing request.logout."); - } + executeHttpServletRequestLogoutIfPossible(request); } } } @@ -345,4 +343,22 @@ public final class SingleSignOutHandler { private boolean isMultipartRequest(final HttpServletRequest request) { return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart"); } + + private void executeHttpServletRequestLogoutIfPossible(final HttpServletRequest request) { + if (this.httpRequestLogoutMethod != null) { + try { + this.httpRequestLogoutMethod.invoke(request); + } catch (final Exception e) { + logger.debug("Error performing request.logout."); + } + } + } + + private static Method retrieveHttpRequestLogoutMethod() { + try { + return HttpServletRequest.class.getMethod("logout"); + } catch (final NoSuchMethodException e) { + return null; + } + } } From b34c4e104fe2827271b91d911ac993ced59f9fdc Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Mon, 11 Aug 2014 23:04:24 -0400 Subject: [PATCH 13/57] Updated code to abstract the reflection logic a bit more behind a strategy interface. --- .../client/session/SingleSignOutHandler.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index 07264c3..fe4bbc1 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -18,11 +18,11 @@ */ package org.jasig.cas.client.session; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.zip.Inflater; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -78,7 +78,7 @@ public final class SingleSignOutHandler { private List safeParameters; - private Method httpRequestLogoutMethod = retrieveHttpRequestLogoutMethod(); + private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy(); public void setSessionMappingStorage(final SessionMappingStorage storage) { this.sessionMappingStorage = storage; @@ -308,7 +308,7 @@ public final class SingleSignOutHandler { } catch (final IllegalStateException e) { logger.debug("Error invalidating session.", e); } - executeHttpServletRequestLogoutIfPossible(request); + this.logoutStrategy.logout(request); } } } @@ -344,21 +344,38 @@ public final class SingleSignOutHandler { return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart"); } - private void executeHttpServletRequestLogoutIfPossible(final HttpServletRequest request) { - if (this.httpRequestLogoutMethod != null) { + private static boolean isServlet30() { + try { + return HttpServletRequest.class.getMethod("logout") != null; + } catch (final NoSuchMethodException e) { + return false; + } + } + + + /** + * Abstracts the ways we can force logout with the Servlet spec. + */ + private interface LogoutStrategy { + + void logout(HttpServletRequest request); + } + + private class Servlet25LogoutStrategy implements LogoutStrategy { + + public void logout(final HttpServletRequest request) { + // nothing additional to do here + } + } + + private class Servlet30LogoutStrategy implements LogoutStrategy { + + public void logout(final HttpServletRequest request) { try { - this.httpRequestLogoutMethod.invoke(request); - } catch (final Exception e) { + request.logout(); + } catch (final ServletException e) { logger.debug("Error performing request.logout."); } } } - - private static Method retrieveHttpRequestLogoutMethod() { - try { - return HttpServletRequest.class.getMethod("logout"); - } catch (final NoSuchMethodException e) { - return null; - } - } } From f57f0ff09685982cabbfa519d2faebd300069f79 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 15 Aug 2014 08:48:05 -0400 Subject: [PATCH 14/57] Update notice files. --- NOTICE | 10 +++++----- cas-client-core/NOTICE | 2 +- cas-client-integration-atlassian/NOTICE | 6 +++--- cas-client-integration-jboss/NOTICE | 2 +- cas-client-integration-tomcat-common/NOTICE | 2 +- cas-client-integration-tomcat-v6/NOTICE | 2 +- cas-client-integration-tomcat-v7/NOTICE | 2 +- cas-client-support-distributed-ehcache/NOTICE | 2 +- cas-client-support-distributed-memcached/NOTICE | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/NOTICE b/NOTICE index 5de596c..44db3d1 100644 --- a/NOTICE +++ b/NOTICE @@ -16,21 +16,22 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License AOP alliance under Public Domain Apache Log4j under The Apache Software License, Version 2.0 Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Apache XML Security under The Apache Software License, Version 2.0 - Atlassian JIRA - Code - Core under Atlassian End User License - Atlassian Seraph under BSD License - atlassian-osuser under BSD License Bouncy Castle Provider under Bouncy Castle Licence catalina under Apache License, Version 2.0 Codec under The Apache Software License, Version 2.0 + com.atlassian.confluence:confluence under Atlassian End User License com.atlassian.event:atlassian-event under Atlassian End User License + com.atlassian.jira:jira-core under Atlassian End User License + com.atlassian.osuser:atlassian-osuser under Atlassian End User License + com.atlassian.seraph:atlassian-seraph under Atlassian End User License Commons Codec under The Apache Software License, Version 2.0 commons-collections under Apache License, Version 2.0 - Confluence Core under Atlassian End User License Ehcache Core under The Apache Software License, Version 2.0 ESAPI 2.0 under BSD or Creative Commons 3.0 BY-SA Google Collections Library under The Apache Software License, Version 2.0 @@ -49,7 +50,6 @@ This project includes: JavaBeans Activation Framework (JAF) under Common Development and Distribution License (CDDL) v1.0 JavaMail API under Common Development and Distribution License (CDDL) v1.0 JBoss Application Server Tomcat under lgpl - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-core/NOTICE b/cas-client-core/NOTICE index 68fc9d2..2297c6f 100644 --- a/cas-client-core/NOTICE +++ b/cas-client-core/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License AOP alliance under Public Domain Apache Log4j under The Apache Software License, Version 2.0 Apache Santuario under The Apache Software License, Version 2.0 @@ -30,7 +31,6 @@ This project includes: Java Servlet API under CDDL + GPLv2 with classpath exception JavaBeans Activation Framework (JAF) under Common Development and Distribution License (CDDL) v1.0 JavaMail API under Common Development and Distribution License (CDDL) v1.0 - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-integration-atlassian/NOTICE b/cas-client-integration-atlassian/NOTICE index 5d2091c..502f172 100644 --- a/cas-client-integration-atlassian/NOTICE +++ b/cas-client-integration-atlassian/NOTICE @@ -16,13 +16,14 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License AOP alliance under Public Domain Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Atlassian Event under Atlassian End User License Atlassian JIRA - Code - Core under Atlassian End User License - Atlassian Seraph under BSD License - atlassian-osuser under BSD License + Atlassian Seraph under Atlassian End User License + atlassian-osuser under Atlassian End User License Bouncy Castle Provider under Bouncy Castle Licence Codec under The Apache Software License, Version 2.0 commons-collections under Apache License, Version 2.0 @@ -33,7 +34,6 @@ This project includes: Jasig CAS Client for Java - Atlassian Integration under Apache License Version 2.0 Jasig CAS Client for Java - Core under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-integration-jboss/NOTICE b/cas-client-integration-jboss/NOTICE index 2feec28..d373708 100644 --- a/cas-client-integration-jboss/NOTICE +++ b/cas-client-integration-jboss/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -27,7 +28,6 @@ This project includes: Jasig CAS Client for Java - JBoss Integration under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception JBoss Application Server Tomcat under lgpl - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-integration-tomcat-common/NOTICE b/cas-client-integration-tomcat-common/NOTICE index 434c58a..7c109fc 100644 --- a/cas-client-integration-tomcat-common/NOTICE +++ b/cas-client-integration-tomcat-common/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -26,7 +27,6 @@ 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 Java Servlet API under CDDL + GPLv2 with classpath exception - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-integration-tomcat-v6/NOTICE b/cas-client-integration-tomcat-v6/NOTICE index bc86731..05565bb 100644 --- a/cas-client-integration-tomcat-v6/NOTICE +++ b/cas-client-integration-tomcat-v6/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -28,7 +29,6 @@ This project includes: Jasig CAS Client for Java - Core under Apache License Version 2.0 Jasig CAS Client for Java - Tomcat 6.x Integration under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-integration-tomcat-v7/NOTICE b/cas-client-integration-tomcat-v7/NOTICE index 0fe413f..c129bf4 100644 --- a/cas-client-integration-tomcat-v7/NOTICE +++ b/cas-client-integration-tomcat-v7/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -27,7 +28,6 @@ This project includes: Jasig CAS Client for Java - Core 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 - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-support-distributed-ehcache/NOTICE b/cas-client-support-distributed-ehcache/NOTICE index cef121a..e355d62 100644 --- a/cas-client-support-distributed-ehcache/NOTICE +++ b/cas-client-support-distributed-ehcache/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -27,7 +28,6 @@ This project includes: Jasig CAS Client for Java - Core under Apache License Version 2.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License diff --git a/cas-client-support-distributed-memcached/NOTICE b/cas-client-support-distributed-memcached/NOTICE index ba79611..2fe29a8 100644 --- a/cas-client-support-distributed-memcached/NOTICE +++ b/cas-client-support-distributed-memcached/NOTICE @@ -16,6 +16,7 @@ specific language governing permissions and limitations under the License. This project includes: + "Java Concurrency in Practice" book annotations under Creative Commons Attribution License Apache Santuario under The Apache Software License, Version 2.0 Apache Velocity under The Apache Software License, Version 2.0 Bouncy Castle Provider under Bouncy Castle Licence @@ -27,7 +28,6 @@ This project includes: Jasig CAS Client for Java - Distributed Proxy Storage Support: Memcached under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception - jcip-annotations under Creative Commons Attribution License JCL 1.1.1 implemented over SLF4J under MIT License Joda time under Apache 2 JUL to SLF4J bridge under MIT License From 0174cfbbb568ac20de145ed2863e6979d029b88d Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 15 Aug 2014 08:51:04 -0400 Subject: [PATCH 15/57] [maven-release-plugin] prepare release cas-client-3.3.3 --- cas-client-core/pom.xml | 2 +- cas-client-integration-atlassian/pom.xml | 2 +- cas-client-integration-jboss/pom.xml | 2 +- cas-client-integration-tomcat-common/pom.xml | 2 +- cas-client-integration-tomcat-v6/pom.xml | 2 +- cas-client-integration-tomcat-v7/pom.xml | 2 +- cas-client-support-distributed-ehcache/pom.xml | 2 +- cas-client-support-distributed-memcached/pom.xml | 2 +- pom.xml | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index f37b084..b852eb2 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index d94bbd5..2803e7e 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index f2de056..ce5904b 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index e72e953..5fe5a47 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 067fa1b..7983578 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 4139880..bfa4957 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index d556557..605a6df 100644 --- a/cas-client-support-distributed-ehcache/pom.xml +++ b/cas-client-support-distributed-ehcache/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 4.0.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index 3143fdb..97b62de 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 4.0.0 diff --git a/pom.xml b/pom.xml index c51b43e..b0ce184 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.3.3-SNAPSHOT + 3.3.3 cas-client pom @@ -26,7 +26,7 @@ scm:git:git@github.com:Jasig/java-cas-client.git scm:git:git@github.com:Jasig/java-cas-client.git https://github.com/Jasig/java-cas-client - HEAD + cas-client-3.3.3 2006 From 4e3f761efe185c7c93d1cc91d8f1d774a9601b05 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 15 Aug 2014 08:52:01 -0400 Subject: [PATCH 16/57] [maven-release-plugin] prepare for next development iteration --- cas-client-core/pom.xml | 2 +- cas-client-integration-atlassian/pom.xml | 2 +- cas-client-integration-jboss/pom.xml | 2 +- cas-client-integration-tomcat-common/pom.xml | 2 +- cas-client-integration-tomcat-v6/pom.xml | 2 +- cas-client-integration-tomcat-v7/pom.xml | 2 +- cas-client-support-distributed-ehcache/pom.xml | 2 +- cas-client-support-distributed-memcached/pom.xml | 2 +- pom.xml | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index b852eb2..b0de44b 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 2803e7e..96895e9 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index ce5904b..5a118ea 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index 5fe5a47..06a1c33 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 7983578..5d40ce4 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index bfa4957..5bc817d 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index 605a6df..1e1f712 100644 --- a/cas-client-support-distributed-ehcache/pom.xml +++ b/cas-client-support-distributed-ehcache/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT 4.0.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index 97b62de..52a8640 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index b0ce184..70befae 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.3.3 + 3.3.4-SNAPSHOT cas-client pom @@ -26,7 +26,7 @@ scm:git:git@github.com:Jasig/java-cas-client.git scm:git:git@github.com:Jasig/java-cas-client.git https://github.com/Jasig/java-cas-client - cas-client-3.3.3 + HEAD 2006 From 461cdcd8fc31ea9b203feb26b5a4ad758c489043 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Wed, 9 Apr 2014 22:12:26 -0400 Subject: [PATCH 17/57] CASC-200 Create a ConfigurationStrategy to allow for pluggable configurations. Problem: The lookup strategy for configuration is hard-coded into the filter, making it impossible to replace or expand. Solution: Pull the strategies into their own classees and make it configurable. Default to the previous strategy. QA Notes: The current unit tests work. New unit tests for the configuration will have to be added once the design is approved. --- cas-client-core/pom.xml | 7 + .../java/org/jasig/cas/client/Protocol.java | 28 ++++ .../authentication/AuthenticationFilter.java | 35 ++--- .../Saml11AuthenticationFilter.java | 17 +-- .../BaseConfigurationStrategy.java | 95 +++++++++++++ .../configuration/ConfigurationKey.java | 42 ++++++ .../configuration/ConfigurationKeys.java | 58 ++++++++ .../configuration/ConfigurationStrategy.java | 62 +++++++++ .../ConfigurationStrategyName.java | 51 +++++++ .../JndiConfigurationStrategyImpl.java | 75 ++++++++++ .../LegacyConfigurationStrategyImpl.java | 35 +++++ .../WebXmlConfigurationStrategyImpl.java | 42 ++++++ .../jaas/Servlet3AuthenticationFilter.java | 7 +- ...cryptedProxyGrantingTicketStorageImpl.java | 6 +- .../client/session/SingleSignOutFilter.java | 22 ++- .../client/session/SingleSignOutHandler.java | 15 +- .../cas/client/util/AbstractCasFilter.java | 49 +++---- .../util/AbstractConfigurationFilter.java | 108 ++++----------- .../jasig/cas/client/util/CommonUtils.java | 16 ++- .../util/HttpServletRequestWrapperFilter.java | 6 +- .../AbstractTicketValidationFilter.java | 32 ++--- .../Cas10TicketValidationFilter.java | 25 ++-- ...0ProxyReceivingTicketValidationFilter.java | 71 +++++----- .../Saml11TicketValidationFilter.java | 37 ++--- .../configuration/ConfigurationKeyTests.java | 27 ++++ .../ConfigurationStrategyNameTests.java | 16 +++ .../WebXmlConfigurationStrategyImplTests.java | 128 ++++++++++++++++++ .../session/SingleSignOutFilterTests.java | 30 ++-- .../jasig/cas/client/util/CasFilterTests.java | 6 + .../Cas10TicketValidationFilterTests.java | 5 +- ...yReceivingTicketValidationFilterTests.java | 30 ++-- .../Saml11TicketValidationFilterTests.java | 6 +- ...mpatibleJndiConfigurationStrategyImpl.java | 16 +++ .../WebAuthenticationFilter.java | 8 +- 34 files changed, 932 insertions(+), 281 deletions(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java create mode 100644 cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index f37b084..3cecc14 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -75,6 +75,13 @@ test + + org.mockito + mockito-all + 1.10.8 + test + + log4j log4j diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java new file mode 100644 index 0000000..184104f --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java @@ -0,0 +1,28 @@ +package org.jasig.cas.client; + +/** + * Created by battags on 10/14/14. + */ +public enum Protocol { + + + + CAS1("ticket", "service"), CAS2(CAS1.getArtifactParameterName(), CAS1.getServiceParameterName()), SAML11("SAMLart", "TARGET"); + + private final String artifactParameterName; + + private final String serviceParameterName; + + private Protocol(final String artifactParameterName, final String serviceParameterName) { + this.artifactParameterName = artifactParameterName; + this.serviceParameterName = serviceParameterName; + } + + public String getArtifactParameterName() { + return this.artifactParameterName; + } + + public String getServiceParameterName() { + return this.serviceParameterName; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java index b77c64c..d5e7fe4 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java @@ -27,6 +27,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.AbstractCasFilter; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.ReflectUtils; @@ -79,22 +81,24 @@ public class AuthenticationFilter extends AbstractCasFilter { PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class); PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class); } + + public AuthenticationFilter() { + this(Protocol.CAS2); + } + + protected AuthenticationFilter(final Protocol protocol) { + super(protocol); + } protected void initInternal(final FilterConfig filterConfig) throws ServletException { if (!isIgnoreInitConfiguration()) { super.initInternal(filterConfig); - setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null)); - logger.trace("Loaded CasServerLoginUrl parameter: {}", this.casServerLoginUrl); - setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - logger.trace("Loaded renew parameter: {}", this.renew); - setGateway(parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false"))); - logger.trace("Loaded gateway parameter: {}", this.gateway); + setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL)); + setRenew(getBoolean(ConfigurationKeys.RENEW)); + setGateway(getBoolean(ConfigurationKeys.GATEWAY)); - final String ignorePattern = getPropertyFromInitParams(filterConfig, "ignorePattern", null); - logger.trace("Loaded ignorePattern parameter: {}", ignorePattern); - - final String ignoreUrlPatternType = getPropertyFromInitParams(filterConfig, "ignoreUrlPatternType", "REGEX"); - logger.trace("Loaded ignoreUrlPatternType parameter: {}", ignoreUrlPatternType); + final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN); + final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE); if (ignorePattern != null) { final Class ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType); @@ -113,14 +117,13 @@ public class AuthenticationFilter extends AbstractCasFilter { } } - final String gatewayStorageClass = getPropertyFromInitParams(filterConfig, "gatewayStorageClass", null); + final Class gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS); if (gatewayStorageClass != null) { - this.gatewayStorage = ReflectUtils.newInstance(gatewayStorageClass); + setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass)); } - final String authenticationRedirectStrategyClass = getPropertyFromInitParams(filterConfig, - "authenticationRedirectStrategyClass", null); + final Class authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS); if (authenticationRedirectStrategyClass != null) { this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass); @@ -175,7 +178,7 @@ public class AuthenticationFilter extends AbstractCasFilter { logger.debug("Constructed service url: {}", modifiedServiceUrl); final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, - getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway); + getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway); logger.debug("redirecting to \"{}\"", urlToRedirectTo); this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java index 6c853ec..63483b2 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java @@ -18,13 +18,12 @@ */ package org.jasig.cas.client.authentication; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; +import org.jasig.cas.client.Protocol; /** - * Extension to the default Authentication filter that sets the required SAML1.1 artifact parameter name and service parameter name. + * Extension to the default Authentication filter that sets the required SAML11.1 artifact parameter name and service parameter name. *

- * Note, as of 3.3, the final keyword was removed to allow you to override the method to retrieve tickets, per CASC-154s + * Note, as of 3.3, the final keyword was removed to allow you to override the method to retrieve tickets, per CASC-154 * * @author Scott Battaglia * @since 3.1.12 @@ -32,13 +31,7 @@ import javax.servlet.ServletException; */ public class Saml11AuthenticationFilter extends AuthenticationFilter { - protected final void initInternal(final FilterConfig filterConfig) throws ServletException { - super.initInternal(filterConfig); - - logger.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values."); - logger.warn("This filter will overwrite any user-provided values (if any are provided)"); - - setArtifactParameterName("SAMLart"); - setServiceParameterName("TARGET"); + private Saml11AuthenticationFilter() { + super(Protocol.SAML11); } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java new file mode 100644 index 0000000..384f89d --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java @@ -0,0 +1,95 @@ +package org.jasig.cas.client.configuration; + +import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.ReflectUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base class to provide most of the boiler-plate code (i.e. checking for proper values, returning defaults, etc. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public abstract class BaseConfigurationStrategy implements ConfigurationStrategy { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + public final boolean getBoolean(final ConfigurationKey configurationKey) { + return getValue(configurationKey, new Parser() { + public Boolean parse(final String value) { + return BooleanUtils.toBoolean(value); + } + }); + } + + public final long getLong(final ConfigurationKey configurationKey) { + return getValue(configurationKey, new Parser() { + public Long parse(final String value) { + return NumberUtils.toLong(value, configurationKey.getDefaultValue()); + } + }); + } + + public final int getInt(final ConfigurationKey configurationKey) { + return getValue(configurationKey, new Parser() { + public Integer parse(final String value) { + return NumberUtils.toInt(value, configurationKey.getDefaultValue()); + } + }); + } + + public final String getString(final ConfigurationKey configurationKey) { + return getValue(configurationKey, new Parser() { + public String parse(final String value) { + return value; + } + }); + } + + public Class getClass(final ConfigurationKey> configurationKey) { + return getValue(configurationKey, new Parser>() { + public Class parse(final String value) { + try { + return ReflectUtils.loadClass(value); + } catch (final IllegalArgumentException e) { + return configurationKey.getDefaultValue(); + } + } + }); + } + + private T getValue(final ConfigurationKey configurationKey, final Parser parser) { + final String value = getWithCheck(configurationKey); + + if (CommonUtils.isBlank(value)) { + logger.trace("No value found for property {}, returning default {}", configurationKey.getName(), configurationKey.getDefaultValue()); + return configurationKey.getDefaultValue(); + } else { + logger.trace("Loaded property {} with value {}", configurationKey.getName(), configurationKey.getDefaultValue()); + } + + return parser.parse(value); + } + + private String getWithCheck(final ConfigurationKey configurationKey) { + CommonUtils.assertNotNull(configurationKey, "configurationKey cannot be null"); + + return get(configurationKey); + } + + /** + * Retrieve the String value for this key. Returns null if there is no value. + * + * @param configurationKey the key to retrieve. MUST NOT BE NULL. + * @return the String if its found, null otherwise. + */ + protected abstract String get(ConfigurationKey configurationKey); + + private interface Parser { + + T parse(String value); + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java new file mode 100644 index 0000000..f6c0df7 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java @@ -0,0 +1,42 @@ +package org.jasig.cas.client.configuration; + +/** + * Holder class to represent a particular configuration key and its optional default value. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public final class ConfigurationKey { + + private final String name; + + private final E defaultValue; + + public ConfigurationKey(final String name) { + this(name, null); + } + + public ConfigurationKey(final String name, final E defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + /** + * The referencing name of the configuration key (i.e. what you would use to look it up in your configuration strategy) + * + * @return the name. MUST NOT BE NULL. + */ + public String getName() { + return this.name; + } + + + /** + * The (optional) default value to use when this configuration key is not set. If a value is provided it should be used. A null value indicates that there is no default. + * + * @return the default value or null. + */ + public E getDefaultValue() { + return this.defaultValue; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java new file mode 100644 index 0000000..138c459 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -0,0 +1,58 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy; +import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl; +import org.jasig.cas.client.authentication.GatewayResolver; +import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; +import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; + +import javax.net.ssl.HostnameVerifier; + +/** + * Holder interface for all known configuration keys. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public interface ConfigurationKeys { + + ConfigurationKey ARTIFACT_PARAMETER_NAME = new ConfigurationKey("artifactParameterName", Protocol.CAS2.getArtifactParameterName()); + ConfigurationKey SERVER_NAME = new ConfigurationKey("serverName", null); + ConfigurationKey SERVICE = new ConfigurationKey("service"); + ConfigurationKey RENEW = new ConfigurationKey("renew", Boolean.FALSE); + ConfigurationKey LOGOUT_PARAMETER_NAME = new ConfigurationKey("logoutParameterName", "logoutRequest"); + ConfigurationKey ARTIFACT_PARAMETER_OVER_POST = new ConfigurationKey("artifactParameterOverPost", Boolean.FALSE); + ConfigurationKey EAGERLY_CREATE_SESSIONS = new ConfigurationKey("eagerlyCreateSessions", Boolean.TRUE); + ConfigurationKey ENCODE_SERVICE_URL = new ConfigurationKey("encodeServiceUrl", Boolean.TRUE); + ConfigurationKey SSL_CONFIG_FILE = new ConfigurationKey("sslConfigFile", null); + ConfigurationKey ROLE_ATTRIBUTE = new ConfigurationKey("roleAttribute", null); + ConfigurationKey IGNORE_CASE = new ConfigurationKey("ignoreCase", Boolean.FALSE); + ConfigurationKey CAS_SERVER_LOGIN_URL = new ConfigurationKey("casServerLoginUrl", null); + ConfigurationKey GATEWAY = new ConfigurationKey("gateway", Boolean.FALSE); + ConfigurationKey> AUTHENTICATION_REDIRECT_STRATEGY_CLASS = new ConfigurationKey>("authenticationRedirectStrategyClass", null); + ConfigurationKey> GATEWAY_STORAGE_CLASS = new ConfigurationKey>("gatewayStorageClass", DefaultGatewayResolverImpl.class); + ConfigurationKey CAS_SERVER_URL_PREFIX = new ConfigurationKey("casServerUrlPrefix", null); + ConfigurationKey ENCODING = new ConfigurationKey("encoding", null); + ConfigurationKey TOLERANCE = new ConfigurationKey("tolerance", 1000L); + ConfigurationKey DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey("disableXmlSchemaValidation", Boolean.FALSE); + ConfigurationKey IGNORE_PATTERN = new ConfigurationKey("ignorePattern", null); + ConfigurationKey IGNORE_URL_PATTERN_TYPE = new ConfigurationKey("ignoreUrlPatternType", "REGEX"); + ConfigurationKey> HOSTNAME_VERIFIER = new ConfigurationKey>("hostnameVerifier", null); + ConfigurationKey HOSTNAME_VERIFIER_CONFIG = new ConfigurationKey("hostnameVerifierConfig", null); + ConfigurationKey EXCEPTION_ON_VALIDATION_FAILURE = new ConfigurationKey("exceptionOnValidationFailure", Boolean.TRUE); + ConfigurationKey REDIRECT_AFTER_VALIDATION = new ConfigurationKey("redirectAfterValidation", Boolean.TRUE); + ConfigurationKey USE_SESSION = new ConfigurationKey("useSession", Boolean.TRUE); + ConfigurationKey SECRET_KEY = new ConfigurationKey("secretKey", null); + ConfigurationKey CIPHER_ALGORITHM = new ConfigurationKey("cipherAlgorithm", "DESede"); + ConfigurationKey PROXY_RECEPTOR_URL = new ConfigurationKey("proxyReceptorUrl", null); + ConfigurationKey> PROXY_GRANTING_TICKET_STORAGE_CLASS = new ConfigurationKey>("proxyGrantingTicketStorageClass", ProxyGrantingTicketStorageImpl.class); + ConfigurationKey MILLIS_BETWEEN_CLEAN_UPS = new ConfigurationKey("millisBetweenCleanUps", 60000); + ConfigurationKey ACCEPT_ANY_PROXY = new ConfigurationKey("acceptAnyProxy", Boolean.FALSE); + ConfigurationKey ALLOWED_PROXY_CHAINS = new ConfigurationKey("allowedProxyChains", null); + ConfigurationKey> TICKET_VALIDATOR_CLASS = new ConfigurationKey>("ticketValidatorClass", null); + ConfigurationKey PROXY_CALLBACK_URL = new ConfigurationKey("proxyCallbackUrl", null); + ConfigurationKey FRONT_LOGOUT_PARAMETER_NAME = new ConfigurationKey("frontLogoutParameterName", "SAMLRequest"); + ConfigurationKey RELAY_STATE_PARAMETER_NAME = new ConfigurationKey("relayStateParameterName", "RelayState"); +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java new file mode 100644 index 0000000..cd1b9dd --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java @@ -0,0 +1,62 @@ +package org.jasig.cas.client.configuration; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + +/** + * Abstraction to allow for pluggable methods for retrieving filter configuration. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public interface ConfigurationStrategy { + + + /** + * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. + * + * @param configurationKey the configuration key. MUST NOT BE NULL. + * @return the configured value, or the default value. + */ + boolean getBoolean(ConfigurationKey configurationKey); + + /** + * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. + * + * @param configurationKey the configuration key. MUST NOT BE NULL. + * @return the configured value, or the default value. + */ + String getString(ConfigurationKey configurationKey); + + /** + * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. + * + * @param configurationKey the configuration key. MUST NOT BE NULL. + * @return the configured value, or the default value. + */ + long getLong(ConfigurationKey configurationKey); + + /** + * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. + * + * @param configurationKey the configuration key. MUST NOT BE NULL. + * @return the configured value, or the default value. + */ + int getInt(ConfigurationKey configurationKey); + + /** + * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. + * + * @param configurationKey the configuration key. MUST NOT BE NULL. + * @return the configured value, or the default value. + */ + Class getClass(ConfigurationKey> configurationKey); + + /** + * Initializes the strategy. This must be called before calling any of the "get" methods. + * + * @param filterConfig the filter configuration object. + * @param filterClazz the filter + */ + void init(FilterConfig filterConfig, Class filterClazz); +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java new file mode 100644 index 0000000..ea089fe --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java @@ -0,0 +1,51 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.CommonUtils; + +/** + * Enumeration to map simple names to the underlying classes so that deployers can reference the simple name in the + * web.xml instead of the fully qualified class name. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public enum ConfigurationStrategyName { + + DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class); + + private final Class configurationStrategyClass; + + private ConfigurationStrategyName(final Class configurationStrategyClass) { + this.configurationStrategyClass = configurationStrategyClass; + } + + /** + * Static helper method that will resolve a simple string to either an enum value or a {@link org.jasig.cas.client.configuration.ConfigurationStrategy} class. + * + * @param value the value to attempt to resolve. + * @return the underlying class that this maps to (either via simple name or fully qualified class name). + */ + public static Class resolveToConfigurationStrategy(final String value) { + if (CommonUtils.isBlank(value)) { + return DEFAULT.configurationStrategyClass; + } + + for (final ConfigurationStrategyName csn : values()) { + if (csn.name().equalsIgnoreCase(value)) { + return csn.configurationStrategyClass; + } + } + + try { + final Class clazz = Class.forName(value); + + if (clazz.isAssignableFrom(ConfigurationStrategy.class)) { + return (Class) clazz; + } + } catch (final ClassNotFoundException e) { + // nothing we can do here + } + + return DEFAULT.configurationStrategyClass; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java new file mode 100644 index 0000000..b81f1ee --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java @@ -0,0 +1,75 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.CommonUtils; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + +/** + * Loads configuration information from JNDI, using the defaultValue if it can't. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public class JndiConfigurationStrategyImpl extends BaseConfigurationStrategy { + + private static final String ENVIRONMENT_PREFIX = "java:comp/env/cas/"; + + private final String environmentPrefix; + + private InitialContext context; + + private String simpleFilterName; + + public JndiConfigurationStrategyImpl() { + this(ENVIRONMENT_PREFIX); + } + + public JndiConfigurationStrategyImpl(final String environmentPrefix) { + this.environmentPrefix = environmentPrefix; + } + + @Override + protected final String get(final ConfigurationKey configurationKey) { + if (context == null) { + return null; + } + + final String propertyName = configurationKey.getName(); + final String filterValue = loadFromContext(context, this.environmentPrefix + this.simpleFilterName + "/" + propertyName); + + if (CommonUtils.isNotBlank(filterValue)) { + logger.info("Property [{}] loaded from JNDI Filter Specific Property with value [{}]", propertyName, filterValue); + return filterValue; + } + + final String rootValue = loadFromContext(context, this.environmentPrefix + propertyName); + + if (CommonUtils.isNotBlank(rootValue)) { + logger.info("Property [{}] loaded from JNDI with value [{}]", propertyName, rootValue); + return rootValue; + } + + return null; + } + + private String loadFromContext(final InitialContext context, final String path) { + try { + return (String) context.lookup(path); + } catch (final NamingException e) { + return null; + } + } + + + public final void init(final FilterConfig filterConfig, final Class clazz) { + this.simpleFilterName = clazz.getSimpleName(); + try { + this.context = new InitialContext(); + } catch (final NamingException e) { + logger.error("Unable to create InitialContext. No properties can be loaded via JNDI.", e); + } + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java new file mode 100644 index 0000000..d1f47c3 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java @@ -0,0 +1,35 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.CommonUtils; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + +/** + * Replicates the original behavior by checking the {@link org.jasig.cas.client.configuration.WebXmlConfigurationStrategyImpl} first, and then + * the {@link org.jasig.cas.client.configuration.JndiConfigurationStrategyImpl} before using the defaultValue. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public final class LegacyConfigurationStrategyImpl extends BaseConfigurationStrategy { + + private final WebXmlConfigurationStrategyImpl webXmlConfigurationStrategy = new WebXmlConfigurationStrategyImpl(); + + private final JndiConfigurationStrategyImpl jndiConfigurationStrategy = new JndiConfigurationStrategyImpl(); + + public void init(FilterConfig filterConfig, Class filterClazz) { + this.webXmlConfigurationStrategy.init(filterConfig, filterClazz); + this.jndiConfigurationStrategy.init(filterConfig, filterClazz); + } + + protected String get(final ConfigurationKey key) { + final String value1 = this.webXmlConfigurationStrategy.get(key); + + if (CommonUtils.isNotBlank(value1)) { + return value1; + } + + return this.jndiConfigurationStrategy.get(key); + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java new file mode 100644 index 0000000..1c05b0b --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java @@ -0,0 +1,42 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.CommonUtils; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + +/** + * Implementation of the {@link org.jasig.cas.client.configuration.ConfigurationStrategy} that first checks the {@link javax.servlet.FilterConfig} and + * then checks the {@link javax.servlet.ServletContext}, ultimately falling back to the defaultValue. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public final class WebXmlConfigurationStrategyImpl extends BaseConfigurationStrategy { + + private FilterConfig filterConfig; + + protected String get(final ConfigurationKey configurationKey) { + final String value = this.filterConfig.getInitParameter(configurationKey.getName()); + + if (CommonUtils.isNotBlank(value)) { + CommonUtils.assertFalse(ConfigurationKeys.RENEW.equals(configurationKey), "Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration."); + logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", configurationKey, value); + return value; + } + + final String value2 = filterConfig.getServletContext().getInitParameter(configurationKey.getName()); + + if (CommonUtils.isNotBlank(value2)) { + logger.info("Property [{}] loaded from ServletContext.getInitParameter with value [{}]", configurationKey, + value2); + return value2; + } + + return null; + } + + public void init(final FilterConfig filterConfig, final Class clazz) { + this.filterConfig = filterConfig; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/Servlet3AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/Servlet3AuthenticationFilter.java index d39027e..e64b578 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/Servlet3AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/Servlet3AuthenticationFilter.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.jasig.cas.client.Protocol; import org.jasig.cas.client.util.AbstractCasFilter; import org.jasig.cas.client.util.CommonUtils; @@ -50,12 +51,16 @@ import org.jasig.cas.client.util.CommonUtils; */ public final class Servlet3AuthenticationFilter extends AbstractCasFilter { + public Servlet3AuthenticationFilter() { + super(Protocol.CAS2); + } + public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; final HttpSession session = request.getSession(); - final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName()); + final String ticket = CommonUtils.safeGetParameter(request, getProtocol().getArtifactParameterName()); if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) { try { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractEncryptedProxyGrantingTicketStorageImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractEncryptedProxyGrantingTicketStorageImpl.java index 69cc75d..24826cf 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractEncryptedProxyGrantingTicketStorageImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/AbstractEncryptedProxyGrantingTicketStorageImpl.java @@ -18,6 +18,8 @@ */ package org.jasig.cas.client.proxy; +import org.jasig.cas.client.configuration.ConfigurationKeys; + import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; @@ -36,11 +38,9 @@ import javax.crypto.spec.DESedeKeySpec; */ public abstract class AbstractEncryptedProxyGrantingTicketStorageImpl implements ProxyGrantingTicketStorage { - public static final String DEFAULT_ENCRYPTION_ALGORITHM = "DESede"; - private Key key; - private String cipherAlgorithm = DEFAULT_ENCRYPTION_ALGORITHM; + private String cipherAlgorithm = ConfigurationKeys.CIPHER_ALGORITHM.getDefaultValue(); public final void setSecretKey(final String key) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index c9243e9..da533cf 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -22,8 +22,10 @@ import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; + import javax.servlet.http.HttpServletResponse; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.AbstractConfigurationFilter; /** @@ -41,19 +43,13 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { public void init(final FilterConfig filterConfig) throws ServletException { if (!isIgnoreInitConfiguration()) { - HANDLER.setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", - SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME)); - HANDLER.setLogoutParameterName(getPropertyFromInitParams(filterConfig, "logoutParameterName", - SingleSignOutHandler.DEFAULT_LOGOUT_PARAMETER_NAME)); - HANDLER.setFrontLogoutParameterName(getPropertyFromInitParams(filterConfig, "frontLogoutParameterName", - SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME)); - HANDLER.setRelayStateParameterName(getPropertyFromInitParams(filterConfig, "relayStateParameterName", - SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME)); - HANDLER.setCasServerUrlPrefix(getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null)); - HANDLER.setArtifactParameterOverPost(parseBoolean(getPropertyFromInitParams(filterConfig, - "artifactParameterOverPost", "false"))); - HANDLER.setEagerlyCreateSessions(parseBoolean(getPropertyFromInitParams(filterConfig, - "eagerlyCreateSessions", "true"))); + setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME)); + setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME)); + setFrontLogoutParameterName(getString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME)); + setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME)); + setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX)); + HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST)); + HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS)); } HANDLER.init(); handlerInitialized.set(true); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index 5f8b46c..cc049f7 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -29,6 +29,8 @@ import javax.servlet.http.HttpSession; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; import org.slf4j.Logger; @@ -44,11 +46,6 @@ import org.slf4j.LoggerFactory; */ public final class SingleSignOutHandler { - public final static String DEFAULT_ARTIFACT_PARAMETER_NAME = "ticket"; - public final static String DEFAULT_LOGOUT_PARAMETER_NAME = "logoutRequest"; - public final static String DEFAULT_FRONT_LOGOUT_PARAMETER_NAME = "SAMLRequest"; - public final static String DEFAULT_RELAY_STATE_PARAMETER_NAME = "RelayState"; - private final static int DECOMPRESSION_FACTOR = 10; /** Logger instance */ @@ -58,16 +55,16 @@ public final class SingleSignOutHandler { private SessionMappingStorage sessionMappingStorage = new HashMapBackedSessionMappingStorage(); /** The name of the artifact parameter. This is used to capture the session identifier. */ - private String artifactParameterName = DEFAULT_ARTIFACT_PARAMETER_NAME; + private String artifactParameterName = Protocol.CAS2.getArtifactParameterName(); /** Parameter name that stores logout request for back channel SLO */ - private String logoutParameterName = DEFAULT_LOGOUT_PARAMETER_NAME; + private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(); /** Parameter name that stores logout request for front channel SLO */ - private String frontLogoutParameterName = DEFAULT_FRONT_LOGOUT_PARAMETER_NAME; + private String frontLogoutParameterName = ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(); /** Parameter name that stores the state of the CAS server webflow for the callback */ - private String relayStateParameterName = DEFAULT_RELAY_STATE_PARAMETER_NAME; + private String relayStateParameterName = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(); /** The prefix url of the CAS server */ private String casServerUrlPrefix; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java index 8cf47ef..6e0df5f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java @@ -18,6 +18,9 @@ */ package org.jasig.cas.client.util; +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; + import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -42,12 +45,8 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { /** Represents the constant for where the assertion will be located in memory. */ public static final String CONST_CAS_ASSERTION = "_const_cas_assertion_"; - /** Defines the parameter to look for for the artifact. */ - private String artifactParameterName = "ticket"; + private Protocol protocol; - /** Defines the parameter to look for for the service. */ - private String serviceParameterName = "service"; - /** Sets where response.encodeUrl should be called on service urls when constructed. */ private boolean encodeServiceUrl = true; @@ -59,18 +58,16 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { /** The exact url of the service. */ private String service; + protected AbstractCasFilter(final Protocol protocol) { + this.protocol = protocol; + } + public final void init(final FilterConfig filterConfig) throws ServletException { + super.init(filterConfig); if (!isIgnoreInitConfiguration()) { - setServerName(getPropertyFromInitParams(filterConfig, "serverName", null)); - logger.trace("Loading serverName property: {}", this.serverName); - setService(getPropertyFromInitParams(filterConfig, "service", null)); - logger.trace("Loading service property: {}", this.service); - setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket")); - logger.trace("Loading artifact parameter name property: {}", this.artifactParameterName); - setServiceParameterName(getPropertyFromInitParams(filterConfig, "serviceParameterName", "service")); - logger.trace("Loading serviceParameterName property: {} ", this.serviceParameterName); - setEncodeServiceUrl(parseBoolean(getPropertyFromInitParams(filterConfig, "encodeServiceUrl", "true"))); - logger.trace("Loading encodeServiceUrl property: {}", this.encodeServiceUrl); + setServerName(getString(ConfigurationKeys.SERVER_NAME)); + setService(getString(ConfigurationKeys.SERVICE)); + setEncodeServiceUrl(getBoolean(ConfigurationKeys.ENCODE_SERVICE_URL)); initInternal(filterConfig); } @@ -92,8 +89,6 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { * afterPropertiesSet(); */ public void init() { - CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null."); - CommonUtils.assertNotNull(this.serviceParameterName, "serviceParameterName cannot be null."); CommonUtils.assertTrue(CommonUtils.isNotEmpty(this.serverName) || CommonUtils.isNotEmpty(this.service), "serverName or service must be set."); CommonUtils.assertTrue(CommonUtils.isBlank(this.serverName) || CommonUtils.isBlank(this.service), @@ -107,7 +102,7 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { protected final String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) { return CommonUtils.constructServiceUrl(request, response, this.service, this.serverName, - this.artifactParameterName, this.encodeServiceUrl); + this.protocol.getArtifactParameterName(), this.encodeServiceUrl); } /** @@ -129,26 +124,14 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { this.service = service; } - public final void setArtifactParameterName(final String artifactParameterName) { - this.artifactParameterName = artifactParameterName; - } - - public final void setServiceParameterName(final String serviceParameterName) { - this.serviceParameterName = serviceParameterName; - } - public final void setEncodeServiceUrl(final boolean encodeServiceUrl) { this.encodeServiceUrl = encodeServiceUrl; } - public final String getArtifactParameterName() { - return this.artifactParameterName; + protected Protocol getProtocol() { + return this.protocol; } - public final String getServiceParameterName() { - return this.serviceParameterName; - } - /** * Template method to allow you to change how you retrieve the ticket. * @@ -156,6 +139,6 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { * @return the ticket if its found, null otherwise. */ protected String retrieveTicketFromRequest(final HttpServletRequest request) { - return CommonUtils.safeGetParameter(request, getArtifactParameterName()); + return CommonUtils.safeGetParameter(request, this.protocol.getArtifactParameterName()); } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java index 708b7bf..9d3e542 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java @@ -18,10 +18,13 @@ */ package org.jasig.cas.client.util; -import javax.naming.InitialContext; -import javax.naming.NamingException; import javax.servlet.Filter; import javax.servlet.FilterConfig; +import javax.servlet.ServletException; + +import org.jasig.cas.client.configuration.ConfigurationKey; +import org.jasig.cas.client.configuration.ConfigurationStrategy; +import org.jasig.cas.client.configuration.ConfigurationStrategyName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,94 +37,41 @@ import org.slf4j.LoggerFactory; */ public abstract class AbstractConfigurationFilter implements Filter { + private static final String CONFIGURATION_STRATEGY_KEY = "configurationStrategy"; + protected final Logger logger = LoggerFactory.getLogger(getClass()); private boolean ignoreInitConfiguration = false; - /** - * Retrieves the property from the FilterConfig. First it checks the FilterConfig's initParameters to see if it - * has a value. - * If it does, it returns that, otherwise it retrieves the ServletContext's initParameters and returns that value if any. - *

- * Finally, it will check JNDI if all other methods fail. All the JNDI properties should be stored under either java:comp/env/cas/SHORTFILTERNAME/{propertyName} - * or java:comp/env/cas/{propertyName} - *

- * Essentially the documented order is: - *

    - *
  1. FilterConfig.getInitParameter
  2. - *
  3. ServletContext.getInitParameter
  4. - *
  5. java:comp/env/cas/SHORTFILTERNAME/{propertyName}
  6. - *
  7. java:comp/env/cas/{propertyName}
  8. - *
  9. Default Value
  10. - *
- * - * - * @param filterConfig the Filter Configuration. - * @param propertyName the property to retrieve. - * @param defaultValue the default value if the property is not found. - * @return the property value, following the above conventions. It will always return the more specific value (i.e. - * filter vs. context). - */ - protected final String getPropertyFromInitParams(final FilterConfig filterConfig, final String propertyName, - final String defaultValue) { - final String value = filterConfig.getInitParameter(propertyName); + private ConfigurationStrategy configurationStrategy; - if (CommonUtils.isNotBlank(value)) { - if ("renew".equals(propertyName)) { - throw new IllegalArgumentException( - "Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration."); - } - logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", propertyName, value); - return value; - } - - final String value2 = filterConfig.getServletContext().getInitParameter(propertyName); - - if (CommonUtils.isNotBlank(value2)) { - logger.info("Property [{}] loaded from ServletContext.getInitParameter with value [{}]", propertyName, - value2); - return value2; - } - InitialContext context; - try { - context = new InitialContext(); - } catch (final NamingException e) { - logger.warn(e.getMessage(), e); - return defaultValue; - } - - final String shortName = this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1); - final String value3 = loadFromContext(context, "java:comp/env/cas/" + shortName + "/" + propertyName); - - if (CommonUtils.isNotBlank(value3)) { - logger.info("Property [{}] loaded from JNDI Filter Specific Property with value [{}]", propertyName, value3); - return value3; - } - - final String value4 = loadFromContext(context, "java:comp/env/cas/" + propertyName); - - if (CommonUtils.isNotBlank(value4)) { - logger.info("Property [{}] loaded from JNDI with value [{}]", propertyName, value4); - return value4; - } - - logger.info("Property [{}] not found. Using default value [{}]", propertyName, defaultValue); - return defaultValue; + public void init(FilterConfig filterConfig) throws ServletException { + final String configurationStrategyName = filterConfig.getServletContext().getInitParameter(CONFIGURATION_STRATEGY_KEY); + this.configurationStrategy = ReflectUtils.newInstance(ConfigurationStrategyName.resolveToConfigurationStrategy(configurationStrategyName)); + this.configurationStrategy.init(filterConfig, getClass()); } - protected final boolean parseBoolean(final String value) { - return ((value != null) && value.equalsIgnoreCase("true")); + protected final boolean getBoolean(final ConfigurationKey configurationKey) { + return this.configurationStrategy.getBoolean(configurationKey); } - protected final String loadFromContext(final InitialContext context, final String path) { - try { - return (String) context.lookup(path); - } catch (final NamingException e) { - return null; - } + protected final String getString(final ConfigurationKey configurationKey) { + return this.configurationStrategy.getString(configurationKey); } - public final void setIgnoreInitConfiguration(boolean ignoreInitConfiguration) { + protected final long getLong(final ConfigurationKey configurationKey) { + return this.configurationStrategy.getLong(configurationKey); + } + + protected final int getInt(final ConfigurationKey configurationKey) { + return this.configurationStrategy.getInt(configurationKey); + } + + protected final Class getClass(final ConfigurationKey> configurationKey) { + return this.configurationStrategy.getClass(configurationKey); + } + + public final void setIgnoreInitConfiguration(final boolean ignoreInitConfiguration) { this.ignoreInitConfiguration = ignoreInitConfiguration; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index 3d99171..ac0ca80 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -99,7 +99,7 @@ public final class CommonUtils { * Assert that the statement is true, otherwise throw an exception with the * provided message. * - * @param cond the codition to assert is true. + * @param cond the condition to assert is true. * @param message the message to display if the condition is not true. */ public static void assertTrue(final boolean cond, final String message) { @@ -108,6 +108,20 @@ public final class CommonUtils { } } + + /** + * Assert that the statement is true, otherwise throw an exception with the + * provided message. + * + * @param cond the condition to assert is false. + * @param message the message to display if the condition is not false. + */ + public static void assertFalse(final boolean cond, final String message) { + if (cond) { + throw new IllegalArgumentException(message); + } + } + /** * Determines whether the String is null or of length 0. * diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpServletRequestWrapperFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpServletRequestWrapperFilter.java index 3512f48..a474a83 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpServletRequestWrapperFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpServletRequestWrapperFilter.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; import org.jasig.cas.client.authentication.AttributePrincipal; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.validation.Assertion; /** @@ -82,8 +83,9 @@ public final class HttpServletRequestWrapperFilter extends AbstractConfiguration } public void init(final FilterConfig filterConfig) throws ServletException { - this.roleAttribute = getPropertyFromInitParams(filterConfig, "roleAttribute", null); - this.ignoreCase = Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "ignoreCase", "false")); + super.init(filterConfig); + this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE); + this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE); } final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java index 1d27314..51df207 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java @@ -25,6 +25,9 @@ import javax.net.ssl.HostnameVerifier; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.AbstractCasFilter; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.ReflectUtils; @@ -68,6 +71,10 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { */ private boolean useSession = true; + protected AbstractTicketValidationFilter(final Protocol protocol) { + super(protocol); + } + /** * Template method to return the appropriate validator. * @@ -81,12 +88,11 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { /** * Gets the ssl config to use for HTTPS connections * if one is configured for this filter. - * @param filterConfig Servlet filter configuration. * @return Properties that can contains key/trust info for Client Side Certificates */ - protected Properties getSSLConfig(final FilterConfig filterConfig) { + protected Properties getSSLConfig() { final Properties properties = new Properties(); - final String fileName = getPropertyFromInitParams(filterConfig, "sslConfigFile", null); + final String fileName = getString(ConfigurationKeys.SSL_CONFIG_FILE); if (fileName != null) { FileInputStream fis = null; @@ -106,14 +112,11 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { /** * Gets the configured {@link HostnameVerifier} to use for HTTPS connections * if one is configured for this filter. - * @param filterConfig Servlet filter configuration. * @return Instance of specified host name verifier or null if none specified. */ - protected HostnameVerifier getHostnameVerifier(final FilterConfig filterConfig) { - final String className = getPropertyFromInitParams(filterConfig, "hostnameVerifier", null); - logger.trace("Using hostnameVerifier parameter: {}", className); - final String config = getPropertyFromInitParams(filterConfig, "hostnameVerifierConfig", null); - logger.trace("Using hostnameVerifierConfig parameter: {}", config); + protected HostnameVerifier getHostnameVerifier() { + final Class className = getClass(ConfigurationKeys.HOSTNAME_VERIFIER); + final String config = getString(ConfigurationKeys.HOSTNAME_VERIFIER_CONFIG); if (className != null) { if (config != null) { return ReflectUtils.newInstance(className, config); @@ -125,14 +128,9 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { } protected void initInternal(final FilterConfig filterConfig) throws ServletException { - setExceptionOnValidationFailure(parseBoolean(getPropertyFromInitParams(filterConfig, - "exceptionOnValidationFailure", "false"))); - logger.trace("Setting exceptionOnValidationFailure parameter: {}", this.exceptionOnValidationFailure); - setRedirectAfterValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation", - "true"))); - logger.trace("Setting redirectAfterValidation parameter: {}", this.redirectAfterValidation); - setUseSession(parseBoolean(getPropertyFromInitParams(filterConfig, "useSession", "true"))); - logger.trace("Setting useSession parameter: {}", this.useSession); + setExceptionOnValidationFailure(getBoolean(ConfigurationKeys.EXCEPTION_ON_VALIDATION_FAILURE)); + setRedirectAfterValidation(getBoolean(ConfigurationKeys.REDIRECT_AFTER_VALIDATION)); + setUseSession(getBoolean(ConfigurationKeys.USE_SESSION)); if (!this.useSession && this.redirectAfterValidation) { logger.warn("redirectAfterValidation parameter may not be true when useSession parameter is false. Resetting it to false in order to prevent infinite redirects."); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java index 6e142c9..aca0dee 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java @@ -19,29 +19,36 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; + +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; /** - * Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator. + * Implementation of AbstractTicketValidatorFilter that creates a Cas10TicketValidator. *

Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init * parameters. - * + * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.1 */ public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter { - protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) { - final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null); - final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix); - validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); + public Cas10TicketValidationFilter() { + super(Protocol.CAS1); + } - final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), - getSSLConfig(filterConfig)); + protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) { + final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX); + final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix); + validator.setRenew(getBoolean(ConfigurationKeys.RENEW)); + + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), + getSSLConfig()); validator.setURLConnectionFactory(factory); - validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); + validator.setEncoding(getString(ConfigurationKeys.ENCODING)); return validator; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index e256755..cfea9e7 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -23,6 +23,9 @@ import java.util.*; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.proxy.*; import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; @@ -32,7 +35,7 @@ import org.jasig.cas.client.util.ReflectUtils; /** * Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the * proxy parameters are set. - *

+ *

* This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the * reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}. * @@ -40,20 +43,17 @@ import org.jasig.cas.client.util.ReflectUtils; * @author Brad Cupit (brad [at] lsu {dot} edu) * @version $Revision$ $Date$ * @since 3.1 - * */ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter { - private static final String[] RESERVED_INIT_PARAMS = new String[] { "proxyGrantingTicketStorageClass", + private static final String[] RESERVED_INIT_PARAMS = new String[]{"proxyGrantingTicketStorageClass", "proxyReceptorUrl", "acceptAnyProxy", "allowedProxyChains", "casServerUrlPrefix", "proxyCallbackUrl", "renew", "exceptionOnValidationFailure", "redirectAfterValidation", "useSession", "serverName", "service", "artifactParameterName", "serviceParameterName", "encodeServiceUrl", "millisBetweenCleanUps", - "hostnameVerifier", "encoding", "config", "ticketValidatorClass" }; - - private static final int DEFAULT_MILLIS_BETWEEN_CLEANUPS = 60 * 1000; + "hostnameVerifier", "encoding", "config", "ticketValidatorClass"}; /** - * The URL to send to the CAS server as the URL that will process proxying requests on the CAS client. + * The URL to send to the CAS server as the URL that will process proxying requests on the CAS client. */ private String proxyReceptorUrl; @@ -68,20 +68,22 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal */ private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl(); - protected void initInternal(final FilterConfig filterConfig) throws ServletException { - setProxyReceptorUrl(getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", null)); + public Cas20ProxyReceivingTicketValidationFilter() { + super(Protocol.CAS2); + } - final String proxyGrantingTicketStorageClass = getPropertyFromInitParams(filterConfig, - "proxyGrantingTicketStorageClass", null); + protected void initInternal(final FilterConfig filterConfig) throws ServletException { + setProxyReceptorUrl(getString(ConfigurationKeys.PROXY_RECEPTOR_URL)); + + final Class proxyGrantingTicketStorageClass = getClass(ConfigurationKeys.PROXY_GRANTING_TICKET_STORAGE_CLASS); if (proxyGrantingTicketStorageClass != null) { this.proxyGrantingTicketStorage = ReflectUtils.newInstance(proxyGrantingTicketStorageClass); if (this.proxyGrantingTicketStorage instanceof AbstractEncryptedProxyGrantingTicketStorageImpl) { final AbstractEncryptedProxyGrantingTicketStorageImpl p = (AbstractEncryptedProxyGrantingTicketStorageImpl) this.proxyGrantingTicketStorage; - final String cipherAlgorithm = getPropertyFromInitParams(filterConfig, "cipherAlgorithm", - AbstractEncryptedProxyGrantingTicketStorageImpl.DEFAULT_ENCRYPTION_ALGORITHM); - final String secretKey = getPropertyFromInitParams(filterConfig, "secretKey", null); + final String cipherAlgorithm = getString(ConfigurationKeys.CIPHER_ALGORITHM); + final String secretKey = getString(ConfigurationKeys.SECRET_KEY); p.setCipherAlgorithm(cipherAlgorithm); @@ -95,9 +97,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal } } - logger.trace("Setting proxyReceptorUrl parameter: {}", this.proxyReceptorUrl); - this.millisBetweenCleanUps = Integer.parseInt(getPropertyFromInitParams(filterConfig, "millisBetweenCleanUps", - Integer.toString(DEFAULT_MILLIS_BETWEEN_CLEANUPS))); + this.millisBetweenCleanUps = getInt(ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS); super.initInternal(filterConfig); } @@ -115,13 +115,13 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal this.timer.schedule(this.timerTask, this.millisBetweenCleanUps, this.millisBetweenCleanUps); } - private T createNewTicketValidator(final String ticketValidatorClass, final String casServerUrlPrefix, - final Class clazz) { - if (CommonUtils.isBlank(ticketValidatorClass)) { + private T createNewTicketValidator(final Class ticketValidatorClass, final String casServerUrlPrefix, + final Class clazz) { + if (ticketValidatorClass == null) { return ReflectUtils.newInstance(clazz, casServerUrlPrefix); } - return ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix); + return (T) ReflectUtils.newInstance(ticketValidatorClass, casServerUrlPrefix); } /** @@ -131,38 +131,37 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal * @return a fully constructed TicketValidator. */ protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) { - final String allowAnyProxy = getPropertyFromInitParams(filterConfig, "acceptAnyProxy", null); - final String allowedProxyChains = getPropertyFromInitParams(filterConfig, "allowedProxyChains", null); - final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null); - final String ticketValidatorClass = getPropertyFromInitParams(filterConfig, "ticketValidatorClass", null); + final boolean allowAnyProxy = getBoolean(ConfigurationKeys.ACCEPT_ANY_PROXY); + final String allowedProxyChains = getString(ConfigurationKeys.ALLOWED_PROXY_CHAINS); + final String casServerUrlPrefix = getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX); + final Class ticketValidatorClass = getClass(ConfigurationKeys.TICKET_VALIDATOR_CLASS); final Cas20ServiceTicketValidator validator; - if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) { + if (allowAnyProxy || CommonUtils.isNotBlank(allowedProxyChains)) { final Cas20ProxyTicketValidator v = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix, Cas20ProxyTicketValidator.class); - v.setAcceptAnyProxy(parseBoolean(allowAnyProxy)); + v.setAcceptAnyProxy(allowAnyProxy); v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains)); validator = v; } else { validator = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix, Cas20ServiceTicketValidator.class); } - validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null)); + validator.setProxyCallbackUrl(getString(ConfigurationKeys.PROXY_CALLBACK_URL)); validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage); - final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), - getSSLConfig(filterConfig)); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), + getSSLConfig()); validator.setURLConnectionFactory(factory); - validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig, - "encoding", null), factory)); - validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); + validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getString(ConfigurationKeys.ENCODING), factory)); + validator.setRenew(getBoolean(ConfigurationKeys.RENEW)); + validator.setEncoding(getString(ConfigurationKeys.ENCODING)); final Map additionalParameters = new HashMap(); final List params = Arrays.asList(RESERVED_INIT_PARAMS); - for (final Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) { + for (final Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) { final String s = (String) e.nextElement(); if (!params.contains(s)) { @@ -183,7 +182,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal * This processes the ProxyReceptor request before the ticket validation code executes. */ protected final boolean preFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, - final FilterChain filterChain) throws IOException, ServletException { + final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; final String requestUri = request.getRequestURI(); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 14711ab..73aede0 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -19,13 +19,15 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; -import javax.servlet.ServletException; + +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; /** * Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator. - *

+ *

* Deployers can provide the "casServerUrlPrefix" and "tolerance" properties of the Saml11TicketValidator via the * context or filter init parameters. * @@ -36,34 +38,21 @@ import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter { public Saml11TicketValidationFilter() { - setArtifactParameterName("SAMLart"); - setServiceParameterName("TARGET"); - } - - protected final void initInternal(final FilterConfig filterConfig) throws ServletException { - super.initInternal(filterConfig); - - logger.warn("SAML1.1 compliance requires the [artifactParameterName] and [serviceParameterName] to be set to specified values."); - logger.warn("This filter will overwrite any user-provided values (if any are provided)"); - - setArtifactParameterName("SAMLart"); - setServiceParameterName("TARGET"); + super(Protocol.SAML11); } protected final TicketValidator getTicketValidator(final FilterConfig filterConfig) { - final Saml11TicketValidator validator = new Saml11TicketValidator(getPropertyFromInitParams(filterConfig, - "casServerUrlPrefix", null)); - final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000"); - validator.setTolerance(Long.parseLong(tolerance)); - validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); + final Saml11TicketValidator validator = new Saml11TicketValidator(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX)); + final long tolerance = getLong(ConfigurationKeys.TOLERANCE); + validator.setTolerance(tolerance); + validator.setRenew(getBoolean(ConfigurationKeys.RENEW)); - final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), - getSSLConfig(filterConfig)); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), + getSSLConfig()); validator.setURLConnectionFactory(factory); - validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); - validator.setDisableXmlSchemaValidation(parseBoolean(getPropertyFromInitParams(filterConfig, - "disableXmlSchemaValidation", "false"))); + validator.setEncoding(getString(ConfigurationKeys.ENCODING)); + validator.setDisableXmlSchemaValidation(getBoolean(ConfigurationKeys.DISABLE_XML_SCHEMA_VALIDATION)); return validator; } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java new file mode 100644 index 0000000..add5b3f --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java @@ -0,0 +1,27 @@ +package org.jasig.cas.client.configuration; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public final class ConfigurationKeyTests { + + + @Test + public void gettersWithNoDefaultValue() { + final String name = "name"; + final ConfigurationKey configurationKey = new ConfigurationKey(name); + assertEquals(name, configurationKey.getName()); + assertNull(configurationKey.getDefaultValue()); + } + + + @Test + public void gettersWithDefaultValue() { + final String name = "name"; + final Boolean defaultValue = Boolean.TRUE; + final ConfigurationKey configurationKey = new ConfigurationKey(name, defaultValue); + assertEquals(name, configurationKey.getName()); + assertEquals(defaultValue, configurationKey.getDefaultValue()); + } +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java new file mode 100644 index 0000000..534ecbc --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java @@ -0,0 +1,16 @@ +package org.jasig.cas.client.configuration; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public final class ConfigurationStrategyNameTests { + + @Test + public void stringToClass() { + assertEquals(JndiConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.JNDI.name())); + assertEquals(WebXmlConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.WEB_XML.name())); + assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.DEFAULT.name())); + assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy("bleh!")); + } +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java new file mode 100644 index 0000000..9ec94dc --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java @@ -0,0 +1,128 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.AbstractCasFilter; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockServletContext; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public final class WebXmlConfigurationStrategyImplTests { + + private WebXmlConfigurationStrategyImpl impl; + + private MockFilterConfig filterConfig; + + @Before + public void setUp() throws Exception { + this.filterConfig = new MockFilterConfig(); + this.impl = new WebXmlConfigurationStrategyImpl(); + this.impl.init(this.filterConfig, AbstractCasFilter.class); + } + + + @Test + public void noKeyFoundGetDefaultForBoolean() { + final ConfigurationKey key = ConfigurationKeys.ACCEPT_ANY_PROXY; + assertEquals(key.getDefaultValue(), this.impl.getBoolean(key)); + } + + + @Test + public void noKeyFoundGetDefaultForString() { + final ConfigurationKey key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME; + assertEquals(key.getDefaultValue(), this.impl.getString(key)); + } + + + @Test + public void noKeyFoundGetDefaultForLong() { + final ConfigurationKey key = ConfigurationKeys.TOLERANCE; + assertEquals(key.getDefaultValue().longValue(), this.impl.getLong(key)); + } + + + @Test + public void noKeyFoundGetDefaultForInt() { + final ConfigurationKey key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS; + assertEquals(key.getDefaultValue().intValue(), this.impl.getInt(key)); + } + + @Test + public void filterConfigValueForBoolean() { + final ConfigurationKey key = ConfigurationKeys.ACCEPT_ANY_PROXY; + final Boolean value = Boolean.TRUE; + this.filterConfig.addInitParameter(key.getName(), value.toString()); + assertEquals(value, this.impl.getBoolean(key)); + } + + + @Test + public void filterConfigValueForString() { + final ConfigurationKey key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME; + final String value = "foobar"; + this.filterConfig.addInitParameter(key.getName(), value); + assertEquals(value, this.impl.getString(key)); + } + + + @Test + public void filterConfigValueForLong() { + final ConfigurationKey key = ConfigurationKeys.TOLERANCE; + final long value = 1500; + this.filterConfig.addInitParameter(key.getName(), Long.toString(value)); + assertEquals(value, this.impl.getLong(key)); + } + + + @Test + public void filterConfigValueForInt() { + final ConfigurationKey key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS; + final int value = 1500; + this.filterConfig.addInitParameter(key.getName(), Integer.toString(value)); + assertEquals(value, this.impl.getInt(key)); + } + + + @Test + public void servletConfigValueForBoolean() { + final ConfigurationKey key = ConfigurationKeys.ACCEPT_ANY_PROXY; + final Boolean value = Boolean.TRUE; + final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext(); + context.addInitParameter(key.getName(), value.toString()); + assertEquals(value, this.impl.getBoolean(key)); + } + + + @Test + public void servletConfigValueForString() { + final ConfigurationKey key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME; + final String value = "foobar"; + final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext(); + context.addInitParameter(key.getName(), value); + assertEquals(value, this.impl.getString(key)); + } + + + @Test + public void servletConfigValueForLong() { + final ConfigurationKey key = ConfigurationKeys.TOLERANCE; + final long value = 1500; + final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext(); + context.addInitParameter(key.getName(), Long.toString(value)); + assertEquals(value, this.impl.getLong(key)); + } + + + @Test + public void servletConfigValueForInt() { + final ConfigurationKey key = ConfigurationKeys.MILLIS_BETWEEN_CLEAN_UPS; + final int value = 1500; + final MockServletContext context = (MockServletContext) this.filterConfig.getServletContext(); + context.addInitParameter(key.getName(), Integer.toString(value)); + assertEquals(value, this.impl.getInt(key)); + } + +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java index 7c91f8f..93fd665 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java @@ -25,6 +25,8 @@ import java.io.IOException; import javax.servlet.ServletException; +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.configuration.ConfigurationKeys; import org.junit.Before; import org.junit.Test; import org.springframework.mock.web.MockFilterChain; @@ -35,12 +37,12 @@ import org.springframework.mock.web.MockHttpSession; /** * Tests {@link SingleSignOutFilter}. - * + * * @author Jerome Leleu * @since 3.3.1 */ public class SingleSignOutFilterTests { - + private final static String CAS_SERVER_URL_PREFIX = "http://myhost.com/mycasserver"; private final static String TICKET = "ST-yyyyy"; private final static String RELAY_STATE = "e1s1"; @@ -49,7 +51,7 @@ public class SingleSignOutFilterTests { private MockHttpServletRequest request; private MockHttpServletResponse response; private MockFilterChain filterChain; - + @Before public void setUp() throws Exception { filter = new SingleSignOutFilter(); @@ -60,11 +62,11 @@ public class SingleSignOutFilterTests { response = new MockHttpServletResponse(); filterChain = new MockFilterChain(); } - + @Test public void tokenRequest() throws IOException, ServletException { - request.setParameter(SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME, TICKET); - request.setQueryString(SingleSignOutHandler.DEFAULT_ARTIFACT_PARAMETER_NAME + "=" + TICKET); + request.setParameter(Protocol.CAS2.getArtifactParameterName(), TICKET); + request.setQueryString(Protocol.CAS2.getArtifactParameterName() + "=" + TICKET); final MockHttpSession session = new MockHttpSession(); request.setSession(session); filter.doFilter(request, response, filterChain); @@ -73,7 +75,7 @@ public class SingleSignOutFilterTests { @Test public void backChannelRequest() throws IOException, ServletException { - request.setParameter(SingleSignOutHandler.DEFAULT_LOGOUT_PARAMETER_NAME, + request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(), LogoutMessageGenerator.generateBackChannelLogoutMessage(TICKET)); request.setMethod("POST"); final MockHttpSession session = new MockHttpSession(); @@ -85,8 +87,8 @@ public class SingleSignOutFilterTests { @Test public void frontChannelRequest() throws IOException, ServletException { final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME, logoutMessage); - request.setQueryString(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage); + request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); + request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage); request.setMethod("GET"); final MockHttpSession session = new MockHttpSession(); SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); @@ -98,16 +100,16 @@ public class SingleSignOutFilterTests { @Test public void frontChannelRequestRelayState() throws IOException, ServletException { final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME, logoutMessage); - request.setParameter(SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME, RELAY_STATE); - request.setQueryString(SingleSignOutHandler.DEFAULT_FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" + - SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME + "=" + RELAY_STATE); + request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); + request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE); + request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage + "&" + + ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE); request.setMethod("GET"); final MockHttpSession session = new MockHttpSession(); SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); filter.doFilter(request, response, filterChain); assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); assertEquals(CAS_SERVER_URL_PREFIX + "/logout?_eventId=next&" + - SingleSignOutHandler.DEFAULT_RELAY_STATE_PARAMETER_NAME + "=" + RELAY_STATE, response.getRedirectedUrl()); + ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/CasFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/CasFilterTests.java index 758dc9d..8960870 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/CasFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/CasFilterTests.java @@ -24,6 +24,8 @@ import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; + +import org.jasig.cas.client.Protocol; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -55,6 +57,10 @@ public final class CasFilterTests { } private static class TestCasFilter extends AbstractCasFilter { + + public TestCasFilter() { + super(Protocol.CAS2); + } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // nothing to do diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java index 8ccdb2f..f2da173 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java @@ -50,7 +50,10 @@ public class Cas10TicketValidationFilterTests { final MockServletContext context = new MockServletContext(); context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); context.addInitParameter("renew", "true"); - final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + context.addInitParameter("service", "http://www.jasig.org"); + final MockFilterConfig config = new MockFilterConfig(context); + f.init(config); + final TicketValidator validator = f.getTicketValidator(config); assertTrue(validator instanceof Cas10TicketValidator); assertTrue(((Cas10TicketValidator) validator).isRenew()); } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java index 89e900a..7c11042 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java @@ -25,6 +25,7 @@ import org.jasig.cas.client.proxy.CleanUpTimerTask; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; import org.jasig.cas.client.util.MethodFlag; +import org.junit.Test; import org.springframework.mock.web.MockFilterConfig; import org.springframework.mock.web.MockServletContext; @@ -148,32 +149,40 @@ public class Cas20ProxyReceivingTicketValidationFilterTests extends TestCase { public void testGetTicketValidator() throws Exception { Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter(); - filter.setProxyGrantingTicketStorage(storage); - filter.setMillisBetweenCleanUps(250); - filter.setTimer(defaultTimer); - filter.setTimerTask(new TimerTask() { - public void run() { - } - }); - filter.init(); // Test case #1 final MockFilterConfig config1 = new MockFilterConfig(); config1.addInitParameter("allowedProxyChains", "https://a.example.com"); config1.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/"); + config1.addInitParameter("service", "http://www.jasig.org"); + filter.init(config1); assertNotNull(filter.getTicketValidator(config1)); + } + @Test + public void getTicketValidatorWithProxyChains() throws Exception { + Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter(); // Test case #2 final MockFilterConfig config2 = new MockFilterConfig(); config2.addInitParameter("allowedProxyChains", "https://a.example.com https://b.example.com"); config2.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/"); + config2.addInitParameter("service", "http://www.jasig.org"); + filter.init(config2); assertNotNull(filter.getTicketValidator(config2)); + } + + + @Test + public void getTIcketValidatorWithProxyChainsAndLineBreak() throws Exception { + Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter(); // Test case #3 final MockFilterConfig config3 = new MockFilterConfig(); config3.addInitParameter("allowedProxyChains", "https://a.example.com https://b.example.com\nhttps://c.example.com"); config3.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/"); + config3.addInitParameter("service", "http://www.jasig.org"); + filter.init(config3); assertNotNull(filter.getTicketValidator(config3)); } @@ -195,7 +204,10 @@ public class Cas20ProxyReceivingTicketValidationFilterTests extends TestCase { final MockServletContext context = new MockServletContext(); context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); context.addInitParameter("renew", "true"); - final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + context.addInitParameter("service", "http://www.jasig.org"); + final MockFilterConfig config = new MockFilterConfig(context); + f.init(config); + final TicketValidator validator = f.getTicketValidator(config); assertTrue(validator instanceof AbstractUrlBasedTicketValidator); assertTrue(((AbstractUrlBasedTicketValidator) validator).isRenew()); } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java index 53d1875..e4db128 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java @@ -20,6 +20,7 @@ package org.jasig.cas.client.validation; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + import org.junit.Test; import org.springframework.mock.web.MockFilterConfig; import org.springframework.mock.web.MockServletContext; @@ -50,7 +51,10 @@ public class Saml11TicketValidationFilterTests { final MockServletContext context = new MockServletContext(); context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); context.addInitParameter("renew", "true"); - final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + context.addInitParameter("service", "http://www.jasig.org"); + final MockFilterConfig config = new MockFilterConfig(context); + f.init(config); + final TicketValidator validator = f.getTicketValidator(config); assertTrue(validator instanceof Saml11TicketValidator); assertTrue(((Saml11TicketValidator) validator).isRenew()); } diff --git a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java new file mode 100644 index 0000000..99e2a0c --- /dev/null +++ b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java @@ -0,0 +1,16 @@ +package org.jasig.cas.client.configuration; + +/** + * Simple extension to the {@link org.jasig.cas.client.configuration.JndiConfigurationStrategyImpl} to provide a JBoss 7 compatible prefix. + * + * @author Scott Battaglia + * @since 3.4.0 + */ +public final class JBossCompatibleJndiConfigurationStrategyImpl extends JndiConfigurationStrategyImpl { + + private static final String ENVIRONMENT_PREFIX = "java:/comp/env/cas/"; + + public JBossCompatibleJndiConfigurationStrategyImpl() { + super(ENVIRONMENT_PREFIX); + } +} diff --git a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java index cb4c45a..597d495 100644 --- a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java +++ b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/jboss/authentication/WebAuthenticationFilter.java @@ -27,6 +27,8 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; + +import org.jasig.cas.client.Protocol; import org.jasig.cas.client.jaas.AssertionPrincipal; import org.jasig.cas.client.util.AbstractCasFilter; import org.jasig.cas.client.util.CommonUtils; @@ -50,12 +52,16 @@ import org.jboss.web.tomcat.security.login.WebAuthentication; */ public final class WebAuthenticationFilter extends AbstractCasFilter { + public WebAuthenticationFilter() { + super(Protocol.CAS2); + } + public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; final HttpSession session = request.getSession(); - final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName()); + final String ticket = CommonUtils.safeGetParameter(request, getProtocol().getArtifactParameterName()); if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) { try { From 324b0919b63355de8b7963d30b81acc9a750fb4b Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Wed, 9 Apr 2014 22:33:57 -0400 Subject: [PATCH 18/57] Added additional keys that were new from the single signout refactor. --- .../java/org/jasig/cas/client/session/SingleSignOutFilter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index da533cf..5720a69 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -42,6 +42,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { private AtomicBoolean handlerInitialized = new AtomicBoolean(false); public void init(final FilterConfig filterConfig) throws ServletException { + super.init(filterConfig); if (!isIgnoreInitConfiguration()) { setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME)); setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME)); From 17f887595fe9d701589534c1a826ce90106fe9b6 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Thu, 20 Nov 2014 15:58:52 -0500 Subject: [PATCH 19/57] Added missing javadoc for Protocol enumeration --- .../main/java/org/jasig/cas/client/Protocol.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java index 184104f..b484d11 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java @@ -1,13 +1,14 @@ package org.jasig.cas.client; /** - * Created by battags on 10/14/14. + * Simple enumeration to hold/capture some of the standard request parameters used by the various protocols. + * + * @author Scott Battaglia + * @since 3.4.0 */ public enum Protocol { - - - CAS1("ticket", "service"), CAS2(CAS1.getArtifactParameterName(), CAS1.getServiceParameterName()), SAML11("SAMLart", "TARGET"); + CAS1("ticket", "service"), CAS2(CAS1), SAML11("SAMLart", "TARGET"); private final String artifactParameterName; @@ -18,6 +19,10 @@ public enum Protocol { this.serviceParameterName = serviceParameterName; } + private Protocol(final Protocol protocol) { + this(protocol.getArtifactParameterName(), protocol.getServiceParameterName()); + } + public String getArtifactParameterName() { return this.artifactParameterName; } From d011f5e64ab627a7e558a6e181f35af381ed4250 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Thu, 20 Nov 2014 16:01:02 -0500 Subject: [PATCH 20/57] Removed unused mockito dependency --- cas-client-core/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 3cecc14..f37b084 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -75,13 +75,6 @@ test - - org.mockito - mockito-all - 1.10.8 - test - - log4j log4j From c7e66d7df28337f515dbf133e1b63f03d3e51692 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Thu, 20 Nov 2014 16:03:19 -0500 Subject: [PATCH 21/57] Unused reference to Mockito --- .../configuration/WebXmlConfigurationStrategyImplTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java index 9ec94dc..5037133 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java @@ -7,7 +7,6 @@ import org.springframework.mock.web.MockFilterConfig; import org.springframework.mock.web.MockServletContext; import static org.junit.Assert.*; -import static org.mockito.Mockito.*; public final class WebXmlConfigurationStrategyImplTests { From 51a9192792366d404357c30d6022bc4a22aa04b8 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Thu, 20 Nov 2014 16:29:29 -0500 Subject: [PATCH 22/57] CASC-233 ErrorRedirectFilter Can throw Null Pointer Exception Problem: the ErrorRedirectFilter assumes there is a root cause and will null pointer if there is not. Solution: Only use the root cause if there is one, otherwise use the original exception. QA Notes: Added unit test to confirm non-root cause error. --- .../cas/client/util/ErrorRedirectFilter.java | 28 ++++++++--- .../client/util/ErrorRedirectFilterTests.java | 48 +++++++++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java index 74496c0..dd6f4a2 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java @@ -24,22 +24,22 @@ import java.util.Enumeration; import java.util.List; import javax.servlet.*; import javax.servlet.http.HttpServletResponse; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Filters that redirects to the supplied url based on an exception. Exceptions and the urls are configured via * init filter name/param values. - *

+ *

* If there is an exact match the filter uses that value. If there's a non-exact match (i.e. inheritance), then the filter * uses the last value that matched. - *

+ *

* If there is no match it will redirect to a default error page. The default exception is configured via the "defaultErrorRedirectPage" property. - * + * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.1.4 - * */ public final class ErrorRedirectFilter implements Filter { @@ -58,8 +58,8 @@ public final class ErrorRedirectFilter implements Filter { final HttpServletResponse httpResponse = (HttpServletResponse) response; try { filterChain.doFilter(request, response); - } catch (final ServletException e) { - final Throwable t = e.getCause(); + } catch (final Throwable e) { + final Throwable t = extractErrorToCompare(e); ErrorHolder currentMatch = null; for (final ErrorHolder errorHolder : this.errors) { if (errorHolder.exactMatch(t)) { @@ -78,6 +78,22 @@ public final class ErrorRedirectFilter implements Filter { } } + /** + * Determine which error to use for comparison. If there is an {@link Throwable#getCause()} then that will be used. Otherwise, the original throwable is used. + * + * @param throwable the throwable to look for a root cause. + * @return the throwable to use for comparison. MUST NOT BE NULL. + */ + private Throwable extractErrorToCompare(final Throwable throwable) { + final Throwable cause = throwable.getCause(); + + if (cause != null) { + return cause; + } + + return throwable; + } + public void init(final FilterConfig filterConfig) throws ServletException { this.defaultErrorRedirectPage = filterConfig.getInitParameter("defaultErrorRedirectPage"); diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java new file mode 100644 index 0000000..b79daf4 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java @@ -0,0 +1,48 @@ +package org.jasig.cas.client.util; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockFilterChain; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import javax.servlet.FilterChain; + +import static org.junit.Assert.*; + +public final class ErrorRedirectFilterTests { + + private static final String REDIRECT_URL = "/ise.html"; + + private ErrorRedirectFilter errorRedirectFilter; + + private FilterChain filterChain; + + + @Before + public void setUp() throws Exception { + this.errorRedirectFilter = new ErrorRedirectFilter(); + + final MockFilterConfig filterConfig = new MockFilterConfig(); + filterConfig.addInitParameter(IllegalStateException.class.getName(), REDIRECT_URL); + this.errorRedirectFilter.init(filterConfig); + this.filterChain = new MockFilterChain(); + } + + + @Test + public void noRootCause() throws Exception { + final MockHttpServletRequest request = new MockHttpServletRequest(); + final MockHttpServletResponse response = new MockHttpServletResponse(); + + // this should be okay as the mock filter chain allows one call + this.errorRedirectFilter.doFilter(request, response, this.filterChain); + + // this will fail as the mock filter chain will throw IllegalStateException + this.errorRedirectFilter.doFilter(request, response, this.filterChain); + + assertEquals(REDIRECT_URL, response.getRedirectedUrl()); + + } +} From 5109132df3756984bd7ade63fe6dc70cd04314d9 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Wed, 26 Nov 2014 22:31:01 -0500 Subject: [PATCH 23/57] Per feedback, scoped catch block to Exception instead of Throwable --- .../java/org/jasig/cas/client/util/ErrorRedirectFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java index dd6f4a2..b1425a4 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ErrorRedirectFilter.java @@ -58,7 +58,7 @@ public final class ErrorRedirectFilter implements Filter { final HttpServletResponse httpResponse = (HttpServletResponse) response; try { filterChain.doFilter(request, response); - } catch (final Throwable e) { + } catch (final Exception e) { final Throwable t = extractErrorToCompare(e); ErrorHolder currentMatch = null; for (final ErrorHolder errorHolder : this.errors) { From 3af5683dc172f555df62336ad1b02872d2b783c6 Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Wed, 26 Nov 2014 22:58:12 -0500 Subject: [PATCH 24/57] Addressed formatting feedback as well as reserved keywords. --- .../Saml11AuthenticationFilter.java | 2 +- .../client/configuration/ConfigurationKey.java | 3 +++ .../configuration/ConfigurationStrategy.java | 1 - ...Cas20ProxyReceivingTicketValidationFilter.java | 15 ++++++++++----- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java index 63483b2..8a7ddae 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java @@ -21,7 +21,7 @@ package org.jasig.cas.client.authentication; import org.jasig.cas.client.Protocol; /** - * Extension to the default Authentication filter that sets the required SAML11.1 artifact parameter name and service parameter name. + * Extension to the default Authentication filter that sets the required SAML1.1 artifact parameter name and service parameter name. *

* Note, as of 3.3, the final keyword was removed to allow you to override the method to retrieve tickets, per CASC-154 * diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java index f6c0df7..dfe5150 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java @@ -1,5 +1,7 @@ package org.jasig.cas.client.configuration; +import org.jasig.cas.client.util.CommonUtils; + /** * Holder class to represent a particular configuration key and its optional default value. * @@ -17,6 +19,7 @@ public final class ConfigurationKey { } public ConfigurationKey(final String name, final E defaultValue) { + CommonUtils.assertNotNull(name, "name must not be null."); this.name = name; this.defaultValue = defaultValue; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java index cd1b9dd..15905ea 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java @@ -11,7 +11,6 @@ import javax.servlet.FilterConfig; */ public interface ConfigurationStrategy { - /** * Retrieves the value for the provided {@param configurationKey}, falling back to the {@param configurationKey}'s {@link ConfigurationKey#getDefaultValue()} if nothing can be found. * diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index cfea9e7..8c7a632 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -32,6 +32,8 @@ import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.ReflectUtils; +import static org.jasig.cas.client.configuration.ConfigurationKeys.*; + /** * Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the * proxy parameters are set. @@ -46,11 +48,14 @@ import org.jasig.cas.client.util.ReflectUtils; */ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter { - private static final String[] RESERVED_INIT_PARAMS = new String[]{"proxyGrantingTicketStorageClass", - "proxyReceptorUrl", "acceptAnyProxy", "allowedProxyChains", "casServerUrlPrefix", "proxyCallbackUrl", - "renew", "exceptionOnValidationFailure", "redirectAfterValidation", "useSession", "serverName", "service", - "artifactParameterName", "serviceParameterName", "encodeServiceUrl", "millisBetweenCleanUps", - "hostnameVerifier", "encoding", "config", "ticketValidatorClass"}; + private static final String[] RESERVED_INIT_PARAMS = new String[]{ARTIFACT_PARAMETER_NAME.getName(), SERVER_NAME.getName(), SERVICE.getName(), RENEW.getName(), LOGOUT_PARAMETER_NAME.getName(), + ARTIFACT_PARAMETER_OVER_POST.getName(), EAGERLY_CREATE_SESSIONS.getName(), ENCODE_SERVICE_URL.getName(), SSL_CONFIG_FILE.getName(), ROLE_ATTRIBUTE.getName(), IGNORE_CASE.getName(), + CAS_SERVER_LOGIN_URL.getName(), GATEWAY.getName(), AUTHENTICATION_REDIRECT_STRATEGY_CLASS.getName(), GATEWAY_STORAGE_CLASS.getName(), CAS_SERVER_URL_PREFIX.getName(), ENCODING.getName(), + TOLERANCE.getName(), DISABLE_XML_SCHEMA_VALIDATION.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(), + EXCEPTION_ON_VALIDATION_FAILURE.getName(), REDIRECT_AFTER_VALIDATION.getName(), USE_SESSION.getName(), SECRET_KEY.getName(), CIPHER_ALGORITHM.getName(), PROXY_RECEPTOR_URL.getName(), + PROXY_GRANTING_TICKET_STORAGE_CLASS.getName(), MILLIS_BETWEEN_CLEAN_UPS.getName(), ACCEPT_ANY_PROXY.getName(), ALLOWED_PROXY_CHAINS.getName(), TICKET_VALIDATOR_CLASS.getName(), + PROXY_CALLBACK_URL.getName(), FRONT_LOGOUT_PARAMETER_NAME.getName(), RELAY_STATE_PARAMETER_NAME.getName() + }; /** * The URL to send to the CAS server as the URL that will process proxying requests on the CAS client. From bef2a886037864e904e1fce4b81034052c219bfe Mon Sep 17 00:00:00 2001 From: Scott Battaglia Date: Sun, 30 Nov 2014 17:09:09 -0500 Subject: [PATCH 25/57] Updated try/catch loop to log when a class is not found. --- .../cas/client/configuration/ConfigurationStrategyName.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java index ea089fe..bc257f2 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java @@ -1,6 +1,8 @@ package org.jasig.cas.client.configuration; import org.jasig.cas.client.util.CommonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Enumeration to map simple names to the underlying classes so that deployers can reference the simple name in the @@ -13,6 +15,8 @@ public enum ConfigurationStrategyName { DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStrategyName.class); + private final Class configurationStrategyClass; private ConfigurationStrategyName(final Class configurationStrategyClass) { @@ -43,7 +47,7 @@ public enum ConfigurationStrategyName { return (Class) clazz; } } catch (final ClassNotFoundException e) { - // nothing we can do here + LOGGER.error("Unable to locate strategy {} by name or class name. Using default strategy instead.", value, e); } return DEFAULT.configurationStrategyClass; From d1da02f457b667d6f4f277d1bac6e48bad297fc2 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 7 Dec 2014 13:32:14 -0500 Subject: [PATCH 26/57] CASC-231 HttpsURLConnectonFactory is Not Serializable Problem: THe HttpsURLConnectionFactory is not serializable, causing problems for clients that must serialize the principal (which depends on a ProxyRetriever). Solution: Make the HttpsURLConnectionFactory serializable. QA Notes: added unit test to confirm serialize-deserialize --- .../client/ssl/HttpURLConnectionFactory.java | 3 +- .../client/ssl/HttpsURLConnectionFactory.java | 46 ++++++++++++++++++- .../cas/client/ssl/RegexHostnameVerifier.java | 5 +- .../client/ssl/WhitelistHostnameVerifier.java | 5 +- .../ssl/HttpsURLConnectionFactoryTests.java | 37 +++++++++++++++ .../ssl/WhitelistHostnameVerifierTests.java | 2 +- 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java index e280b7a..8ea298f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java @@ -18,6 +18,7 @@ */ package org.jasig.cas.client.ssl; +import java.io.Serializable; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; @@ -28,7 +29,7 @@ import java.net.URLConnection; * @author Misagh Moayyed * @since 3.3 */ -public interface HttpURLConnectionFactory { +public interface HttpURLConnectionFactory extends Serializable { /** * Receives a {@link URLConnection} instance typically as a result of a {@link URL} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index d0b2308..cede908 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -18,8 +18,7 @@ */ package org.jasig.cas.client.ssl; -import java.io.FileInputStream; -import java.io.InputStream; +import java.io.*; import java.net.HttpURLConnection; import java.net.URLConnection; import java.security.KeyStore; @@ -41,6 +40,8 @@ import org.slf4j.LoggerFactory; */ public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class); /** @@ -146,4 +147,45 @@ public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory return null; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final HttpsURLConnectionFactory that = (HttpsURLConnectionFactory) o; + + if (!hostnameVerifier.equals(that.hostnameVerifier)) return false; + if (!sslConfiguration.equals(that.sslConfiguration)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = hostnameVerifier.hashCode(); + result = 31 * result + sslConfiguration.hashCode(); + return result; + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + if (this.hostnameVerifier == HttpsURLConnection.getDefaultHostnameVerifier()) { + out.writeObject(null); + } else { + out.writeObject(this.hostnameVerifier); + } + + out.writeObject(this.sslConfiguration); + + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + final Object internalHostNameVerifier = in.readObject(); + if (internalHostNameVerifier == null) { + this.hostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + } else { + this.hostnameVerifier = (HostnameVerifier) internalHostNameVerifier; + } + + this.sslConfiguration = (Properties) in.readObject(); + } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/RegexHostnameVerifier.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/RegexHostnameVerifier.java index 1576364..a13c9f7 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/RegexHostnameVerifier.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/RegexHostnameVerifier.java @@ -19,6 +19,7 @@ package org.jasig.cas.client.ssl; +import java.io.Serializable; import java.util.regex.Pattern; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; @@ -32,7 +33,9 @@ import javax.net.ssl.SSLSession; * @since 3.1.10 * */ -public final class RegexHostnameVerifier implements HostnameVerifier { +public final class RegexHostnameVerifier implements HostnameVerifier, Serializable { + + private static final long serialVersionUID = 1L; /** Allowed hostname pattern */ private Pattern pattern; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifier.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifier.java index db9abb5..c882225 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifier.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifier.java @@ -20,6 +20,7 @@ package org.jasig.cas.client.ssl; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; +import java.io.Serializable; /** * Verifies a SSL peer host name based on an explicit whitelist of allowed hosts. @@ -29,7 +30,9 @@ import javax.net.ssl.SSLSession; * @since 3.1.10 * */ -public final class WhitelistHostnameVerifier implements HostnameVerifier { +public final class WhitelistHostnameVerifier implements HostnameVerifier, Serializable { + + private static final long serialVersionUID = 1L; /** Allowed hosts */ private String[] allowedHosts; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java new file mode 100644 index 0000000..f5d11d1 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java @@ -0,0 +1,37 @@ +package org.jasig.cas.client.ssl; + +import org.junit.Before; +import org.junit.Test; + +import java.io.*; + +import static org.junit.Assert.*; + +public final class HttpsURLConnectionFactoryTests { + + private HttpsURLConnectionFactory httpsURLConnectionFactory; + + + @Before + public void setUp() throws Exception { + this.httpsURLConnectionFactory = new HttpsURLConnectionFactory(); + } + + + @Test + public void serializeAndDeserialize() throws Exception { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(this.httpsURLConnectionFactory); + oos.close(); + + final byte[] serializedHttpsUrlConnectionFactory = baos.toByteArray(); + + final ByteArrayInputStream bais = new ByteArrayInputStream(serializedHttpsUrlConnectionFactory); + final ObjectInputStream ois = new ObjectInputStream(bais); + + final HttpsURLConnectionFactory deserializedObject = (HttpsURLConnectionFactory) ois.readObject(); + assertEquals(this.httpsURLConnectionFactory, deserializedObject); + } +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifierTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifierTests.java index a021c75..92a41f5 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifierTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/WhitelistHostnameVerifierTests.java @@ -43,7 +43,7 @@ import junit.framework.TestCase; */ public class WhitelistHostnameVerifierTests extends TestCase { /** - * Test method for {@link WhitelistHostnameVerifier#verify(String, SSLSession)}. + * Test method for {@link WhitelistHostnameVerifier#verify(String, javax.net.ssl.SSLSession)}. */ public void testVerify() { final WhitelistHostnameVerifier verifier = new WhitelistHostnameVerifier("red.vt.edu, green.vt.edu,blue.vt.edu"); From 39f0f29dd9784996e50122f7c01bc83d2ec16b26 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 7 Dec 2014 14:14:08 -0500 Subject: [PATCH 27/57] CASC-200 Introduce Properties File Configuration Option Problem: We can configure via JNDI, WebXML (or both) but not by properties file. Solution: Introduce a method to use property files. --- .../ConfigurationStrategyName.java | 2 +- .../PropertiesConfigurationStrategyImpl.java | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java index bc257f2..d4b46ab 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java @@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory; */ public enum ConfigurationStrategyName { - DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class); + DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class), PROPERTY_FILE(PropertiesConfigurationStrategyImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStrategyName.class); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java new file mode 100644 index 0000000..7222abe --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java @@ -0,0 +1,83 @@ +package org.jasig.cas.client.configuration; + +import org.jasig.cas.client.util.CommonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +/** + * @author Scott Battaglia + * @since 3.4.0 + */ +public final class PropertiesConfigurationStrategyImpl extends BaseConfigurationStrategy { + + /** + * Property name we'll use in the {@link javax.servlet.FilterConfig} and {@link javax.servlet.ServletConfig} to try and find where + * you stored the configuration file. + */ + private static final String CONFIGURATION_FILE_LOCATION = "configFileLocation"; + + /** + * Default location of the configuration file. Mostly for testing/demo. You will most likely want to configure an alternative location. + */ + private static final String DEFAULT_CONFIGURATION_FILE_LOCATION = "/etc/java-cas-client.properties"; + + private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesConfigurationStrategyImpl.class); + + private String simpleFilterName; + + private Properties properties = new Properties(); + + @Override + protected String get(final ConfigurationKey configurationKey) { + final String property = configurationKey.getName(); + final String filterSpecificProperty = this.simpleFilterName + "." + property; + + final String filterSpecificValue = this.properties.getProperty(filterSpecificProperty); + + if (CommonUtils.isNotEmpty(filterSpecificValue)) { + return filterSpecificValue; + } + + return this.properties.getProperty(property); + } + + public void init(final FilterConfig filterConfig, final Class filterClazz) { + this.simpleFilterName = filterClazz.getSimpleName(); + final String fileLocationFromFilterConfig = filterConfig.getInitParameter(CONFIGURATION_FILE_LOCATION); + final boolean filterConfigFileLoad = loadPropertiesFromFile(fileLocationFromFilterConfig); + + if (!filterConfigFileLoad) { + final String fileLocationFromServletConfig = filterConfig.getServletContext().getInitParameter(CONFIGURATION_FILE_LOCATION); + final boolean servletContextFileLoad = loadPropertiesFromFile(fileLocationFromServletConfig); + + if (!servletContextFileLoad) { + final boolean defaultConfigFileLoaded = loadPropertiesFromFile(DEFAULT_CONFIGURATION_FILE_LOCATION); + CommonUtils.assertTrue(defaultConfigFileLoaded, "unable to load properties to configure CAS client"); + } + } + } + + private boolean loadPropertiesFromFile(final String file) { + if (CommonUtils.isEmpty(file)) { + return false; + } + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + this.properties.load(fis); + return true; + } catch (final IOException e) { + LOGGER.warn("Unable to load properties for file {}", file, e); + return false; + } finally { + CommonUtils.closeQuietly(fis); + } + } +} From ec92d9751866affeaadc5f075a6df46cb7eaaf98 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 22 Dec 2014 23:55:23 -0500 Subject: [PATCH 28/57] Added license headers --- .../java/org/jasig/cas/client/Protocol.java | 18 ++++++++++++++++++ .../BaseConfigurationStrategy.java | 18 ++++++++++++++++++ .../client/configuration/ConfigurationKey.java | 18 ++++++++++++++++++ .../configuration/ConfigurationKeys.java | 18 ++++++++++++++++++ .../configuration/ConfigurationStrategy.java | 18 ++++++++++++++++++ .../ConfigurationStrategyName.java | 18 ++++++++++++++++++ .../JndiConfigurationStrategyImpl.java | 18 ++++++++++++++++++ .../LegacyConfigurationStrategyImpl.java | 18 ++++++++++++++++++ .../PropertiesConfigurationStrategyImpl.java | 18 ++++++++++++++++++ .../WebXmlConfigurationStrategyImpl.java | 18 ++++++++++++++++++ .../configuration/ConfigurationKeyTests.java | 18 ++++++++++++++++++ .../ConfigurationStrategyNameTests.java | 18 ++++++++++++++++++ .../WebXmlConfigurationStrategyImplTests.java | 18 ++++++++++++++++++ .../ssl/HttpsURLConnectionFactoryTests.java | 18 ++++++++++++++++++ .../client/util/ErrorRedirectFilterTests.java | 18 ++++++++++++++++++ ...ompatibleJndiConfigurationStrategyImpl.java | 18 ++++++++++++++++++ 16 files changed, 288 insertions(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java index b484d11..e26761d 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java @@ -1,3 +1,21 @@ +/* + * 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; /** diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java index 384f89d..79872c5 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.apache.commons.lang.BooleanUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java index dfe5150..da6a3a1 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKey.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java index 138c459..9418151 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.Protocol; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java index 15905ea..1493d72 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategy.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import javax.servlet.Filter; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java index d4b46ab..e180d26 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java index b81f1ee..6fcaa11 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/JndiConfigurationStrategyImpl.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java index d1f47c3..a9af77c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/LegacyConfigurationStrategyImpl.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java index 7222abe..5dd7dd9 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/PropertiesConfigurationStrategyImpl.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java index 1c05b0b..634b9f1 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImpl.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.CommonUtils; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java index add5b3f..3a93a41 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationKeyTests.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.junit.Test; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java index 534ecbc..1fb2ee1 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.junit.Test; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java index 5037133..57c66d5 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/WebXmlConfigurationStrategyImplTests.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; import org.jasig.cas.client.util.AbstractCasFilter; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java index f5d11d1..321d978 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactoryTests.java @@ -1,3 +1,21 @@ +/* + * 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.ssl; import org.junit.Before; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java index b79daf4..69ad9aa 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/ErrorRedirectFilterTests.java @@ -1,3 +1,21 @@ +/* + * 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.util; import org.junit.Before; diff --git a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java index 99e2a0c..1675f48 100644 --- a/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java +++ b/cas-client-integration-jboss/src/main/java/org/jasig/cas/client/configuration/JBossCompatibleJndiConfigurationStrategyImpl.java @@ -1,3 +1,21 @@ +/* + * 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.configuration; /** From 2a98556daa88cc901c7bfc2dfa82677fc8086544 Mon Sep 17 00:00:00 2001 From: LELEU Jerome Date: Mon, 5 Jan 2015 15:55:33 +0100 Subject: [PATCH 29/57] CASC-217: Update the ticket validators to point to the new endpoint First commit --- .../java/org/jasig/cas/client/Protocol.java | 2 +- ...0ProxyReceivingTicketValidationFilter.java | 16 ++++++-- ...0ProxyReceivingTicketValidationFilter.java | 40 +++++++++++++++++++ .../validation/Cas30ProxyTicketValidator.java | 37 +++++++++++++++++ .../Cas30ServiceTicketValidator.java | 37 +++++++++++++++++ 5 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyReceivingTicketValidationFilter.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ServiceTicketValidator.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java index e26761d..bf259aa 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/Protocol.java @@ -26,7 +26,7 @@ package org.jasig.cas.client; */ public enum Protocol { - CAS1("ticket", "service"), CAS2(CAS1), SAML11("SAMLart", "TARGET"); + CAS1("ticket", "service"), CAS2(CAS1), CAS3(CAS2), SAML11("SAMLart", "TARGET"); private final String artifactParameterName; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index 8c7a632..deefe22 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -68,13 +68,23 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal private int millisBetweenCleanUps; + protected Class defaultServiceTicketValidatorClass; + + protected Class defaultProxyTicketValidatorClass; + /** * Storage location of ProxyGrantingTickets and Proxy Ticket IOUs. */ private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl(); public Cas20ProxyReceivingTicketValidationFilter() { - super(Protocol.CAS2); + this(Protocol.CAS2); + this.defaultServiceTicketValidatorClass = Cas20ServiceTicketValidator.class; + this.defaultProxyTicketValidatorClass = Cas20ProxyTicketValidator.class; + } + + protected Cas20ProxyReceivingTicketValidationFilter(final Protocol protocol) { + super(protocol); } protected void initInternal(final FilterConfig filterConfig) throws ServletException { @@ -144,13 +154,13 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal if (allowAnyProxy || CommonUtils.isNotBlank(allowedProxyChains)) { final Cas20ProxyTicketValidator v = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix, - Cas20ProxyTicketValidator.class); + this.defaultProxyTicketValidatorClass); v.setAcceptAnyProxy(allowAnyProxy); v.setAllowedProxyChains(CommonUtils.createProxyList(allowedProxyChains)); validator = v; } else { validator = createNewTicketValidator(ticketValidatorClass, casServerUrlPrefix, - Cas20ServiceTicketValidator.class); + this.defaultServiceTicketValidatorClass); } validator.setProxyCallbackUrl(getString(ConfigurationKeys.PROXY_CALLBACK_URL)); validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyReceivingTicketValidationFilter.java new file mode 100644 index 0000000..4f11627 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyReceivingTicketValidationFilter.java @@ -0,0 +1,40 @@ +/* + * 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.validation; + +import org.jasig.cas.client.Protocol; + +/** + * Creates either a Cas30ProxyTicketValidator or a Cas30ServiceTicketValidator depending on whether any of the + * proxy parameters are set. + *

+ * This filter can also pass additional parameters to the ticket validator. Any init parameter not included in the + * reserved list {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter#RESERVED_INIT_PARAMS}. + * + * @author Jerome Leleu + * @since 3.4.0 + */ +public class Cas30ProxyReceivingTicketValidationFilter extends Cas20ProxyReceivingTicketValidationFilter { + + public Cas30ProxyReceivingTicketValidationFilter() { + super(Protocol.CAS3); + this.defaultServiceTicketValidatorClass = Cas30ServiceTicketValidator.class; + this.defaultProxyTicketValidatorClass = Cas30ProxyTicketValidator.class; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java new file mode 100644 index 0000000..2cdb641 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java @@ -0,0 +1,37 @@ +/* + * 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.validation; + +/** + * Service and proxy tickets validation service for the CAS protocol v3. + * + * @author Jerome Leleu + * @since 3.4.0 + */ +public class Cas30ProxyTicketValidator extends Cas20ProxyTicketValidator { + + public Cas30ProxyTicketValidator(String casServerUrlPrefix) { + super(casServerUrlPrefix); + } + + @Override + protected String getUrlSuffix() { + return "p3/proxyValidate"; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ServiceTicketValidator.java new file mode 100644 index 0000000..cb155a7 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ServiceTicketValidator.java @@ -0,0 +1,37 @@ +/* + * 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.validation; + +/** + * Service tickets validation service for the CAS protocol v3. + * + * @author Jerome Leleu + * @since 3.4.0 + */ +public class Cas30ServiceTicketValidator extends Cas20ServiceTicketValidator { + + public Cas30ServiceTicketValidator(String casServerUrlPrefix) { + super(casServerUrlPrefix); + } + + @Override + protected String getUrlSuffix() { + return "p3/serviceValidate"; + } +} From bec0e6bb2e4497833dadb4c969c2165ffc11d99b Mon Sep 17 00:00:00 2001 From: LELEU Jerome Date: Mon, 5 Jan 2015 17:19:40 +0100 Subject: [PATCH 30/57] Issue-91: Introduce system properties configuration option First commit --- .../ConfigurationStrategyName.java | 3 +- ...emPropertiesConfigurationStrategyImpl.java | 39 ++++++++++++ .../ConfigurationStrategyNameTests.java | 2 + ...pertiesConfigurationStrategyImplTests.java | 62 +++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImpl.java create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImplTests.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java index e180d26..2d3146f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationStrategyName.java @@ -31,7 +31,8 @@ import org.slf4j.LoggerFactory; */ public enum ConfigurationStrategyName { - DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class), PROPERTY_FILE(PropertiesConfigurationStrategyImpl.class); + DEFAULT(LegacyConfigurationStrategyImpl.class), JNDI(JndiConfigurationStrategyImpl.class), WEB_XML(WebXmlConfigurationStrategyImpl.class), + PROPERTY_FILE(PropertiesConfigurationStrategyImpl.class), SYSTEM_PROPERTIES(SystemPropertiesConfigurationStrategyImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationStrategyName.class); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImpl.java new file mode 100644 index 0000000..49be2c5 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImpl.java @@ -0,0 +1,39 @@ +/* + * 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.configuration; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + +/** + * Load all configuration from system properties. + * + * @author Jerome Leleu + * @since 3.4.0 + */ +public class SystemPropertiesConfigurationStrategyImpl extends BaseConfigurationStrategy { + + public void init(FilterConfig filterConfig, Class filterClazz) { + } + + @Override + protected String get(ConfigurationKey configurationKey) { + return System.getProperty(configurationKey.getName()); + } +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java index 1fb2ee1..5c2da1e 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/ConfigurationStrategyNameTests.java @@ -28,6 +28,8 @@ public final class ConfigurationStrategyNameTests { public void stringToClass() { assertEquals(JndiConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.JNDI.name())); assertEquals(WebXmlConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.WEB_XML.name())); + assertEquals(PropertiesConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.PROPERTY_FILE.name())); + assertEquals(SystemPropertiesConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.SYSTEM_PROPERTIES.name())); assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.DEFAULT.name())); assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy("bleh!")); } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImplTests.java new file mode 100644 index 0000000..9b362d0 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/configuration/SystemPropertiesConfigurationStrategyImplTests.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.configuration; + +import static org.junit.Assert.assertEquals; + +import org.jasig.cas.client.util.AbstractCasFilter; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockFilterConfig; + +/** + * Tests {@link SystemPropertiesConfigurationStrategyImpl}. + * + * @author Jerome Leleu + * @since 3.4.0 + */ +public class SystemPropertiesConfigurationStrategyImplTests { + + private final static String PARAMETER_NAME = "parameter"; + + private SystemPropertiesConfigurationStrategyImpl impl; + + private MockFilterConfig filterConfig; + + @Before + public void setUp() throws Exception { + this.filterConfig = new MockFilterConfig(); + this.impl = new SystemPropertiesConfigurationStrategyImpl(); + this.impl.init(this.filterConfig, AbstractCasFilter.class); + } + + @Test + public void testNoSystemPropertyDefined() { + final ConfigurationKey key = ConfigurationKeys.SERVER_NAME; + // no system property defined + assertEquals(key.getDefaultValue(), impl.getString(key)); + } + + @Test + public void testWithSystemProperty() { + final ConfigurationKey key = ConfigurationKeys.ARTIFACT_PARAMETER_NAME; + System.setProperty(key.getName(), PARAMETER_NAME); + assertEquals(PARAMETER_NAME, impl.getString(key)); + } +} From 4aef3680572702c9949dfc208038fee437b830f0 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Sat, 17 Jan 2015 11:25:03 -0500 Subject: [PATCH 31/57] CASC-237 Make OpenSAML bootstrap conditional. --- .../jasig/cas/client/validation/Saml11TicketValidator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index c99ea1d..007fc5c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -56,8 +56,11 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator static { try { - // we really only need to do this once, so this is why its here. - DefaultBootstrap.bootstrap(); + // Check for prior OpenSAML initialization to prevent double init + // that would overwrite existing OpenSAML configuration + if (Configuration.getParserPool() == null) { + DefaultBootstrap.bootstrap(); + } } catch (final ConfigurationException e) { throw new RuntimeException(e); } From db3610123f3360f34e3ad3aab4179d5762b4aa83 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 24 Jan 2015 23:58:51 -0500 Subject: [PATCH 32/57] CASC-239 Saml11AuthenticationFilter Constructor was Private instead of Public. --- .../cas/client/authentication/Saml11AuthenticationFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java index 8a7ddae..14cbd1c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java @@ -31,7 +31,7 @@ import org.jasig.cas.client.Protocol; */ public class Saml11AuthenticationFilter extends AuthenticationFilter { - private Saml11AuthenticationFilter() { + public Saml11AuthenticationFilter() { super(Protocol.SAML11); } } From e998985732c5dd0d710cd9cfe83a636f1b254781 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 20 Feb 2015 09:18:05 -0500 Subject: [PATCH 33/57] SAML validation with XPath instead of OpenSAML. --- cas-client-core/pom.xml | 27 +- .../configuration/ConfigurationKeys.java | 1 - .../jasig/cas/client/util/CommonUtils.java | 20 +- .../org/jasig/cas/client/util/IOUtils.java | 74 +++++ .../cas/client/util/MapNamespaceContext.java | 62 ++++ .../org/jasig/cas/client/util/XmlUtils.java | 99 +++++- ...actCasProtocolUrlBasedTicketValidator.java | 4 - .../AbstractUrlBasedTicketValidator.java | 7 - ...0ProxyReceivingTicketValidationFilter.java | 2 +- .../Saml11TicketValidationFilter.java | 4 +- .../validation/Saml11TicketValidator.java | 301 +++++++----------- .../META-INF/cas/samlRequestTemplate.xml | 8 + .../cas/client/util/CommonUtilsTests.java | 7 + .../Saml11TicketValidatorTests.java | 17 +- 14 files changed, 417 insertions(+), 216 deletions(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java create mode 100644 cas-client-core/src/main/resources/META-INF/cas/samlRequestTemplate.xml diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index b0de44b..795b674 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -11,6 +11,18 @@ Jasig CAS Client for Java - Core + + commons-lang + commons-lang + 2.6 + + + + joda-time + joda-time + 2.7 + + xml-security xmlsec @@ -19,20 +31,6 @@ true - - org.opensaml - opensaml - ${opensaml.version} - jar - compile - - - org.slf4j - jcl-over-slf4j - - - - commons-codec commons-codec @@ -99,6 +97,5 @@ 3.1.3.RELEASE - 2.5.1-1 diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java index 9418151..b9838cb 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -54,7 +54,6 @@ public interface ConfigurationKeys { ConfigurationKey CAS_SERVER_URL_PREFIX = new ConfigurationKey("casServerUrlPrefix", null); ConfigurationKey ENCODING = new ConfigurationKey("encoding", null); ConfigurationKey TOLERANCE = new ConfigurationKey("tolerance", 1000L); - ConfigurationKey DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey("disableXmlSchemaValidation", Boolean.FALSE); ConfigurationKey IGNORE_PATTERN = new ConfigurationKey("ignorePattern", null); ConfigurationKey IGNORE_URL_PATTERN_TYPE = new ConfigurationKey("ignoreUrlPatternType", "REGEX"); ConfigurationKey> HOSTNAME_VERIFIER = new ConfigurationKey>("hostnameVerifier", null); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index 5f2ca61..e7cc375 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -23,6 +23,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import javax.servlet.http.HttpServletRequest; @@ -32,6 +33,11 @@ import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; import org.jasig.cas.client.validation.ProxyList; import org.jasig.cas.client.validation.ProxyListEditor; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.LocalDateTime; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,14 +64,22 @@ public final class CommonUtils { private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory(); + private static final DateTimeFormatter ISO_FORMAT = ISODateTimeFormat.dateTimeNoMillis(); + private CommonUtils() { // nothing to do } public static String formatForUtcTime(final Date date) { - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return dateFormat.format(date); + return ISO_FORMAT.print(new DateTime(date).withZone(DateTimeZone.UTC)); + } + + + public static Date parseUtcDate(final String date) { + if (isEmpty(date)) { + return null; + } + return ISODateTimeFormat.dateTimeParser().parseDateTime(date).toDate(); } /** diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java new file mode 100644 index 0000000..7220465 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java @@ -0,0 +1,74 @@ +package org.jasig.cas.client.util; + +import java.io.*; +import java.nio.CharBuffer; +import java.nio.charset.Charset; + +/** + * IO utility class. + * + * @author Marvin S. Addison + * @since 3.3.1 + */ +public class IOUtils { + + /** UTF-8 character set. */ + public static final Charset UTF8 = Charset.forName("UTF-8"); + + + private IOUtils() { /** Utility class pattern. */ } + + /** + * Reads all data from the given stream as UTF-8 character data and closes it on completion or errors. + * + * @param in Input stream containing character data. + * + * @return String of all data in stream. + * + * @throws IOException On IO errors. + */ + public static String readString(final InputStream in) throws IOException { + return readString(in, UTF8); + } + + /** + * Reads all data from the given stream as character data in the given character set and closes it on completion + * or errors. + * + * @param in Input stream containing character data. + * @param charset Character set of data in stream. + * + * @return String of all data in stream. + * + * @throws IOException On IO errors. + */ + public static String readString(final InputStream in, final Charset charset) throws IOException { + final Reader reader = new InputStreamReader(in, charset); + final StringBuilder builder = new StringBuilder(); + final CharBuffer buffer = CharBuffer.allocate(2048); + try { + while (reader.read(buffer) > -1) { + buffer.flip(); + builder.append(buffer); + } + } finally { + closeQuietly(reader); + } + return builder.toString(); + } + + /** + * Unconditionally close a {@link Closeable} resource. Errors on close are ignored. + * + * @param resource Resource to close. + */ + public static void closeQuietly(final Closeable resource) { + try { + if (resource != null) { + resource.close(); + } + } catch (final IOException e) { + //ignore + } + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java new file mode 100644 index 0000000..0dd773c --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java @@ -0,0 +1,62 @@ +package org.jasig.cas.client.util; + +import javax.xml.namespace.NamespaceContext; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Namespace context implementation backed by a map of XML prefixes to namespace URIs. + * + * @author Marvin S. Addison + * @since 3.3.1 + */ +public class MapNamespaceContext implements NamespaceContext { + + private final Map namespaceMap; + + /** + * Creates a new instance from an array of namespace delcarations. + * + * @param namespaceDeclarations An array of namespace declarations of the form prefix->uri. + */ + public MapNamespaceContext(final String ... namespaceDeclarations) { + namespaceMap = new HashMap(); + int index; + String key; + String value; + for (final String decl : namespaceDeclarations) { + index = decl.indexOf('-'); + key = decl.substring(0, index); + value = decl.substring(index + 2); + namespaceMap.put(key, value); + } + } + + /** + * Creates a new instance from a map. + * + * @param namespaceMap Map of XML namespace prefixes (keys) to URIs (values). + */ + public MapNamespaceContext(final Map namespaceMap) { + this.namespaceMap = namespaceMap; + } + + public String getNamespaceURI(final String prefix) { + return namespaceMap.get(prefix); + } + + public String getPrefix(final String namespaceURI) { + for (final Map.Entry entry : namespaceMap.entrySet()) { + if (entry.getValue().equalsIgnoreCase(namespaceURI)) { + return entry.getKey(); + } + } + return null; + } + + public Iterator getPrefixes(final String namespaceURI) { + return Collections.singleton(getPrefix(namespaceURI)).iterator(); + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java index f882b04..926ec91 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java @@ -19,17 +19,24 @@ package org.jasig.cas.client.util; import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; +import java.util.*; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; +import javax.xml.xpath.*; /** * Common utilities for easily parsing XML without duplicating logic. @@ -45,6 +52,93 @@ public final class XmlUtils { */ private final static Logger LOGGER = LoggerFactory.getLogger(XmlUtils.class); + + /** + * Creates a new namespace-aware DOM document object by parsing the given XML. + * + * @param xml XML content. + * + * @return DOM document. + */ + public static Document newDocument(final String xml) { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + final Map features = new HashMap(); + features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true); + features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + for (final Map.Entry entry : features.entrySet()) { + try { + factory.setFeature(entry.getKey(), entry.getValue()); + } catch (ParserConfigurationException e) { + LOGGER.warn("Failed setting XML feature {}: {}", entry.getKey(), e); + } + } + factory.setNamespaceAware(true); + try { + return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml))); + } catch (Exception e) { + throw new RuntimeException("XML parsing error: " + e); + } + } + + + /** + * Compiles the given XPath expression. + * + * @param expression XPath expression. + * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. + * + * @return Compiled XPath expression. + */ + public static XPathExpression compileXPath(final String expression, final NamespaceContext nsContext) { + try { + final XPath xPath = XPathFactory.newInstance().newXPath(); + xPath.setNamespaceContext(nsContext); + return xPath.compile(expression); + } catch (XPathExpressionException e) { + throw new IllegalArgumentException("Invalid XPath expression"); + } + } + + + /** + * Evaluates the given XPath expression as a string result. + * + * @param expression XPath expression. + * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. + * @param document DOM document on which to evaluate expression. + * + * @return Evaluated XPath expression as a string. + */ + public static String evaluateXPathString( + final String expression, final NamespaceContext nsContext, final Document document) { + try { + return (String) compileXPath(expression, nsContext).evaluate(document, XPathConstants.STRING); + } catch (XPathExpressionException e) { + throw new RuntimeException("XPath evaluation error", e); + } + } + + + + /** + * Evaluates the given XPath expression as a node list result. + * + * @param expression XPath expression. + * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. + * @param document DOM document on which to evaluate expression. + * + * @return Evaluated XPath expression as a node list. + */ + public static NodeList evaluateXPathNodeList( + final String expression, final NamespaceContext nsContext, final Document document) { + try { + return (NodeList) compileXPath(expression, nsContext).evaluate(document, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + throw new RuntimeException("XPath evaluation error", e); + } + } + + /** * Get an instance of an XML reader from the XMLReaderFactory. * @@ -62,6 +156,7 @@ public final class XmlUtils { } } + /** * Retrieve the text for a group of elements. Each text element is an entry * in a list. diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java index b5d5c2f..146280d 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java @@ -34,10 +34,6 @@ public abstract class AbstractCasProtocolUrlBasedTicketValidator extends Abstrac super(casServerUrlPrefix); } - protected final void setDisableXmlSchemaValidation(final boolean disable) { - // nothing to do - } - /** * Retrieves the response from the server by opening a connection and merely reading the response. */ diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index fab0581..59c4d88 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -90,13 +90,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator */ protected abstract String getUrlSuffix(); - /** - * Disable XML Schema validation. Note, setting this to true may not be reversable. Defaults to false. Setting it to false - * after setting it to true may not have any affect. - * - * @param disabled whether to disable or not. - */ - protected abstract void setDisableXmlSchemaValidation(boolean disabled); /** * Constructs the URL to send the validation request to. diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index 8c7a632..c43e958 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -51,7 +51,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal private static final String[] RESERVED_INIT_PARAMS = new String[]{ARTIFACT_PARAMETER_NAME.getName(), SERVER_NAME.getName(), SERVICE.getName(), RENEW.getName(), LOGOUT_PARAMETER_NAME.getName(), ARTIFACT_PARAMETER_OVER_POST.getName(), EAGERLY_CREATE_SESSIONS.getName(), ENCODE_SERVICE_URL.getName(), SSL_CONFIG_FILE.getName(), ROLE_ATTRIBUTE.getName(), IGNORE_CASE.getName(), CAS_SERVER_LOGIN_URL.getName(), GATEWAY.getName(), AUTHENTICATION_REDIRECT_STRATEGY_CLASS.getName(), GATEWAY_STORAGE_CLASS.getName(), CAS_SERVER_URL_PREFIX.getName(), ENCODING.getName(), - TOLERANCE.getName(), DISABLE_XML_SCHEMA_VALIDATION.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(), + TOLERANCE.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(), EXCEPTION_ON_VALIDATION_FAILURE.getName(), REDIRECT_AFTER_VALIDATION.getName(), USE_SESSION.getName(), SECRET_KEY.getName(), CIPHER_ALGORITHM.getName(), PROXY_RECEPTOR_URL.getName(), PROXY_GRANTING_TICKET_STORAGE_CLASS.getName(), MILLIS_BETWEEN_CLEAN_UPS.getName(), ACCEPT_ANY_PROXY.getName(), ALLOWED_PROXY_CHAINS.getName(), TICKET_VALIDATOR_CLASS.getName(), PROXY_CALLBACK_URL.getName(), FRONT_LOGOUT_PARAMETER_NAME.getName(), RELAY_STATE_PARAMETER_NAME.getName() diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 73aede0..78d37a3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -47,12 +47,10 @@ public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter validator.setTolerance(tolerance); validator.setRenew(getBoolean(ConfigurationKeys.RENEW)); - final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), - getSSLConfig()); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(), getSSLConfig()); validator.setURLConnectionFactory(factory); validator.setEncoding(getString(ConfigurationKeys.ENCODING)); - validator.setDisableXmlSchemaValidation(getBoolean(ConfigurationKeys.DISABLE_XML_SCHEMA_VALIDATION)); return validator; } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 007fc5c..506d9a3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -22,29 +22,22 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.Charset; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.*; -import org.jasig.cas.client.authentication.AttributePrincipal; import org.jasig.cas.client.authentication.AttributePrincipalImpl; import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.IOUtils; +import org.jasig.cas.client.util.MapNamespaceContext; +import org.jasig.cas.client.util.XmlUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; -import org.opensaml.Configuration; -import org.opensaml.DefaultBootstrap; -import org.opensaml.common.IdentifierGenerator; -import org.opensaml.common.impl.SecureRandomIdentifierGenerator; -import org.opensaml.saml1.core.*; -import org.opensaml.ws.soap.soap11.Envelope; -import org.opensaml.xml.ConfigurationException; -import org.opensaml.xml.io.Unmarshaller; -import org.opensaml.xml.io.UnmarshallerFactory; -import org.opensaml.xml.io.UnmarshallingException; -import org.opensaml.xml.parse.BasicParserPool; -import org.opensaml.xml.parse.XMLParserException; -import org.opensaml.xml.schema.XSAny; -import org.opensaml.xml.schema.XSString; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import javax.xml.namespace.NamespaceContext; /** * TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response. @@ -54,34 +47,59 @@ import org.w3c.dom.Element; */ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator { - static { - try { - // Check for prior OpenSAML initialization to prevent double init - // that would overwrite existing OpenSAML configuration - if (Configuration.getParserPool() == null) { - DefaultBootstrap.bootstrap(); - } - } catch (final ConfigurationException e) { - throw new RuntimeException(e); - } - } + /** Authentication attribute containing SAML AuthenticationMethod attribute value. */ + public static final String AUTH_METHOD_ATTRIBUTE = "samlAuthenticationStatement::authMethod"; + + /** SAML 1.1 request template. */ + private static final String SAML_REQUEST_TEMPLATE; + + /** SAML 1.1. namespace context. */ + private static final NamespaceContext SAML_NS_CONTEXT = new MapNamespaceContext( + "soap->http://schemas.xmlsoap.org/soap/envelope/", + "sa->urn:oasis:names:tc:SAML:1.0:assertion", + "sp->urn:oasis:names:tc:SAML:1.0:protocol"); + + /** XPath expression to extract Assertion validity start date. */ + private static final String XPATH_ASSERTION_DATE_START = "//sa:Assertion/sa:Conditions/@NotBefore"; + + /** XPath expression to extract Assertion validity end date. */ + private static final String XPATH_ASSERTION_DATE_END = "//sa:Assertion/sa:Conditions/@NotOnOrAfter"; + + /** XPath expression to extract NameIdentifier. */ + private static final String XPATH_NAME_ID = "//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier"; + + /** XPath expression to extract authentication method. */ + private static final String XPATH_AUTH_METHOD = "//sa:AuthenticationStatement/@AuthenticationMethod"; + + /** XPath expression to extract attributes. */ + private static final String XPATH_ATTRIBUTES = "//sa:AttributeStatement/sa:Attribute"; + + private static final String HEX_CHARS = "0123456789abcdef"; /** Time tolerance to allow for time drifting. */ private long tolerance = 1000L; - private final BasicParserPool basicParserPool; + private final Random random; - private final IdentifierGenerator identifierGenerator; + + /** Class initializer. */ + static { + try { + SAML_REQUEST_TEMPLATE = IOUtils.readString( + Saml11TicketValidator.class.getResourceAsStream("/META-INF/cas/samlRequestTemplate.xml")); + } catch (IOException e) { + throw new IllegalStateException("Cannot load SAML request template from classpath", e); + } + + } public Saml11TicketValidator(final String casServerUrlPrefix) { super(casServerUrlPrefix); - this.basicParserPool = new BasicParserPool(); - this.basicParserPool.setNamespaceAware(true); try { - this.identifierGenerator = new SecureRandomIdentifierGenerator(); - } catch (final Exception e) { - throw new RuntimeException(e); + random = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Cannot find required SHA1PRNG algorithm"); } } @@ -96,95 +114,62 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator urlParameters.put("TARGET", service); } - @Override - protected void setDisableXmlSchemaValidation(final boolean disabled) { - if (disabled) { - this.basicParserPool.setSchema(null); - } - } - - protected byte[] getBytes(final String text) { - try { - return CommonUtils.isNotBlank(getEncoding()) ? text.getBytes(getEncoding()) : text.getBytes(); - } catch (final Exception e) { - return text.getBytes(); - } - } - protected Assertion parseResponseFromServer(final String response) throws TicketValidationException { try { - - final Document responseDocument = this.basicParserPool.parse(new ByteArrayInputStream(getBytes(response))); - final Element responseRoot = responseDocument.getDocumentElement(); - final UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); - final Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseRoot); - final Envelope envelope = (Envelope) unmarshaller.unmarshall(responseRoot); - final Response samlResponse = (Response) envelope.getBody().getOrderedChildren().get(0); - - final List assertions = samlResponse.getAssertions(); - if (assertions.isEmpty()) { - throw new TicketValidationException("No assertions found."); + final Document document = XmlUtils.newDocument(response); + final Date assertionValidityStart = CommonUtils.parseUtcDate( + XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_START, SAML_NS_CONTEXT, document)); + final Date assertionValidityEnd = CommonUtils.parseUtcDate( + XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_END, SAML_NS_CONTEXT, document)); + if (!isValidAssertion(assertionValidityStart, assertionValidityEnd)) { + throw new TicketValidationException("Invalid SAML assertion"); } - - for (final org.opensaml.saml1.core.Assertion assertion : assertions) { - - if (!isValidAssertion(assertion)) { - continue; - } - - final AuthenticationStatement authenticationStatement = getSAMLAuthenticationStatement(assertion); - - if (authenticationStatement == null) { - throw new TicketValidationException("No AuthentiationStatement found in SAML Assertion."); - } - final Subject subject = authenticationStatement.getSubject(); - - if (subject == null) { - throw new TicketValidationException("No Subject found in SAML Assertion."); - } - - final List attributes = getAttributesFor(assertion, subject); - final Map personAttributes = new HashMap(); - for (final Attribute samlAttribute : attributes) { - final List values = getValuesFrom(samlAttribute); - - personAttributes.put(samlAttribute.getAttributeName(), values.size() == 1 ? values.get(0) : values); - } - - final AttributePrincipal principal = new AttributePrincipalImpl(subject.getNameIdentifier() - .getNameIdentifier(), personAttributes); - - final Map authenticationAttributes = new HashMap(); - authenticationAttributes.put("samlAuthenticationStatement::authMethod", - authenticationStatement.getAuthenticationMethod()); - - final DateTime notBefore = assertion.getConditions().getNotBefore(); - final DateTime notOnOrAfter = assertion.getConditions().getNotOnOrAfter(); - final DateTime authenticationInstant = authenticationStatement.getAuthenticationInstant(); - return new AssertionImpl(principal, notBefore.toDate(), notOnOrAfter.toDate(), - authenticationInstant.toDate(), authenticationAttributes); + final String nameId = XmlUtils.evaluateXPathString(XPATH_NAME_ID, SAML_NS_CONTEXT, document); + if (nameId == null) { + throw new TicketValidationException("SAML assertion does not contain NameIdentifier element"); } - } catch (final UnmarshallingException e) { - throw new TicketValidationException(e); - } catch (final XMLParserException e) { - throw new TicketValidationException(e); + final String authMethod = XmlUtils.evaluateXPathString(XPATH_AUTH_METHOD, SAML_NS_CONTEXT, document); + final NodeList attributes = XmlUtils.evaluateXPathNodeList(XPATH_ATTRIBUTES, SAML_NS_CONTEXT, document); + final Map principalAttributes = new HashMap(attributes.getLength()); + Element attribute; + NodeList values; + String name; + for (int i = 0; i < attributes.getLength(); i++) { + attribute = (Element) attributes.item(i); + name = attribute.getAttribute("AttributeName"); + logger.trace("Processing attribute {}", name); + values = attribute.getElementsByTagNameNS("*", "AttributeValue"); + if (values.getLength() == 1) { + principalAttributes.put(name, values.item(0).getTextContent()); + } else { + final Collection items = new ArrayList(values.getLength()); + for (int j = 0; j < values.getLength(); j++) { + items.add(values.item(j).getTextContent()); + } + principalAttributes.put(name, items); + } + } + return new AssertionImpl( + new AttributePrincipalImpl(nameId, principalAttributes), + assertionValidityStart, + assertionValidityEnd, + new Date(), + Collections.singletonMap(AUTH_METHOD_ATTRIBUTE, (Object) authMethod)); + } catch (final Exception e) { + throw new TicketValidationException("Error processing SAML response", e); } - - throw new TicketValidationException( - "No Assertion found within valid time range. Either there's a replay of the ticket or there's clock drift. Check tolerance range, or server/client synchronization."); } - private boolean isValidAssertion(final org.opensaml.saml1.core.Assertion assertion) { - final DateTime notBefore = assertion.getConditions().getNotBefore(); - final DateTime notOnOrAfter = assertion.getConditions().getNotOnOrAfter(); - + private boolean isValidAssertion(final Date notBefore, final Date notOnOrAfter) { if (notBefore == null || notOnOrAfter == null) { - logger.debug("Assertion has no bounding dates. Will not process."); + logger.debug("Assertion is not valid because it does not have bounding dates."); return false; } final DateTime currentTime = new DateTime(DateTimeZone.UTC); - final Interval validityRange = new Interval(notBefore.minus(this.tolerance), notOnOrAfter.plus(this.tolerance)); + final Interval validityRange = new Interval( + new DateTime(notBefore).minus(this.tolerance), + new DateTime(notOnOrAfter).plus(this.tolerance)); if (validityRange.contains(currentTime)) { logger.debug("Current time is within the interval validity."); @@ -192,93 +177,41 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator } if (currentTime.isBefore(validityRange.getStart())) { - logger.debug("skipping assertion that's not yet valid..."); - return false; + logger.debug("Assertion is not yet valid"); + } else { + logger.debug("Assertion is expired"); } - - logger.debug("skipping expired assertion..."); return false; } - private AuthenticationStatement getSAMLAuthenticationStatement(final org.opensaml.saml1.core.Assertion assertion) { - final List statements = assertion.getAuthenticationStatements(); - - if (statements.isEmpty()) { - return null; - } - - return statements.get(0); - } - - private List getAttributesFor(final org.opensaml.saml1.core.Assertion assertion, final Subject subject) { - final List attributes = new ArrayList(); - for (final AttributeStatement attribute : assertion.getAttributeStatements()) { - if (subject.getNameIdentifier().getNameIdentifier() - .equals(attribute.getSubject().getNameIdentifier().getNameIdentifier())) { - attributes.addAll(attribute.getAttributes()); - } - } - - return attributes; - } - - private List getValuesFrom(final Attribute attribute) { - final List list = new ArrayList(); - for (final Object o : attribute.getAttributeValues()) { - if (o instanceof XSAny) { - list.add(((XSAny) o).getTextContent()); - } else if (o instanceof XSString) { - list.add(((XSString) o).getValue()); - } else { - list.add(o.toString()); - } - } - return list; - } - protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) { - final String MESSAGE_TO_SEND = "" - + "" - + ticket - + ""; + final String request = String.format( + SAML_REQUEST_TEMPLATE, + generateId(), + CommonUtils.formatForUtcTime(new Date()), + ticket); HttpURLConnection conn = null; - DataOutputStream out = null; - BufferedReader in = null; - try { conn = this.getURLConnectionFactory().buildHttpURLConnection(validationUrl.openConnection()); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "text/xml"); - conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length())); + conn.setRequestProperty("Content-Type", "text/xml"); + conn.setRequestProperty("Content-Length", Integer.toString(request.length())); conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security"); conn.setUseCaches(false); conn.setDoInput(true); conn.setDoOutput(true); - out = new DataOutputStream(conn.getOutputStream()); - out.writeBytes(MESSAGE_TO_SEND); - out.flush(); - in = new BufferedReader(CommonUtils.isNotBlank(getEncoding()) ? new InputStreamReader( - conn.getInputStream(), Charset.forName(getEncoding())) : new InputStreamReader( - conn.getInputStream())); - final StringBuilder buffer = new StringBuilder(256); + final Charset charset = CommonUtils.isNotBlank(getEncoding()) ? + Charset.forName(getEncoding()) : IOUtils.UTF8; + conn.getOutputStream().write(request.getBytes(charset)); + conn.getOutputStream().flush(); - String line; - - while ((line = in.readLine()) != null) { - buffer.append(line); - } - return buffer.toString(); + return IOUtils.readString(conn.getInputStream(), charset); } catch (final IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("IO error sending HTTP request to /samlValidate", e); } finally { - CommonUtils.closeQuietly(out); - CommonUtils.closeQuietly(in); if (conn != null) { conn.disconnect(); } @@ -288,4 +221,16 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator public void setTolerance(final long tolerance) { this.tolerance = tolerance; } + + private String generateId() { + final byte[] data = new byte[16]; + random.nextBytes(data); + final StringBuilder id = new StringBuilder(33); + id.append('_'); + for (int i = 0; i < data.length; i++) { + id.append(HEX_CHARS.charAt((data[i] & 0xF0) >> 4)); + id.append(HEX_CHARS.charAt(data[i] & 0x0F)); + } + return id.toString(); + } } diff --git a/cas-client-core/src/main/resources/META-INF/cas/samlRequestTemplate.xml b/cas-client-core/src/main/resources/META-INF/cas/samlRequestTemplate.xml new file mode 100644 index 0000000..4247909 --- /dev/null +++ b/cas-client-core/src/main/resources/META-INF/cas/samlRequestTemplate.xml @@ -0,0 +1,8 @@ + + + + + %s + + + diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java index 8b585b4..479a3f3 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java @@ -21,6 +21,8 @@ package org.jasig.cas.client.util; import java.net.URL; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; + import junit.framework.TestCase; import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; @@ -192,4 +194,9 @@ public final class CommonUtilsTests extends TestCase { public void testUrlEncode() { assertEquals("this+is+a+very+special+parameter+with+%3D%25%2F", CommonUtils.urlEncode("this is a very special parameter with =%/")); } + + public void testParseUtcDate() { + final Date expected = new Date(1424437961025L); + assertEquals(expected, CommonUtils.parseUtcDate("2015-02-20T08:12:41.025-0500")); + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java index 417db57..c648232 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java @@ -21,6 +21,7 @@ package org.jasig.cas.client.validation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.UnsupportedEncodingException; +import java.util.Collection; import java.util.Date; import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.util.CommonUtils; @@ -117,11 +118,17 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes + "\" NotOnOrAfter=\"" + CommonUtils.formatForUtcTime(range.getEnd().toDate()) + "\">" - + "https://example.com/test-client/secure/" + + "https://example.com/test-client/secure/" + + "" + "" - + "testPrincipalurn:oasis:names:tc:SAML:1.0:cm:artifacttestPrincipalurn:oasis:names:tc:SAML:1.0:cm:artifact12345" + + "testPrincipal" + + "urn:oasis:names:tc:SAML:1.0:cm:artifact" + + "" + + "testPrincipal" + + "urn:oasis:names:tc:SAML:1.0:cm:artifact" + + "12345" + "" + "ACTIVE" + "" @@ -132,7 +139,13 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes server.content = response.getBytes(server.encoding); try { final Assertion a = this.validator.validate("test", "test"); + assertEquals( + "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport", + a.getAttributes().get(Saml11TicketValidator.AUTH_METHOD_ATTRIBUTE)); assertEquals("testPrincipal", a.getPrincipal().getName()); + assertEquals("12345", a.getPrincipal().getAttributes().get("uid")); + assertEquals("ACTIVE", a.getPrincipal().getAttributes().get("accountState")); + assertEquals(3, ((Collection) a.getPrincipal().getAttributes().get("eduPersonAffiliation")).size()); } catch (final TicketValidationException e) { fail(e.toString()); } From 4527671568414162790e3c4a99d8f04365253236 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 20 Feb 2015 10:26:01 -0500 Subject: [PATCH 34/57] Sensible XPath processing optimizations. --- .../util/ThreadLocalXPathExpression.java | 87 +++++++++++++++++++ .../org/jasig/cas/client/util/XmlUtils.java | 62 ------------- .../validation/Saml11TicketValidator.java | 32 +++---- 3 files changed, 104 insertions(+), 77 deletions(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java new file mode 100644 index 0000000..23d6ce1 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java @@ -0,0 +1,87 @@ +package org.jasig.cas.client.util; + +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.xpath.*; + +/** + * Thread local XPath expression. + * + * @author Marvin S. Addison + * @since 3.3 + */ +public class ThreadLocalXPathExpression extends ThreadLocal implements XPathExpression { + + /** XPath expression */ + private String expression; + + /** Namespace context. */ + private NamespaceContext context; + + /** + * Creates a new instance from an XPath expression and namespace context. + * + * @param xPath XPath expression. + * @param context Namespace context for handling namespace prefix to URI mappings. + */ + public ThreadLocalXPathExpression(final String xPath, final NamespaceContext context) { + this.expression = xPath; + this.context = context; + } + + public Object evaluate(final Object o, final QName qName) throws XPathExpressionException { + return get().evaluate(o, qName); + } + + public String evaluate(final Object o) throws XPathExpressionException { + return get().evaluate(o); + } + + public Object evaluate(final InputSource inputSource, final QName qName) throws XPathExpressionException { + return get().evaluate(inputSource, qName); + } + + public String evaluate(final InputSource inputSource) throws XPathExpressionException { + return get().evaluate(inputSource); + } + + /** + * Evaluates the XPath expression and returns the result coerced to a string. + * + * @param o Object on which to evaluate the expression; typically a DOM node. + * + * @return Evaluation result as a string. + * + * @throws XPathExpressionException On XPath evaluation errors. + */ + public String evaluateAsString(final Object o) throws XPathExpressionException { + return (String) evaluate(o, XPathConstants.STRING); + } + + /** + * Evaluates the XPath expression and returns the result coerced to a node list. + * + * @param o Object on which to evaluate the expression; typically a DOM node. + * + * @return Evaluation result as a node list. + * + * @throws XPathExpressionException On XPath evaluation errors. + */ + public NodeList evaluateAsNodeList(final Object o) throws XPathExpressionException { + return (NodeList) evaluate(o, XPathConstants.NODESET); + } + + @Override + protected XPathExpression initialValue() { + try { + final XPath xPath = XPathFactory.newInstance().newXPath(); + xPath.setNamespaceContext(context); + return xPath.compile(expression); + } catch (XPathExpressionException e) { + throw new IllegalArgumentException("Invalid XPath expression"); + } + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java index 926ec91..77831f4 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/XmlUtils.java @@ -24,7 +24,6 @@ import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -32,11 +31,9 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; -import javax.xml.xpath.*; /** * Common utilities for easily parsing XML without duplicating logic. @@ -80,65 +77,6 @@ public final class XmlUtils { } } - - /** - * Compiles the given XPath expression. - * - * @param expression XPath expression. - * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. - * - * @return Compiled XPath expression. - */ - public static XPathExpression compileXPath(final String expression, final NamespaceContext nsContext) { - try { - final XPath xPath = XPathFactory.newInstance().newXPath(); - xPath.setNamespaceContext(nsContext); - return xPath.compile(expression); - } catch (XPathExpressionException e) { - throw new IllegalArgumentException("Invalid XPath expression"); - } - } - - - /** - * Evaluates the given XPath expression as a string result. - * - * @param expression XPath expression. - * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. - * @param document DOM document on which to evaluate expression. - * - * @return Evaluated XPath expression as a string. - */ - public static String evaluateXPathString( - final String expression, final NamespaceContext nsContext, final Document document) { - try { - return (String) compileXPath(expression, nsContext).evaluate(document, XPathConstants.STRING); - } catch (XPathExpressionException e) { - throw new RuntimeException("XPath evaluation error", e); - } - } - - - - /** - * Evaluates the given XPath expression as a node list result. - * - * @param expression XPath expression. - * @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions. - * @param document DOM document on which to evaluate expression. - * - * @return Evaluated XPath expression as a node list. - */ - public static NodeList evaluateXPathNodeList( - final String expression, final NamespaceContext nsContext, final Document document) { - try { - return (NodeList) compileXPath(expression, nsContext).evaluate(document, XPathConstants.NODESET); - } catch (XPathExpressionException e) { - throw new RuntimeException("XPath evaluation error", e); - } - } - - /** * Get an instance of an XML reader from the XMLReaderFactory. * diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 506d9a3..33cb005 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -26,10 +26,7 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.*; import org.jasig.cas.client.authentication.AttributePrincipalImpl; -import org.jasig.cas.client.util.CommonUtils; -import org.jasig.cas.client.util.IOUtils; -import org.jasig.cas.client.util.MapNamespaceContext; -import org.jasig.cas.client.util.XmlUtils; +import org.jasig.cas.client.util.*; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; @@ -54,25 +51,30 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator private static final String SAML_REQUEST_TEMPLATE; /** SAML 1.1. namespace context. */ - private static final NamespaceContext SAML_NS_CONTEXT = new MapNamespaceContext( + private static final NamespaceContext NS_CONTEXT = new MapNamespaceContext( "soap->http://schemas.xmlsoap.org/soap/envelope/", "sa->urn:oasis:names:tc:SAML:1.0:assertion", "sp->urn:oasis:names:tc:SAML:1.0:protocol"); /** XPath expression to extract Assertion validity start date. */ - private static final String XPATH_ASSERTION_DATE_START = "//sa:Assertion/sa:Conditions/@NotBefore"; + private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_START = + new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotBefore", NS_CONTEXT); /** XPath expression to extract Assertion validity end date. */ - private static final String XPATH_ASSERTION_DATE_END = "//sa:Assertion/sa:Conditions/@NotOnOrAfter"; + private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_END = + new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotOnOrAfter", NS_CONTEXT); /** XPath expression to extract NameIdentifier. */ - private static final String XPATH_NAME_ID = "//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier"; + private static final ThreadLocalXPathExpression XPATH_NAME_ID = + new ThreadLocalXPathExpression("//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier", NS_CONTEXT); /** XPath expression to extract authentication method. */ - private static final String XPATH_AUTH_METHOD = "//sa:AuthenticationStatement/@AuthenticationMethod"; + private static final ThreadLocalXPathExpression XPATH_AUTH_METHOD = + new ThreadLocalXPathExpression("//sa:AuthenticationStatement/@AuthenticationMethod", NS_CONTEXT); /** XPath expression to extract attributes. */ - private static final String XPATH_ATTRIBUTES = "//sa:AttributeStatement/sa:Attribute"; + private static final ThreadLocalXPathExpression XPATH_ATTRIBUTES = + new ThreadLocalXPathExpression("//sa:AttributeStatement/sa:Attribute", NS_CONTEXT); private static final String HEX_CHARS = "0123456789abcdef"; @@ -118,18 +120,18 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator try { final Document document = XmlUtils.newDocument(response); final Date assertionValidityStart = CommonUtils.parseUtcDate( - XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_START, SAML_NS_CONTEXT, document)); + XPATH_ASSERTION_DATE_START.evaluateAsString(document)); final Date assertionValidityEnd = CommonUtils.parseUtcDate( - XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_END, SAML_NS_CONTEXT, document)); + XPATH_ASSERTION_DATE_END.evaluateAsString(document)); if (!isValidAssertion(assertionValidityStart, assertionValidityEnd)) { throw new TicketValidationException("Invalid SAML assertion"); } - final String nameId = XmlUtils.evaluateXPathString(XPATH_NAME_ID, SAML_NS_CONTEXT, document); + final String nameId = XPATH_NAME_ID.evaluateAsString(document); if (nameId == null) { throw new TicketValidationException("SAML assertion does not contain NameIdentifier element"); } - final String authMethod = XmlUtils.evaluateXPathString(XPATH_AUTH_METHOD, SAML_NS_CONTEXT, document); - final NodeList attributes = XmlUtils.evaluateXPathNodeList(XPATH_ATTRIBUTES, SAML_NS_CONTEXT, document); + final String authMethod = XPATH_AUTH_METHOD.evaluateAsString(document); + final NodeList attributes = XPATH_ATTRIBUTES.evaluateAsNodeList(document); final Map principalAttributes = new HashMap(attributes.getLength()); Element attribute; NodeList values; From dd0818b84f94fdc1342162479c1c381db9157314 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 20 Feb 2015 10:35:05 -0500 Subject: [PATCH 35/57] Fix @since version. --- .../src/main/java/org/jasig/cas/client/util/IOUtils.java | 2 +- .../java/org/jasig/cas/client/util/MapNamespaceContext.java | 2 +- .../org/jasig/cas/client/util/ThreadLocalXPathExpression.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java index 7220465..e8dd77e 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java @@ -8,7 +8,7 @@ import java.nio.charset.Charset; * IO utility class. * * @author Marvin S. Addison - * @since 3.3.1 + * @since 3.3.4 */ public class IOUtils { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java index 0dd773c..f6c2199 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java @@ -10,7 +10,7 @@ import java.util.Map; * Namespace context implementation backed by a map of XML prefixes to namespace URIs. * * @author Marvin S. Addison - * @since 3.3.1 + * @since 3.3.4 */ public class MapNamespaceContext implements NamespaceContext { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java index 23d6ce1..86a4a09 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java @@ -11,7 +11,7 @@ import javax.xml.xpath.*; * Thread local XPath expression. * * @author Marvin S. Addison - * @since 3.3 + * @since 3.3.4 */ public class ThreadLocalXPathExpression extends ThreadLocal implements XPathExpression { From d8980535b774c67edc883d6c23aaf0d9ec50e3aa Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Tue, 14 Apr 2015 16:19:12 -0400 Subject: [PATCH 36/57] Move SAML components into separate module. --- cas-client-core/pom.xml | 29 ++++++----- cas-client-integration-atlassian/pom.xml | 5 ++ cas-client-integration-tomcat-v6/pom.xml | 8 +++ cas-client-integration-tomcat-v7/pom.xml | 8 +++ cas-client-support-saml/pom.xml | 38 ++++++++++++++ .../Saml11AuthenticationFilter.java | 0 .../Saml11TicketValidationFilter.java | 0 .../validation/Saml11TicketValidator.java | 0 .../Saml11TicketValidationFilterTests.java | 0 .../Saml11TicketValidatorTests.java | 2 +- pom.xml | 52 +++++++++++++++++++ 11 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 cas-client-support-saml/pom.xml rename {cas-client-core => cas-client-support-saml}/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java (100%) rename {cas-client-core => cas-client-support-saml}/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java (100%) rename {cas-client-core => cas-client-support-saml}/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java (100%) rename {cas-client-core => cas-client-support-saml}/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java (100%) rename {cas-client-core => cas-client-support-saml}/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java (98%) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 795b674..08a42b1 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -10,6 +10,23 @@ jar Jasig CAS Client for Java - Core + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + + test-jar + + + + + + + commons-lang @@ -49,27 +66,18 @@ org.springframework spring-test - ${spring.version} test org.springframework spring-core - ${spring.version} test - - - commons-logging - commons-logging - - org.springframework spring-context - ${spring.version} test @@ -95,7 +103,4 @@ - - 3.1.3.RELEASE - diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 96895e9..ce13bce 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -46,6 +46,11 @@ true + + org.springframework + spring-context + + atlassian-osuser com.atlassian.osuser diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 5d40ce4..37d0465 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -20,6 +20,14 @@ jar compile + + org.jasig.cas.client + cas-client-support-saml + ${project.version} + jar + compile + true + org.apache.tomcat catalina diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 5bc817d..e1068ba 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -20,6 +20,14 @@ jar compile + + org.jasig.cas.client + cas-client-support-saml + ${project.version} + jar + compile + true + org.apache.tomcat tomcat-catalina diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml new file mode 100644 index 0000000..60c49f7 --- /dev/null +++ b/cas-client-support-saml/pom.xml @@ -0,0 +1,38 @@ + + + org.jasig.cas.client + 3.3.4-SNAPSHOT + cas-client + + 4.0.0 + org.jasig.cas.client + cas-client-support-saml + jar + Jasig CAS Client for Java - SAML Protocol Support + + + + org.jasig.cas.client + cas-client-core + ${project.version} + + + + org.jasig.cas.client + cas-client-core + ${project.version} + test-jar + test + + + org.springframework + spring-test + test + + + org.springframework + spring-core + test + + + diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java similarity index 100% rename from cas-client-core/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java rename to cas-client-support-saml/src/main/java/org/jasig/cas/client/authentication/Saml11AuthenticationFilter.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java similarity index 100% rename from cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java rename to cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java similarity index 100% rename from cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java rename to cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java b/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java similarity index 100% rename from cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java rename to cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java b/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java similarity index 98% rename from cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java rename to cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java index c648232..7738966 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java +++ b/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java @@ -46,7 +46,7 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes @Before public void setUp() throws Exception { - this.validator = new Saml11TicketValidator(CONST_CAS_SERVER_URL_PREFIX + "9051"); + this.validator = new Saml11TicketValidator(AbstractTicketValidatorTests.CONST_CAS_SERVER_URL_PREFIX + "9051"); this.validator.setTolerance(1000L); } diff --git a/pom.xml b/pom.xml index 70befae..bac41ce 100644 --- a/pom.xml +++ b/pom.xml @@ -159,6 +159,56 @@ + + + + org.springframework + spring-core + ${spring.version} + + + commons-logging + commons-logging + + + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-test + ${spring.version} + test + + + + log4j + log4j + test + 1.2.15 + + + jmxri + com.sun.jmx + + + com.sun.jdmk + jmxtools + + + javax.jms + jms + + + + + + junit @@ -198,12 +248,14 @@ cas-client-integration-jboss cas-client-support-distributed-ehcache cas-client-support-distributed-memcached + cas-client-support-saml cas-client-integration-tomcat-common cas-client-integration-tomcat-v6 cas-client-integration-tomcat-v7 + 3.1.3.RELEASE 2.2.0 3.0.2 1.7.1 From 6e261e7251700f00e78e99a34b6628fcf15a49d0 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 20 Apr 2015 10:34:28 -0400 Subject: [PATCH 37/57] Issue #100 Respond to code review feedback. --- .../src/main/java/org/jasig/cas/client/util/IOUtils.java | 2 +- .../org/jasig/cas/client/util/ThreadLocalXPathExpression.java | 4 ++-- .../jasig/cas/client/validation/Saml11TicketValidator.java | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java index e8dd77e..f3c3107 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java @@ -10,7 +10,7 @@ import java.nio.charset.Charset; * @author Marvin S. Addison * @since 3.3.4 */ -public class IOUtils { +public final class IOUtils { /** UTF-8 character set. */ public static final Charset UTF8 = Charset.forName("UTF-8"); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java index 86a4a09..f1ed1f4 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java @@ -16,10 +16,10 @@ import javax.xml.xpath.*; public class ThreadLocalXPathExpression extends ThreadLocal implements XPathExpression { /** XPath expression */ - private String expression; + private final String expression; /** Namespace context. */ - private NamespaceContext context; + private final NamespaceContext context; /** * Creates a new instance from an XPath expression and namespace context. diff --git a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 33cb005..6446544 100644 --- a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -197,7 +197,6 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator conn = this.getURLConnectionFactory().buildHttpURLConnection(validationUrl.openConnection()); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "text/xml"); - conn.setRequestProperty("Content-Type", "text/xml"); conn.setRequestProperty("Content-Length", Integer.toString(request.length())); conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security"); conn.setUseCaches(false); From 70ed5fd8bbe7bd324e62cb5f03904c4bb3d422e1 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 4 May 2015 16:07:47 -0400 Subject: [PATCH 38/57] Add Marvin to SAML validator component authorship. --- .../cas/client/validation/Saml11TicketValidationFilter.java | 1 + .../org/jasig/cas/client/validation/Saml11TicketValidator.java | 1 + 2 files changed, 2 insertions(+) diff --git a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 78d37a3..2d2e18f 100644 --- a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -32,6 +32,7 @@ import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; * context or filter init parameters. * * @author Scott Battaglia + * @author Marvin S. Addison * @version $Revision$ $Date$ * @since 3.1 */ diff --git a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 6446544..f1e5f3a 100644 --- a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -40,6 +40,7 @@ import javax.xml.namespace.NamespaceContext; * TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response. * * @author Scott Battaglia + * @author Marvin S. Addison * @since 3.1 */ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator { From 7c586299585c365842ee8c12707027005a04c7a3 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 4 May 2015 16:09:32 -0400 Subject: [PATCH 39/57] Issue 100 Restore configuration key for backward compatibility. --- .../org/jasig/cas/client/configuration/ConfigurationKeys.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java index b9838cb..9418151 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -54,6 +54,7 @@ public interface ConfigurationKeys { ConfigurationKey CAS_SERVER_URL_PREFIX = new ConfigurationKey("casServerUrlPrefix", null); ConfigurationKey ENCODING = new ConfigurationKey("encoding", null); ConfigurationKey TOLERANCE = new ConfigurationKey("tolerance", 1000L); + ConfigurationKey DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey("disableXmlSchemaValidation", Boolean.FALSE); ConfigurationKey IGNORE_PATTERN = new ConfigurationKey("ignorePattern", null); ConfigurationKey IGNORE_URL_PATTERN_TYPE = new ConfigurationKey("ignoreUrlPatternType", "REGEX"); ConfigurationKey> HOSTNAME_VERIFIER = new ConfigurationKey>("hostnameVerifier", null); From 1edef62ecb9b4fbeb8ddb993d28c192b1146daa8 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 11 May 2015 12:01:48 -0400 Subject: [PATCH 40/57] Issue #100 Isolate JodaTime to SAML module. --- cas-client-core/pom.xml | 6 --- .../jasig/cas/client/util/CommonUtils.java | 22 -------- .../cas/client/util/CommonUtilsTests.java | 6 --- cas-client-support-saml/pom.xml | 6 +++ .../org/jasig/cas/client/util/SamlUtils.java | 53 +++++++++++++++++++ .../validation/Saml11TicketValidator.java | 6 +-- .../jasig/cas/client/util/SamlUtilsTest.java | 40 ++++++++++++++ .../Saml11TicketValidatorTests.java | 20 +++---- 8 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 cas-client-support-saml/src/main/java/org/jasig/cas/client/util/SamlUtils.java create mode 100644 cas-client-support-saml/src/test/java/org/jasig/cas/client/util/SamlUtilsTest.java diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 08a42b1..f82ac35 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -34,12 +34,6 @@ 2.6 - - joda-time - joda-time - 2.7 - - xml-security xmlsec diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java index e7cc375..95eff51 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/CommonUtils.java @@ -22,9 +22,6 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -33,11 +30,6 @@ import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; import org.jasig.cas.client.validation.ProxyList; import org.jasig.cas.client.validation.ProxyListEditor; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.LocalDateTime; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.ISODateTimeFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,24 +56,10 @@ public final class CommonUtils { private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory(); - private static final DateTimeFormatter ISO_FORMAT = ISODateTimeFormat.dateTimeNoMillis(); - private CommonUtils() { // nothing to do } - public static String formatForUtcTime(final Date date) { - return ISO_FORMAT.print(new DateTime(date).withZone(DateTimeZone.UTC)); - } - - - public static Date parseUtcDate(final String date) { - if (isEmpty(date)) { - return null; - } - return ISODateTimeFormat.dateTimeParser().parseDateTime(date).toDate(); - } - /** * Check whether the object is null or not. If it is, throw an exception and * display the message. diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java index 479a3f3..1b28ad5 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/CommonUtilsTests.java @@ -21,7 +21,6 @@ package org.jasig.cas.client.util; import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import junit.framework.TestCase; import org.jasig.cas.client.PublicTestHttpServer; @@ -194,9 +193,4 @@ public final class CommonUtilsTests extends TestCase { public void testUrlEncode() { assertEquals("this+is+a+very+special+parameter+with+%3D%25%2F", CommonUtils.urlEncode("this is a very special parameter with =%/")); } - - public void testParseUtcDate() { - final Date expected = new Date(1424437961025L); - assertEquals(expected, CommonUtils.parseUtcDate("2015-02-20T08:12:41.025-0500")); - } } diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index 60c49f7..b63ae11 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -16,7 +16,13 @@ cas-client-core ${project.version} + + joda-time + joda-time + 2.7 + + org.jasig.cas.client cas-client-core diff --git a/cas-client-support-saml/src/main/java/org/jasig/cas/client/util/SamlUtils.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/util/SamlUtils.java new file mode 100644 index 0000000..8e74a71 --- /dev/null +++ b/cas-client-support-saml/src/main/java/org/jasig/cas/client/util/SamlUtils.java @@ -0,0 +1,53 @@ +/* + * 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.util; + +import java.util.Date; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * SAML utility class. + * + * @author Marvin S. Addison + * @since 3.4 + */ +public final class SamlUtils { + + private static final DateTimeFormatter ISO_FORMAT = ISODateTimeFormat.dateTimeNoMillis(); + + private SamlUtils() { + // nothing to do + } + + public static String formatForUtcTime(final Date date) { + return ISO_FORMAT.print(new DateTime(date).withZone(DateTimeZone.UTC)); + } + + public static Date parseUtcDate(final String date) { + if (CommonUtils.isEmpty(date)) { + return null; + } + return ISODateTimeFormat.dateTimeParser().parseDateTime(date).toDate(); + } +} diff --git a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index f1e5f3a..4a59081 100644 --- a/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-support-saml/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -120,9 +120,9 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator protected Assertion parseResponseFromServer(final String response) throws TicketValidationException { try { final Document document = XmlUtils.newDocument(response); - final Date assertionValidityStart = CommonUtils.parseUtcDate( + final Date assertionValidityStart = SamlUtils.parseUtcDate( XPATH_ASSERTION_DATE_START.evaluateAsString(document)); - final Date assertionValidityEnd = CommonUtils.parseUtcDate( + final Date assertionValidityEnd = SamlUtils.parseUtcDate( XPATH_ASSERTION_DATE_END.evaluateAsString(document)); if (!isValidAssertion(assertionValidityStart, assertionValidityEnd)) { throw new TicketValidationException("Invalid SAML assertion"); @@ -191,7 +191,7 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator final String request = String.format( SAML_REQUEST_TEMPLATE, generateId(), - CommonUtils.formatForUtcTime(new Date()), + SamlUtils.formatForUtcTime(new Date()), ticket); HttpURLConnection conn = null; try { diff --git a/cas-client-support-saml/src/test/java/org/jasig/cas/client/util/SamlUtilsTest.java b/cas-client-support-saml/src/test/java/org/jasig/cas/client/util/SamlUtilsTest.java new file mode 100644 index 0000000..bd42201 --- /dev/null +++ b/cas-client-support-saml/src/test/java/org/jasig/cas/client/util/SamlUtilsTest.java @@ -0,0 +1,40 @@ +/* + * 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.util; + +import java.util.Date; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Test cases for {@link SamlUtils}. + * + * @author Marvin S. Addison + */ +public class SamlUtilsTest { + + @Test + public void testParseUtcDate() { + final Date expected = new Date(1424437961025L); + assertEquals(expected, SamlUtils.parseUtcDate("2015-02-20T08:12:41.025-0500")); + } +} \ No newline at end of file diff --git a/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java b/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java index 7738966..8d90800 100644 --- a/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java +++ b/cas-client-support-saml/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java @@ -24,7 +24,7 @@ import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.Date; import org.jasig.cas.client.PublicTestHttpServer; -import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.SamlUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; @@ -83,13 +83,13 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes final Interval range = currentTimeRangeInterval(); final Date now = new Date(); final String RESPONSE = "testtestPrincipalurn:oasis:names:tc:SAML:1.0:cm:artifact"; server.content = RESPONSE.getBytes(server.encoding); try { @@ -107,21 +107,21 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes final String response = "" + "" + "" + "" + "" + "https://example.com/test-client/secure/" + "" + "" + "testPrincipal" + "urn:oasis:names:tc:SAML:1.0:cm:artifact" From f5b2275913090136b70681eda703422d0b7b4102 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 11 May 2015 12:09:00 -0400 Subject: [PATCH 41/57] Issue #100 Bump minor version due to refactoring. --- cas-client-core/pom.xml | 2 +- .../src/main/java/org/jasig/cas/client/util/IOUtils.java | 2 +- .../java/org/jasig/cas/client/util/MapNamespaceContext.java | 2 +- .../org/jasig/cas/client/util/ThreadLocalXPathExpression.java | 2 +- cas-client-integration-atlassian/pom.xml | 2 +- cas-client-integration-jboss/pom.xml | 2 +- cas-client-integration-tomcat-common/pom.xml | 2 +- cas-client-integration-tomcat-v6/pom.xml | 2 +- cas-client-integration-tomcat-v7/pom.xml | 2 +- cas-client-support-distributed-ehcache/pom.xml | 2 +- cas-client-support-distributed-memcached/pom.xml | 2 +- cas-client-support-saml/pom.xml | 2 +- pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index f82ac35..e8d0a31 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java index f3c3107..b003775 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/IOUtils.java @@ -8,7 +8,7 @@ import java.nio.charset.Charset; * IO utility class. * * @author Marvin S. Addison - * @since 3.3.4 + * @since 3.4 */ public final class IOUtils { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java index f6c2199..6eb5b62 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/MapNamespaceContext.java @@ -10,7 +10,7 @@ import java.util.Map; * Namespace context implementation backed by a map of XML prefixes to namespace URIs. * * @author Marvin S. Addison - * @since 3.3.4 + * @since 3.4 */ public class MapNamespaceContext implements NamespaceContext { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java index f1ed1f4..2e51c0c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ThreadLocalXPathExpression.java @@ -11,7 +11,7 @@ import javax.xml.xpath.*; * Thread local XPath expression. * * @author Marvin S. Addison - * @since 3.3.4 + * @since 3.4 */ public class ThreadLocalXPathExpression extends ThreadLocal implements XPathExpression { diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index ce13bce..009a58d 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index 5a118ea..43c24da 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index 06a1c33..13c2317 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 37d0465..d7dd9bd 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index e1068ba..0c83322 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index 1e1f712..c4bcde0 100644 --- a/cas-client-support-distributed-ehcache/pom.xml +++ b/cas-client-support-distributed-ehcache/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 Jasig CAS Client for Java - Distributed Proxy Storage Support: EhCache diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index 52a8640..3a1cb2a 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -3,7 +3,7 @@ cas-client org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index b63ae11..6c68d43 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT cas-client 4.0.0 diff --git a/pom.xml b/pom.xml index bac41ce..e17ab10 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.3.4-SNAPSHOT + 3.4.0-SNAPSHOT cas-client pom From d3ba9c0ae7c2e93f92658569729a278ffb299328 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 02:45:28 +0400 Subject: [PATCH 42/57] Delete README.txt --- README.txt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 README.txt diff --git a/README.txt b/README.txt deleted file mode 100644 index 97a80ee..0000000 --- a/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -BUILDING THE CAS CLIENT FOR JAVA - -Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache -Clients). In order to build the clients, you must enable the commented out repositories in the appropriate pom.xml -files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the -instructions on how to install the file manually. From f8f5b908d07e0b83eecd43a8479bdc3d63a9c5d6 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 02:46:17 +0400 Subject: [PATCH 43/57] Create README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a33a281 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Java Apereo CAS Client +================================== + +## Build +Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache +Clients). In order to build the clients, you must enable the commented out repositories in the appropriate pom.xml +files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the +instructions on how to install the file manually. From 74f0a209dd4d327a6127569edb97dce0ce771b64 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 16:40:15 +0400 Subject: [PATCH 44/57] Update README.md --- README.md | 501 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 497 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a33a281..da52ab0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,501 @@ -# Java Apereo CAS Client +# Java Apereo CAS Client [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas.client/cas-client-core/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas/cas-server) ================================== +## Intro +This is the official home of the Java Apereo CAS client. The client consists of a collection of Servlet filters that are suitable for most Java-based web applications. It also serves as an API platform to interact with the CAS server programmatically to make authentication requests, validate tickets and consume principal attributes. + +All client artifacts are published to Maven central. At a minimum, a given application will need to configure the following dependency: + +```xml + + org.jasig.cas.client + cas-client-core + ${java.cas.client.version} + +``` +## Configurtion + +### Client Configuration Using `web.xml` + +The client can be configured via `web.xml` via a series of `context-param`s and filter `init-param`s. Each filter for the client has a required (and optional) set of properties. The filters are designed to look for these properties in the following way: + +- Check the filter's local `init-param`s for a parameter matching the required property name. +- Check the `context-param`s for a parameter matching the required property name. +- If two properties are found with the same name in the `init-param`s and the `context-param`s, the `init-param` takes precedence. + +**Note**: If you're using the `serverName` property, you should note well that the fragment-URI (the stuff after the #) is not sent to the server by all browsers, thus the CAS client can't capture it as part of the URL. + +An example application that is protected by the client is [available here](https://github.com/UniconLabs/cas-sample-java-webapp). + +#### org.jasig.cas.client.authentication.AuthenticationFilter +The `AuthenticationFilter` is what detects whether a user needs to be authenticated or not. If a user needs to be authenticated, it will redirect the user to the CAS server. + +```xml + + CAS Authentication Filter + org.jasig.cas.client.authentication.AuthenticationFilter + + casServerLoginUrl + https://battags.ad.ess.rutgers.edu:8443/cas/login + + + serverName + http://www.acme-client.com + + +``` + +| Property | Description | Required +|----------|-------|----------- +| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login` | Yes +| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. https://localhost:8443 (you must include the protocol, but port is optional if it's a standard port). | Yes +| `service` | The service URL to send to the CAS server, i.e. `https://localhost:8443/yourwebapp/index.html` | No +| `renew` | specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No +| `gateway ` | specifies whether `gateway=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all) | No +| `artifactParameterName ` | specifies the name of the request parameter on where to find the artifact (i.e. `ticket`). | No +| `serviceParameterName ` | specifies the name of the request parameter on where to find the service (i.e. `service`) | No + + +#### org.jasig.cas.client.authentication.Saml11AuthenticationFilter +The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be authenticated or not. If a user needs to be authenticated, it will redirect the user to the CAS server. + +```xml + + CAS Authentication Filter + org.jasig.cas.client.authentication.Saml11AuthenticationFilter + + casServerLoginUrl + https://somewhere.cas.edu:8443/cas/login + + + serverName + http://www.the-client.com + + +``` + +| Property | Description | Required +|----------|-------|----------- +| `casServerLoginUrl` | Defines the location of the CAS server login URL, i.e. `https://localhost:8443/cas/login` | Yes +| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. https://localhost:8443 (you must include the protocol, but port is optional if it's a standard port). | Yes +| `service` | The service URL to send to the CAS server, i.e. `https://localhost:8443/yourwebapp/index.html` | No +| `renew` | specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No +| `gateway ` | specifies whether `gateway=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all) | No +| `artifactParameterName ` | specifies the name of the request parameter on where to find the artifact (i.e. `SAMLart`). | No +| `serviceParameterName ` | specifies the name of the request parameter on where to find the service (i.e. `TARGET`) | No + + +####org.jasig.cas.client.validation.Cas10TicketValidationFilter +Validates tickets using the CAS 1.0 Protocol. + +```xml + + CAS Validation Filter + org.jasig.cas.client.validation.Cas10TicketValidationFilter + + casServerUrlPrefix + https://somewhere.cas.edu:8443/cas + + +``` + +| Property | Description | Required +|----------|-------|----------- +| `casServerUrlPrefix ` | The start of the CAS server URL, i.e. `https://localhost:8443/cas` | Yes +| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. `https://localhost:8443` (you must include the protocol, but port is optional if it's a standard port). | Yes +| `renew` | Specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No +| `redirectAfterValidation ` | Whether to redirect to the same URL after ticket validation, but without the ticket in the parameter. Defaults to `true`. | No +| `useSession ` | Whether to store the Assertion in session or not. If sessions are not used, tickets will be required for each request. Defaults to `true`. | No +| `exceptionOnValidationFailure ` | Whether to throw an exception or not on ticket validation failure. Defaults to `true`. | No + + +#### org.jasig.cas.client.validation.Saml11TicketValidationFilter +Validates tickets using the SAML 1.1 protocol. + +```xml + + CAS Validation Filter + org.jasig.cas.client.validation.Saml11TicketValidationFilter + + casServerUrlPrefix + https://battags.ad.ess.rutgers.edu:8443/cas + + + serverName + http://www.acme-client.com + + +``` + +| Property | Description | Required +|----------|-------|----------- +| `casServerUrlPrefix ` | The start of the CAS server URL, i.e. `https://localhost:8443/cas` | Yes +| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. `https://localhost:8443` (you must include the protocol, but port is optional if it's a standard port). | Yes +| `renew` | Specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No +| `redirectAfterValidation ` | Whether to redirect to the same URL after ticket validation, but without the ticket in the parameter. Defaults to `true`. | No +| `useSession ` | Whether to store the Assertion in session or not. If sessions are not used, tickets will be required for each request. Defaults to `true`. | No +| `exceptionOnValidationFailure ` | whether to throw an exception or not on ticket validation failure. Defaults to `true` | No +| `tolerance ` | The tolerance for drifting clocks when validating SAML tickets. Note that 10 seconds should be more than enough for most environments that have NTP time synchronization. Defaults to `1000 msec` | No + + +#### org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter +Validates the tickets using the CAS 2.0 protocol. If you provide either the `acceptAnyProxy` or the `allowedProxyChains` parameters, a `Cas20ProxyTicketValidator` will be constructed. Otherwise a general `Cas20ServiceTicketValidator` will be constructed that does not accept proxy tickets. + +**Note**: If you are using proxy validation, you should place the `filter-mapping` of the validation filter before the authentication filter. + +```xml + + CAS Validation Filter + org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter + + casServerUrlPrefix + https://battags.ad.ess.rutgers.edu:8443/cas + + + serverName + http://www.acme-client.com + + +``` + +| Property | Description | Required +|----------|-------|----------- +| `casServerUrlPrefix ` | The start of the CAS server URL, i.e. `https://localhost:8443/cas` | Yes +| `serverName` | The name of the server this application is hosted on. Service URL will be dynamically constructed using this, i.e. `https://localhost:8443` (you must include the protocol, but port is optional if it's a standard port). | Yes +| `renew` | Specifies whether `renew=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all). Note that `renew` cannot be specified as local `init-param` setting. | No +| `redirectAfterValidation ` | Whether to redirect to the same URL after ticket validation, but without the ticket in the parameter. Defaults to `true`. | No +| `useSession ` | Whether to store the Assertion in session or not. If sessions are not used, tickets will be required for each request. Defaults to `true`. | No +| `exceptionOnValidationFailure ` | whether to throw an exception or not on ticket validation failure. Defaults to `true` | No +| `proxyReceptorUrl ` | The URL to watch for `PGTIOU/PGT` responses from the CAS server. Should be defined from the root of the context. For example, if your application is deployed in `/cas-client-app` and you want the proxy receptor URL to be `/cas-client-app/my/receptor` you need to configure proxyReceptorUrl to be `/my/receptor`. | No +| `acceptAnyProxy ` | Specifies whether any proxy is OK. Defaults to `false`. | No +| `allowedProxyChains ` | Specifies the proxy chain. Each acceptable proxy chain should include a space-separated list of URLs. Each acceptable proxy chain should appear on its own line. | No +| `proxyCallbackUrl` | The callback URL to provide the CAS server to accept Proxy Granting Tickets. | No +| `proxyGrantingTicketStorageClass ` | Specify an implementation of the ProxyGrantingTicketStorage class that has a no-arg constructor. | No + + +##### Proxy Authentication vs. Distributed Caching +The client has support for clustering and distributing the TGT state among application nodes that are behind a load balancer. In order to do so, the parameter needs to be defined as such for the filter. + +###### Ehcache + +Include the following dependency: + +```xml + + org.jasig.cas + cas-client-support-distributed-ehcache + ${java.cas.client.version} + +``` + +Configure the client: + +```xml + + proxyGrantingTicketStorageClass + org.jasig.cas.client.proxy.EhcacheBackedProxyGrantingTicketStorageImpl + +``` +The setting provides an implementation for proxy storage using EhCache to take advantage of its replication features so that the PGT is successfully replicated and shared among nodes, regardless which node is selected as the result of the load balancer rerouting. + +Configuration of this parameter is not enough. The EhCache configuration needs to enable the replication mechanism through once of its suggested ways. A sample of that configuration based on RMI replication can be found here. Please note that while the sample is done for a distributed ticket registry implementation, the basic idea and configuration should easily be transferable. + +When loading from the `web.xml`, the Jasig CAS Client relies on a series of default values, one of which being that the cache must be configured in the default location (i.e. `classpath:ehcache.xml`). + +```xml + + + + + + + +``` + +###### Memcached +A similar implementation based on Memcached is also available: + +Include the following dependency: + +```xml + + org.jasig.cas + cas-client-support-distributed-memcached + ${java.cas.client.version} + +``` + +Configure the client: + +```xml + + proxyGrantingTicketStorageClass + org.jasig.cas.client.proxy. MemcachedBackedProxyGrantingTicketStorageImpl + +``` + +When loading from the `web.xml`, the Client relies on a series of default values, one of which being that the list of memcached servers must be defined in `/cas/casclient_memcached_hosts.txt` on the classpath). The file is a simple list of `:` on separate lines. **BE SURE NOT TO HAVE EXTRA LINE BREAKS**. + +#### org.jasig.cas.client.util.HttpServletRequestWrapperFilter +Wraps an `HttpServletRequest` so that the `getRemoteUser` and `getPrincipal` return the CAS related entries. + +```xml + + CAS HttpServletRequest Wrapper Filter + org.jasig.cas.client.util.HttpServletRequestWrapperFilter + +``` + +#### org.jasig.cas.client.util.AssertionThreadLocalFilter +Places the `Assertion` in a `ThreadLocal` for portions of the application that need access to it. This is useful when the Web application that this filter "fronts" needs to get the Principal name, but it has no access to the `HttpServletRequest`, hence making `getRemoteUser()` call impossible. + +```xml + + CAS Assertion Thread Local Filter + org.jasig.cas.client.util.AssertionThreadLocalFilter + +``` + +### Client Configuration Using Spring + +Configuration via Spring IoC will depend heavily on `DelegatingFilterProxy` class. For each filter that will be configured for CAS via Spring, a corresponding `DelegatingFilterProxy` is needed in the web.xml. + +As the `SingleSignOutFilter`, `HttpServletRequestWrapperFilter` and `AssertionThreadLocalFilter` have no configuration options, we recommend you just configure them in the `web.xml` + +```xml + + CAS Authentication Filter + org.springframework.web.filter.DelegatingFilterProxy + + targetBeanName + authenticationFilter + + + + CAS Authentication Filter + /* + +``` + +#### Bean Configuration + +##### AuthenticationFilter +```xml + +``` + +##### Cas10TicketValidationFilter +```xml + + + + + + + +``` + +##### Saml11TicketValidationFilter +```xml + + + + + + + +``` + +##### Cas20ProxyReceivingTicketValidationFilter +Configuration to validate tickets: +```xml + + + + + + + +``` + +Configuration to accept a Proxy Granting Ticket: +```xml + + + + + + + +``` + +Configuration to accept any Proxy Ticket (and Proxy Granting Tickets): + +```xml + + + + + + + +``` + +Configuration to accept Proxy Ticket from a chain (and Proxy Granting Tickets): + +```xml + + + + + + + http://proxy1 http://proxy2 + + + + + +``` + +The specific filters can be configured in the following ways. Please see the JavaDocs included in the distribution for specific required and optional properties: + + +### Client Configuration Using JNDI + +Configuring the CAS client via JNDI is essentially the same as configuring the client via the `web.xml`, except the properties will reside in JNDI and not in the `web.xml`. +All properties that are placed in JNDI should be placed under `java:comp/env/cas` + +We use the following conventions: +1. JNDI will first look in `java:comp/env/cas/{SHORT FILTER NAME}/{PROPERTY NAME}` (i.e. `java:comp/env/cas/AuthenticationFilter/serverName`) +2. JNDI will as a last resort look in `java:comp/env/cas/{PROPERTY NAME}` (i.e. `java:comp/env/cas/serverName`) + +#### Example +This is an update to the `META-INF/context.xml` that is included in Tomcat's Manager application: + +```xml + + + + + + + + + +``` + +### Configuring Single Sign Out +The Single Sign Out support in CAS consists of configuring one `SingleSignOutFilter` and one `ContextListener`. Please note that if you have configured the CAS Client for Java as Web filters, this filter must come before the other filters as described. + +The `SingleSignOutFilter` can affect character encoding. This becomes most obvious when used in conjunction with Confluence. Its recommended you explicitly configure either the [VT Character Encoding Filter](http://code.google.com/p/vt-middleware/wiki/vtservletfilters#CharacterEncodingFilter) or the [Spring Character Encoding Filter](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html) with explicit encodings. + +#### CAS Protocol + +```xml + + CAS Single Sign Out Filter + org.jasig.cas.client.session.SingleSignOutFilter + +... + + CAS Single Sign Out Filter + /* + +... + + org.jasig.cas.client.session.SingleSignOutHttpSessionListener + +``` + +#### SAML Protocol + +```xml +filter> + CAS Single Sign Out Filter + org.jasig.cas.client.session.SingleSignOutFilter + + artifactParameterName + SAMLart + + +... + + CAS Single Sign Out Filter + /* + +... + + org.jasig.cas.client.session.SingleSignOutHttpSessionListener + +``` + +#### Recommend Logout Procedure +The client has no code to help you handle log out. The client merely places objects in session. Therefore, we recommend you do a `session.invalidate()` call when you log a user out. However, that's entirely your application's responsibility. We recommend that text similar to the following appear when the application's session is ended. + +```html +You have been logged out of [APPLICATION NAME GOES HERE]. +To log out of all applications, click here. (provide link to CAS server's logout) +``` + +## JBoss Integration + +## Tomcat 6 Integration + +## Tomcat 7 Integration + +## Confluence Integration ## Build + +```bash +git clone git@github.com:Jasig/java-cas-client.git +cd java-cas-client +mvn clean package +``` + Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache -Clients). In order to build the clients, you must enable the commented out repositories in the appropriate pom.xml -files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the -instructions on how to install the file manually. +Clients). In order to build the clients, you must enable the commented out repositories in the appropriate `pom.xml` +files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the instructions on how to install the file manually. From 8ec71aa2c6cf72dcd0bc771cc5a52b091cffdbf7 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 16:41:15 +0400 Subject: [PATCH 45/57] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da52ab0..e61956d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Java Apereo CAS Client [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas.client/cas-client-core/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas/cas-server) -================================== + ## Intro This is the official home of the Java Apereo CAS client. The client consists of a collection of Servlet filters that are suitable for most Java-based web applications. It also serves as an API platform to interact with the CAS server programmatically to make authentication requests, validate tickets and consume principal attributes. From a31979920b12f117dae546046c9654aa3f2f8b2a Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 21:50:09 +0400 Subject: [PATCH 46/57] Update README.md --- README.md | 497 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 473 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e61956d..9eccc72 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,11 @@ ## Intro This is the official home of the Java Apereo CAS client. The client consists of a collection of Servlet filters that are suitable for most Java-based web applications. It also serves as an API platform to interact with the CAS server programmatically to make authentication requests, validate tickets and consume principal attributes. -All client artifacts are published to Maven central. At a minimum, a given application will need to configure the following dependency: +All client artifacts are published to Maven central. Depending on functionality, applications will need include one or more of the listed dependencies in their configuration. + +## Components + +- Core functionality, which includes CAS authentication/validation filters. ```xml @@ -12,6 +16,77 @@ All client artifacts are published to Maven central. At a minimum, a given appli ${java.cas.client.version} ``` + +- Support for SAML functionality is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-support-saml + ${java.cas.client.version} + +``` + +- Distributed proxy ticket caching with Ehcache is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-support-distributed-ehcache + ${java.cas.client.version} + +``` + +- Distributed proxy ticket caching with Memcached is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-support-distributed-memcached + ${java.cas.client.version} + +``` + +- Atlassian integration is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-integration-atlassian + ${java.cas.client.version} + +``` + +- JBoss integration is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-integration-jboss + ${java.cas.client.version} + +``` + +- Tomcat 6 integration is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-integration-tomcat-v6 + ${java.cas.client.version} + +``` + +- Tomcat 7 is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-integration-tomcat-v7 + ${java.cas.client.version} + +``` + ## Configurtion ### Client Configuration Using `web.xml` @@ -177,16 +252,6 @@ The client has support for clustering and distributing the TGT state among appli ###### Ehcache -Include the following dependency: - -```xml - - org.jasig.cas - cas-client-support-distributed-ehcache - ${java.cas.client.version} - -``` - Configure the client: ```xml @@ -220,17 +285,7 @@ When loading from the `web.xml`, the Jasig CAS Client relies on a series of defa ``` ###### Memcached -A similar implementation based on Memcached is also available: - -Include the following dependency: - -```xml - - org.jasig.cas - cas-client-support-distributed-memcached - ${java.cas.client.version} - -``` +A similar implementation based on Memcached is also available. Configure the client: @@ -430,7 +485,7 @@ type="java.lang.String" value="https://www.apereo.org/cas"/> ### Configuring Single Sign Out The Single Sign Out support in CAS consists of configuring one `SingleSignOutFilter` and one `ContextListener`. Please note that if you have configured the CAS Client for Java as Web filters, this filter must come before the other filters as described. -The `SingleSignOutFilter` can affect character encoding. This becomes most obvious when used in conjunction with Confluence. Its recommended you explicitly configure either the [VT Character Encoding Filter](http://code.google.com/p/vt-middleware/wiki/vtservletfilters#CharacterEncodingFilter) or the [Spring Character Encoding Filter](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html) with explicit encodings. +The `SingleSignOutFilter` can affect character encoding. This becomes most obvious when used in conjunction with applications such as Atlassian Confluence. Its recommended you explicitly configure either the [VT Character Encoding Filter](http://code.google.com/p/vt-middleware/wiki/vtservletfilters#CharacterEncodingFilter) or the [Spring Character Encoding Filter](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html) with explicit encodings. #### CAS Protocol @@ -480,13 +535,407 @@ You have been logged out of [APPLICATION NAME GOES HERE]. To log out of all applications, click here. (provide link to CAS server's logout) ``` +## JAAS +The client supports the Java Authentication and Authorization Service (JAAS) framework, which provides authnz facilities to CAS-enabled JEE applications. + +A general JAAS authentication module, `CasLoginModule`, is available with the specific purpose of providing authentication and authorization services to CAS-enabled JEE applications. The design of the module is simple: given a service URL and a service ticket in a `NameCallback` and `PasswordCallback`, respectively, the module contacts the CAS server and attempts to validate the ticket. In keeping with CAS integration for Java applications, a JEE container-specific servlet filter is needed to protect JEE Web applications. The JAAS support should be extensible to any JEE container. + +### Configure CasLoginModule +It is expected that for JEE applications both authentication and authorization services will be required for CAS integration. The following JAAS module configuration file excerpt demonstrates how to leverage SAML 1.1 attribute release in CAS to provide authorization data in addition to authentication: + +```json +cas { + org.jasig.cas.client.jaas.CasLoginModule required + ticketValidatorClass="org.jasig.cas.client.validation.Saml11TicketValidator" + casServerUrlPrefix="https://cas.example.com/cas" + tolerance="20000" + service="https://webapp.example.com/webapp" + defaultRoles="admin,operator" + roleAttributeNames="memberOf,eduPersonAffiliation" + principalGroupName="CallerPrincipal" + roleGroupName="Roles" + cacheAssertions="true" + cacheTimeout="480"; +} +``` + + +| Property | Description | Required +|----------|-------|-----------| +| `ticketValidatorClass ` | Fully-qualified class name of CAS ticket validator class. | Yes +| `casServerUrlPrefix` | URL to root of CAS Web application context. | Yes +| `service` | CAS service parameter that may be overridden by callback handler. **Note**: service must be specified by at least one component such that it is available at service ticket validation time. | No +| `defaultRoles` | Comma-delimited list of static roles applied to all authenticated principals. | No +| `roleAttributeNames` | Comma-delimited list of attribute names that describe role data delivered to CAS in the service-ticket validation response that should be applied to the current authenticated principal. | No +| `principalGroupName` | The name of a group principal containing the primary principal name of the current JAAS subject. The default value is `CallerPrincipal`. | No +| `roleGroupName` | The name of a group principal containing all role data. The default value is `Roles`. | No +| `cacheAssertions` | Flag to enable assertion caching. This may be required for JAAS providers that attempt to periodically reauthenticate to renew principal. Since CAS tickets are one-time-use, a cached assertion must be provided on reauthentication. | No +| `cacheTimeout` | Assertion cache timeout in minutes. | No +| `tolerance` | The tolerance for drifting clocks when validating SAML tickets. | No + + ## JBoss Integration +In keeping with CAS integration for Java applications, a JEE container-specific servlet filter is needed to protect JEE Web applications. The JBoss `WebAuthenticationFilter` component provided a convenient integration piece between a servlet filter and the JAAS framework, so a complete integration solution is available only for JBoss AS versions that provide the `WebAuthenticationFilter` class. The JAAS support should be extensible to any JEE container with additional development. + +For JBoss it is vitally important to use the correct values for `principalGroupName` and `roleGroupName`. Additionally, the `cacheAssertions` and `cacheTimeout` are required since JBoss by default attempts to reauthenticate the JAAS principal with a fairly aggressive default timeout. Since CAS tickets are single-use authentication tokens by default, assertion caching is required to support periodic reauthentication. + +### Configure Servlet Filters + +Integration with the servlet pipeline is required for a number of purposes: + +1. Examine servlet request for an authenticated session +2. Redirect to CAS server for unauthenticated sessions +3. Provide service URL and CAS ticket to JAAS pipeline for validation + +The `WebAuthenticationFilter` performs these operations for the JBoss AS container. It is important to note that this filter simply collects the service URL and CAS ticket from the request and passes it to the JAAS pipeline. It is assumed that the `CasLoginModule` will be present in the JAAS pipeline to consume the data and perform ticket validation. The following web.xml excerpts demonstrate how to integrate WebAuthenticationFilter into a JEE Web application. + + +```xml +... + + CASWebAuthenticationFilter + org.jasig.cas.client.jboss.authentication.WebAuthenticationFilter + + + + CASAuthenticationFilter + org.jasig.cas.client.authentication.AuthenticationFilter + + casServerLoginUrl + https://cas.example.com/cas/login + + +... +``` + +The JAAS LoginModule configuration in `conf/login-config.xml` may require the following changes in a JBoss environment: + +```xml + + + + org.jasig.cas.client.validation.Saml11TicketValidator + http://yourcasserver/cas + 20000 + admin,user + memberOf,eduPersonAffiliation,authorities + CallerPrincipal + Roles + true + 480 + + + +``` +It may be necessary to modify the JBoss `server.xml` and uncomment: + +```xml + +``` + +Remember not to add `` and `` elements in your `web.xml`. + +If you have any trouble, you can enable the log of cas in `jboss-logging.xml` by adding: + +```xml + + + +``` + ## Tomcat 6 Integration ## Tomcat 7 Integration -## Confluence Integration +## Atlassian Integration +The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators. + +### Configuration + +#### $JIRA_HOME Location + +- WAR/EAR Installation: /webapp +`/opt/atlassian/jira/atlassian-jira-enterprise-x.y.z/webapp` + +- Standalone: /atlassian-jira +`/opt/atlassian/jira/atlassian-jira-enterprise-x.y.z-standalone/atlassian-jira` + +#### $CONFLUENCE_INSTALL Description + +- /confluence +`/opt/atlassian/confluence/confluence-x.y.z/confluence` + +#### Changes to web.xml +Add the CAS filters to the end of the filter list. See `web.xml` configuration of the client. + + +#### Modify the seraph-config.xml +To rely on the Single Sign Out functionality to sign off of Jira, comment out the normal logout URL and replace it with the CAS logout URL. Also, change the login links to point to the CAS login service. + +```xml + + + login.url + + http://cas.institution.edu/cas/login?service=${originalurl} + + + + link.login.url + + + http://cas.institution.edu/cas/login?service=${originalurl} + + + + logout.url + + https://cas.institution.edu/cas/logout + +``` + +#### CAS Authenticator +Comment out the `DefaultAuthenticator` like so in `[$JIRA_HOME|$CONFLUENCE_INSTALL]/WEB-INF/classes/seraph-config.xml`: + +```xml + + + +``` + +For JIRA, add in the Client Jira Authenticator: + +```xml + + + +``` + +For Confluence, add in the Client Confluence Authenticator: + +```xml + + + +``` + +#### Confluence CAS Logout + +As of this writing, Atlassian doesn't support a config option yet (like Jira). To rely on the Single Sign Out functionality to sign off of Confluence we need to modify the logout link. + + +- Copy `$CONFLUENCE_INSTALL/WEB-INF/lib/confluence-x.x.x.jar` to a temporary directory +- `mkdir /tmp/confluence-jar && cp WEB-INF/lib/confluence-x.y.z.jar /tmp/confluence-jar` +- Unpack the jar +- `cd /tmp/confluence-jar && jar xvf confluence-x.y.z.jar` +- `cp xwork.xml $CONFLUENCE_INSTALL/WEB-INF/classes` +- `cp xwork.xml $CONFLUENCE_INSTALL/WEB-INF/classes/ && cd $CONFLUENCE_INSTALL/WEB-INF/classes/` +- Edit `$CONFLUENCE_INSTALL/WEB-INF/classes/xwork.xml`, find the logout action and comment out the success result and replace it with this one: + +```xml + + +https://cas.institution.edu/cas/logout + +``` + +#### Copy Jars +Copy cas-client-core-x.y.x.jar and cas-client-integration-atlassian-x.y.x.jar to `$JIRA_HOME/WEB-INF/lib` + +## Spring Security Integration +This configuration tested against the sample application that is included with Spring Security. As of this writing, replacing the `applicationContext-security.xml` in the sample application with the one below would enable this alternative configuration. We can not guarantee this version will work without modification in future versions of Spring Security. + +### Changes to web.xml + +```xml +... + + contextConfigLocation + + /WEB-INF/applicationContext-security.xml + + + + + log4jConfigLocation + /WEB-INF/classes/log4j.properties + + + + webAppRootKey + cas.root + + + + CAS Single Sign Out Filter + org.jasig.cas.client.session.SingleSignOutFilter + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + + CAS Single Sign Out Filter + /* + + + + springSecurityFilterChain + /* + + + + org.jasig.cas.client.session.SingleSignOutHttpSessionListener + + + + org.springframework.web.context.ContextLoaderListener + + + + org.springframework.web.util.Log4jConfigListener + + + + 403 + /casfailed.jsp + +... +``` + +The important additions to the `web.xml` include the addition of the 403 error page. 403 is what the CAS Validation Filter will throw if it has a problem with the ticket. Also, if you want Single Log Out, you should enable the `SingleSignOutHttpSessionListener`. + +### Changes to applicationContext-security.xml + +```xml +... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +... +``` + +1. You should replace the userService with something that checks your user storage. +2. Replace the `serverName` and `casServerLoginUrl` with your values (or better yet, externalize them). +3. Replace the URLs with the URL configuration for your application. ## Build From d72913b53a2d33210c50eea9ea3854400a4490a4 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 22:01:48 +0400 Subject: [PATCH 47/57] Update README.md --- README.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9eccc72..6018115 100644 --- a/README.md +++ b/README.md @@ -543,7 +543,7 @@ A general JAAS authentication module, `CasLoginModule`, is available with the sp ### Configure CasLoginModule It is expected that for JEE applications both authentication and authorization services will be required for CAS integration. The following JAAS module configuration file excerpt demonstrates how to leverage SAML 1.1 attribute release in CAS to provide authorization data in addition to authentication: -```json +``` cas { org.jasig.cas.client.jaas.CasLoginModule required ticketValidatorClass="org.jasig.cas.client.validation.Saml11TicketValidator" @@ -644,9 +644,144 @@ If you have any trouble, you can enable the log of cas in `jboss-logging.xml` by ``` -## Tomcat 6 Integration +## Tomcat 6/7 Integration +The client supports container-based CAS authentication and authorization support for the Tomcat servlet container. -## Tomcat 7 Integration +Suppose a single Tomcat container hosts multiple Web applications with similar authentication and authorization needs. Prior to Tomcat container support, each application would require a similar configuration of CAS servlet filters and authorization configuration in the `web.xml` servlet descriptor. Using the new container-based authentication/authorization feature, a single CAS configuration can be applied to the container and leveraged by all Web applications hosted by the container. + +CAS authentication support for Tomcat is based on the Tomcat-specific Realm component. The Realm component has a fairly broad surface area and RealmBase is provided as a convenient superclass for custom implementations; the CAS realm implementations derive from `RealmBase`. Unfortunately RealmBase and related components have proven to change over both major and minor number releases, which requires version-specific CAS components for integration. We have provided two packages with similar components with the hope of supporting all 6.x and 7.x versions. **No support for 5.x is provided.** + +### Component Overview +In the following discussion of components, only the Tomcat 6.x components are mentioned. The Tomcat 7.0.x components have exactly the same name, but **are in the tomcat.v7 package**, e.g. `org.jasig.cas.client.tomcat.v7.Cas20CasAuthenticator`. + +#### Authenticators +Authenticators are responsible for performing CAS authentication using a particular protocol. All protocols supported by the Jasig Java CAS client are supported: CAS 1.0, CAS 2.0, and SAML 1.1. The following components provide protocol-specific support: + +``` +org.jasig.cas.client.tomcat.v6.Cas10CasAuthenticator +org.jasig.cas.client.tomcat.v6.Cas20CasAuthenticator +org.jasig.cas.client.tomcat.v6.Cas20ProxyCasAuthenticator +org.jasig.cas.client.tomcat.v6.Saml11Authenticator +``` + +#### Realms +In terms of CAS configuration, Tomcat realms serve as containers for users and role definitions. The roles defined in a Tomcat realm may be referenced in the web.xml servlet descriptor to define authorization constraints on Web applications hosted by the container. Two sources of user/role data are supported: + +``` +org.jasig.cas.client.tomcat.v6.PropertiesCasRealm +org.jasig.cas.client.tomcat.v6.AssertionCasRealm +``` + +`PropertiesCasRealm` uses a Java properties file as a source of static user/role information. This component is conceptually similar to the `MemoryRealm` component that ships with Tomcat and defines user/role data via XML configuration. The PropertiesCasRealm is different in that it explicitly lacks support for passwords, which have no use with CAS. + +`AssertionCasRealm` is designed to be used in conjunction with the SAML 1.1. protocol to take advantage of CAS attribute release to provide for dynamic user/role data driven by the CAS server. With this component the deployer may define a role attribute, e.g. memberOf, which could be backed by LDAP group membership information. In that case the user would be added to all roles defined in the SAML attribute assertion for values of the the `memberOf` attribute. + +#### Valves +A number of Tomcat valves are provided to handle functionality outside Realms and Authenticators. + +##### Logout Valves +Logout valves provide a way of destroying the CAS authentication state bound to the container for a particular user/session; the destruction of authenticated state is synonymous with logout for the container and its hosted applications. (Note this does not destroy the CAS SSO session.) The implementations provide various strategies to map a URI onto the state-destroying logout function. + +``` +org.jasig.cas.client.tomcat.v6.StaticUriLogoutValve +org.jasig.cas.client.tomcat.v6.RegexUriLogoutValve +``` + +##### SingleSignOutValve +The `org.jasig.cas.client.tomcat.v6.SingleSignOutValve` allows the container to participate in CAS single sign-out. In particular this valve handles the SAML LogoutRequest message sent from the CAS server that is delivered when the CAS SSO session ends. + +##### ProxyCallbackValve +The `org.jasig.cas.client.tomcat.v6.ProxyCallbackValve` provides a handler for watching request URIs for requests that contain a proxy callback request in support of the CAS 2.0 protocol proxy feature. + +### Container Setup +The version-specific CAS libraries must be placed on the container classpath, `$CATALINA_HOME/lib`. + +### Context Configuration +The Realm, Authenticator, and Valve components are wired together inside a Tomcat Context configuration element. The location and scope of the Context determines the scope of the applied configuration. To apply a CAS configuration to every Web application hosted in the container, configure the default Context at `$CATALINA_HOME/conf/context.xml`. Note that individual Web applications/servlets can override the default context; see the Context Container reference for more information. + +Alternatively, CAS configuration can be applied to individual Web applications through a Context configuration element located in a `$CONTEXT_NAME.xml` file placed in `$CATALINA_HOME/conf/$ENGINE/$HOST`, where `$ENGINE` is typically Catalina and `$HOST` is `localhost`, `$CATALINA_HOME/conf/Catalina/localhost`. For example, to configure the Tomcat manager servlet, a `manager.xml` file contains Context configuration elements. + +```xml + + + + + + + + + + + + +``` + +The following example shows how to configure a Context for dynamic role data provided by the CAS attribute release feature. + +```xml + + + + + + + + + +``` ## Atlassian Integration The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators. @@ -947,4 +1082,4 @@ mvn clean package Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache Clients). In order to build the clients, you must enable the commented out repositories in the appropriate `pom.xml` -files in the modules (cas-client-integration-jboss and cas-client-support-distributed-memcached) or follow the instructions on how to install the file manually. +files in the modules (`cas-client-integration-jboss` and `cas-client-support-distributed-memcached`) or follow the instructions on how to install the file manually. From 3c40922847e5e3bb43c12abf6281e6160f36b57d Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 22:50:09 +0400 Subject: [PATCH 48/57] Update README.md --- README.md | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6018115..680ef01 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,64 @@ # Java Apereo CAS Client [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas.client/cas-client-core/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas/cas-server) + + +- [Intro][intro] +- [Components][components] +- [Configurtion][configurtion] + - [Client Configuration Using `web.xml`][client-configuration-using-webxml] + - [org.jasig.cas.client.authentication.AuthenticationFilter][orgjasigcasclientauthenticationauthenticationfilter] + - [org.jasig.cas.client.authentication.Saml11AuthenticationFilter][orgjasigcasclientauthenticationsaml11authenticationfilter] + - [rg.jasig.cas.client.validation.Cas10TicketValidationFilter][rgjasigcasclientvalidationcas10ticketvalidationfilter] + - [org.jasig.cas.client.validation.Saml11TicketValidationFilter][orgjasigcasclientvalidationsaml11ticketvalidationfilter] + - [org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter][orgjasigcasclientvalidationcas20proxyreceivingticketvalidationfilter] + - [org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter][orgjasigcasclientvalidationcas30proxyreceivingticketvalidationfilter] + - [org.jasig.cas.client.util.HttpServletRequestWrapperFilter][orgjasigcasclientutilhttpservletrequestwrapperfilter] + - [org.jasig.cas.client.util.AssertionThreadLocalFilter][orgjasigcasclientutilassertionthreadlocalfilter] + - [Client Configuration Using Spring][client-configuration-using-spring] + - [Bean Configuration][bean-configuration] + - [Client Configuration Using JNDI][client-configuration-using-jndi] + - [Example][example] + - [Configuring Single Sign Out][configuring-single-sign-out] + - [Configuration][configuration] + - [CAS Protocol][cas-protocol] + - [SAML Protocol][saml-protocol] + - [Recommend Logout Procedure][recommend-logout-procedure] +- [JAAS][jaas] + - [Configure CasLoginModule][configure-casloginmodule] + - [Programmatic JAAS login using the Servlet 3][programmatic-jaas-login-using-the-servlet-3] +- [JBoss Integration][jboss-integration] + - [Configure Servlet Filters][configure-servlet-filters] +- [Tomcat 6/7 Integration][tomcat-67-integration] + - [Component Overview][component-overview] + - [Authenticators][authenticators] + - [Realms][realms] + - [Valves][valves] + - [Container Setup][container-setup] + - [Context Configuration][context-configuration] +- [Atlassian Integration][atlassian-integration] + - [Configuration][configuration-1] + - [$JIRA_HOME Location][jira_home-location] + - [$CONFLUENCE_INSTALL Description][confluence_install-description] + - [Changes to web.xml][changes-to-webxml] + - [Modify the seraph-config.xml][modify-the-seraph-configxml] + - [CAS Authenticator][cas-authenticator] + - [Confluence CAS Logout][confluence-cas-logout] + - [Copy Jars][copy-jars] +- [Spring Security Integration][spring-security-integration] + - [Changes to web.xml][changes-to-webxml-1] + - [Changes to applicationContext-security.xml][changes-to-applicationcontext-securityxml] +- [Build][build] + + + + + ## Intro This is the official home of the Java Apereo CAS client. The client consists of a collection of Servlet filters that are suitable for most Java-based web applications. It also serves as an API platform to interact with the CAS server programmatically to make authentication requests, validate tickets and consume principal attributes. All client artifacts are published to Maven central. Depending on functionality, applications will need include one or more of the listed dependencies in their configuration. + ## Components - Core functionality, which includes CAS authentication/validation filters. @@ -87,8 +141,10 @@ All client artifacts are published to Maven central. Depending on functionality, ``` + ## Configurtion + ### Client Configuration Using `web.xml` The client can be configured via `web.xml` via a series of `context-param`s and filter `init-param`s. Each filter for the client has a required (and optional) set of properties. The filters are designed to look for these properties in the following way: @@ -101,6 +157,7 @@ The client can be configured via `web.xml` via a series of `context-param`s and An example application that is protected by the client is [available here](https://github.com/UniconLabs/cas-sample-java-webapp). + #### org.jasig.cas.client.authentication.AuthenticationFilter The `AuthenticationFilter` is what detects whether a user needs to be authenticated or not. If a user needs to be authenticated, it will redirect the user to the CAS server. @@ -128,8 +185,13 @@ The `AuthenticationFilter` is what detects whether a user needs to be authentica | `gateway ` | specifies whether `gateway=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all) | No | `artifactParameterName ` | specifies the name of the request parameter on where to find the artifact (i.e. `ticket`). | No | `serviceParameterName ` | specifies the name of the request parameter on where to find the service (i.e. `service`) | No +| `encodeServiceUrl ` | Whether the client should auto encode the service url. Defaults to `true` | No +| `ignorePattern` | Defines the url pattern to ignore, when intercepting authentication requests. | No +| `ignoreUrlPatternType` | Defines the type of the pattern specified. Defaults to `REGEX`. Other types are `CONTAINS`, `EXACT`. | No +| `gatewayStorageClass` | The storage class used to record gateway requests | No +| `authenticationRedirectStrategyClass` | The class name of the component to decide how to handle authn redirects to CAS | No - + #### org.jasig.cas.client.authentication.Saml11AuthenticationFilter The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be authenticated or not. If a user needs to be authenticated, it will redirect the user to the CAS server. @@ -157,8 +219,9 @@ The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be a | `gateway ` | specifies whether `gateway=true` should be sent to the CAS server. Valid values are either `true/false` (or no value at all) | No | `artifactParameterName ` | specifies the name of the request parameter on where to find the artifact (i.e. `SAMLart`). | No | `serviceParameterName ` | specifies the name of the request parameter on where to find the service (i.e. `TARGET`) | No +| `encodeServiceUrl ` | Whether the client should auto encode the service url. Defaults to `true` | No - + ####org.jasig.cas.client.validation.Cas10TicketValidationFilter Validates tickets using the CAS 1.0 Protocol. @@ -181,8 +244,11 @@ Validates tickets using the CAS 1.0 Protocol. | `redirectAfterValidation ` | Whether to redirect to the same URL after ticket validation, but without the ticket in the parameter. Defaults to `true`. | No | `useSession ` | Whether to store the Assertion in session or not. If sessions are not used, tickets will be required for each request. Defaults to `true`. | No | `exceptionOnValidationFailure ` | Whether to throw an exception or not on ticket validation failure. Defaults to `true`. | No +| `sslConfigFile` | A reference to a properties file that includes SSL settings for client-side SSL config, used during back-channel calls. The configuration includes keys for `protocol` which defaults to `SSL`, `keyStoreType`, `keyStorePath`, `keyStorePass`, `keyManagerType` which defaults to `SunX509` and `certificatePassword`. | No. +| `encoding` | Specifies the encoding charset the client should use | No +| `hostnameVerifier` | Hostname verifier class name, used when making back-channel calls | No - + #### org.jasig.cas.client.validation.Saml11TicketValidationFilter Validates tickets using the SAML 1.1 protocol. @@ -210,8 +276,11 @@ Validates tickets using the SAML 1.1 protocol. | `useSession ` | Whether to store the Assertion in session or not. If sessions are not used, tickets will be required for each request. Defaults to `true`. | No | `exceptionOnValidationFailure ` | whether to throw an exception or not on ticket validation failure. Defaults to `true` | No | `tolerance ` | The tolerance for drifting clocks when validating SAML tickets. Note that 10 seconds should be more than enough for most environments that have NTP time synchronization. Defaults to `1000 msec` | No +| `sslConfigFile` | A reference to a properties file that includes SSL settings for client-side SSL config, used during back-channel calls. The configuration includes keys for `protocol` which defaults to `SSL`, `keyStoreType`, `keyStorePath`, `keyStorePass`, `keyManagerType` which defaults to `SunX509` and `certificatePassword`. | No. +| `encoding` | Specifies the encoding charset the client should use | No +| `hostnameVerifier` | Hostname verifier class name, used when making back-channel calls | No - + #### org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter Validates the tickets using the CAS 2.0 protocol. If you provide either the `acceptAnyProxy` or the `allowedProxyChains` parameters, a `Cas20ProxyTicketValidator` will be constructed. Otherwise a general `Cas20ServiceTicketValidator` will be constructed that does not accept proxy tickets. @@ -245,7 +314,17 @@ Validates the tickets using the CAS 2.0 protocol. If you provide either the `acc | `allowedProxyChains ` | Specifies the proxy chain. Each acceptable proxy chain should include a space-separated list of URLs. Each acceptable proxy chain should appear on its own line. | No | `proxyCallbackUrl` | The callback URL to provide the CAS server to accept Proxy Granting Tickets. | No | `proxyGrantingTicketStorageClass ` | Specify an implementation of the ProxyGrantingTicketStorage class that has a no-arg constructor. | No +| `sslConfigFile` | A reference to a properties file that includes SSL settings for client-side SSL config, used during back-channel calls. The configuration includes keys for `protocol` which defaults to `SSL`, `keyStoreType`, `keyStorePath`, `keyStorePass`, `keyManagerType` which defaults to `SunX509` and `certificatePassword`. | No. +| `encoding` | Specifies the encoding charset the client should use | No +| `secretKey` | The secret key used by the `proxyGrantingTicketStorageClass` if it supports encryption. | No +| `cipherAlgorithm` | The algorithm used by the `proxyGrantingTicketStorageClass` if it supports encryption. Defaults to `DESede` | No +| `millisBetweenCleanUps` | Startup delay for the cleanup task to remove expired tickets from the storage. Defaults to `60000 msec` | No +| `ticketValidatorClass` | Ticket validator class to use/create | No +| `hostnameVerifier` | Hostname verifier class name, used when making back-channel calls | No + +#### org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter +Validates the tickets using the CAS 3.0 protocol. If you provide either the `acceptAnyProxy` or the `allowedProxyChains` parameters, a `Cas30ProxyTicketValidator` will be constructed. Otherwise a general `Cas30ServiceTicketValidator` will be constructed that does not accept proxy tickets. Supports all configurations that are available for `Cas20ProxyReceivingTicketValidationFilter`. ##### Proxy Authentication vs. Distributed Caching The client has support for clustering and distributing the TGT state among application nodes that are behind a load balancer. In order to do so, the parameter needs to be defined as such for the filter. @@ -298,6 +377,7 @@ Configure the client: When loading from the `web.xml`, the Client relies on a series of default values, one of which being that the list of memcached servers must be defined in `/cas/casclient_memcached_hosts.txt` on the classpath). The file is a simple list of `:` on separate lines. **BE SURE NOT TO HAVE EXTRA LINE BREAKS**. + #### org.jasig.cas.client.util.HttpServletRequestWrapperFilter Wraps an `HttpServletRequest` so that the `getRemoteUser` and `getPrincipal` return the CAS related entries. @@ -308,6 +388,12 @@ Wraps an `HttpServletRequest` so that the `getRemoteUser` and `getPrincipal` ret ``` +| Property | Description | Required +|----------|-------|----------- +| `roleAttribute` | Used to determine the principal role. | No +| `ignoreCase` | Whether role checking should ignore case. Defaults to `false` | No + + #### org.jasig.cas.client.util.AssertionThreadLocalFilter Places the `Assertion` in a `ThreadLocal` for portions of the application that need access to it. This is useful when the Web application that this filter "fronts" needs to get the Principal name, but it has no access to the `HttpServletRequest`, hence making `getRemoteUser()` call impossible. @@ -318,6 +404,7 @@ Places the `Assertion` in a `ThreadLocal` for portions of the application that n ``` + ### Client Configuration Using Spring Configuration via Spring IoC will depend heavily on `DelegatingFilterProxy` class. For each filter that will be configured for CAS via Spring, a corresponding `DelegatingFilterProxy` is needed in the web.xml. @@ -339,6 +426,7 @@ As the `SingleSignOutFilter`, `HttpServletRequestWrapperFilter` and `AssertionTh ``` + #### Bean Configuration ##### AuthenticationFilter @@ -455,6 +543,7 @@ Configuration to accept Proxy Ticket from a chain (and Proxy Granting Tickets): The specific filters can be configured in the following ways. Please see the JavaDocs included in the distribution for specific required and optional properties: + ### Client Configuration Using JNDI Configuring the CAS client via JNDI is essentially the same as configuring the client via the `web.xml`, except the properties will reside in JNDI and not in the `web.xml`. @@ -464,6 +553,7 @@ We use the following conventions: 1. JNDI will first look in `java:comp/env/cas/{SHORT FILTER NAME}/{PROPERTY NAME}` (i.e. `java:comp/env/cas/AuthenticationFilter/serverName`) 2. JNDI will as a last resort look in `java:comp/env/cas/{PROPERTY NAME}` (i.e. `java:comp/env/cas/serverName`) + #### Example This is an update to the `META-INF/context.xml` that is included in Tomcat's Manager application: @@ -482,11 +572,26 @@ type="java.lang.String" value="https://www.apereo.org/cas"/> ``` + ### Configuring Single Sign Out The Single Sign Out support in CAS consists of configuring one `SingleSignOutFilter` and one `ContextListener`. Please note that if you have configured the CAS Client for Java as Web filters, this filter must come before the other filters as described. The `SingleSignOutFilter` can affect character encoding. This becomes most obvious when used in conjunction with applications such as Atlassian Confluence. Its recommended you explicitly configure either the [VT Character Encoding Filter](http://code.google.com/p/vt-middleware/wiki/vtservletfilters#CharacterEncodingFilter) or the [Spring Character Encoding Filter](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html) with explicit encodings. + +#### Configuration + +| Property | Description | Required +|----------|-------|----------- +| `artifactParameterName` | The ticket artifact parameter name. Defaults to `ticket`| No +| `logoutParameterName` | Defaults to `logoutRequest` | No +| `frontLogoutParameterName` | Defaults to `SAMLRequest` | No +| `relayStateParameterName` | Defaults to `RelayState` | No +| `eagerlyCreateSessions` | Defaults to `true` | No +| `artifactParameterOverPost` | Defaults to `false` | No +| `casServerUrlPrefix` | URL to root of CAS Web application context. | Yes + + #### CAS Protocol ```xml @@ -505,6 +610,7 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio ``` + #### SAML Protocol ```xml @@ -527,6 +633,9 @@ filter> ``` + + + #### Recommend Logout Procedure The client has no code to help you handle log out. The client merely places objects in session. Therefore, we recommend you do a `session.invalidate()` call when you log a user out. However, that's entirely your application's responsibility. We recommend that text similar to the following appear when the application's session is ended. @@ -535,11 +644,13 @@ You have been logged out of [APPLICATION NAME GOES HERE]. To log out of all applications, click here. (provide link to CAS server's logout) ``` + ## JAAS The client supports the Java Authentication and Authorization Service (JAAS) framework, which provides authnz facilities to CAS-enabled JEE applications. A general JAAS authentication module, `CasLoginModule`, is available with the specific purpose of providing authentication and authorization services to CAS-enabled JEE applications. The design of the module is simple: given a service URL and a service ticket in a `NameCallback` and `PasswordCallback`, respectively, the module contacts the CAS server and attempts to validate the ticket. In keeping with CAS integration for Java applications, a JEE container-specific servlet filter is needed to protect JEE Web applications. The JAAS support should be extensible to any JEE container. + ### Configure CasLoginModule It is expected that for JEE applications both authentication and authorization services will be required for CAS integration. The following JAAS module configuration file excerpt demonstrates how to leverage SAML 1.1 attribute release in CAS to provide authorization data in addition to authentication: @@ -573,13 +684,24 @@ cas { | `cacheTimeout` | Assertion cache timeout in minutes. | No | `tolerance` | The tolerance for drifting clocks when validating SAML tickets. | No + +### Programmatic JAAS login using the Servlet 3 +A `org.jasig.cas.client.jaas.Servlet3AuthenticationFilter` servlet filter that performs a programmatic JAAS login using the Servlet 3.0 `HttpServletRequest#login()` facility. This component should be compatible with any servlet container that supports the Servlet 3.0/JEE6 specification. + +The filter executes when it receives a CAS ticket and expects the +`CasLoginModule` JAAS module to perform the CAS ticket validation in order to produce an `AssertionPrincipal` from which the CAS assertion is obtained and inserted into the session to enable SSO. +If a `service` init-param is specified for this filter, it supersedes +the service defined for the `CasLoginModule`. + + ## JBoss Integration In keeping with CAS integration for Java applications, a JEE container-specific servlet filter is needed to protect JEE Web applications. The JBoss `WebAuthenticationFilter` component provided a convenient integration piece between a servlet filter and the JAAS framework, so a complete integration solution is available only for JBoss AS versions that provide the `WebAuthenticationFilter` class. The JAAS support should be extensible to any JEE container with additional development. For JBoss it is vitally important to use the correct values for `principalGroupName` and `roleGroupName`. Additionally, the `cacheAssertions` and `cacheTimeout` are required since JBoss by default attempts to reauthenticate the JAAS principal with a fairly aggressive default timeout. Since CAS tickets are single-use authentication tokens by default, assertion caching is required to support periodic reauthentication. + ### Configure Servlet Filters Integration with the servlet pipeline is required for a number of purposes: @@ -644,6 +766,7 @@ If you have any trouble, you can enable the log of cas in `jboss-logging.xml` by ``` + ## Tomcat 6/7 Integration The client supports container-based CAS authentication and authorization support for the Tomcat servlet container. @@ -651,9 +774,11 @@ Suppose a single Tomcat container hosts multiple Web applications with similar a CAS authentication support for Tomcat is based on the Tomcat-specific Realm component. The Realm component has a fairly broad surface area and RealmBase is provided as a convenient superclass for custom implementations; the CAS realm implementations derive from `RealmBase`. Unfortunately RealmBase and related components have proven to change over both major and minor number releases, which requires version-specific CAS components for integration. We have provided two packages with similar components with the hope of supporting all 6.x and 7.x versions. **No support for 5.x is provided.** + ### Component Overview In the following discussion of components, only the Tomcat 6.x components are mentioned. The Tomcat 7.0.x components have exactly the same name, but **are in the tomcat.v7 package**, e.g. `org.jasig.cas.client.tomcat.v7.Cas20CasAuthenticator`. + #### Authenticators Authenticators are responsible for performing CAS authentication using a particular protocol. All protocols supported by the Jasig Java CAS client are supported: CAS 1.0, CAS 2.0, and SAML 1.1. The following components provide protocol-specific support: @@ -664,6 +789,7 @@ org.jasig.cas.client.tomcat.v6.Cas20ProxyCasAuthenticator org.jasig.cas.client.tomcat.v6.Saml11Authenticator ``` + #### Realms In terms of CAS configuration, Tomcat realms serve as containers for users and role definitions. The roles defined in a Tomcat realm may be referenced in the web.xml servlet descriptor to define authorization constraints on Web applications hosted by the container. Two sources of user/role data are supported: @@ -676,6 +802,7 @@ org.jasig.cas.client.tomcat.v6.AssertionCasRealm `AssertionCasRealm` is designed to be used in conjunction with the SAML 1.1. protocol to take advantage of CAS attribute release to provide for dynamic user/role data driven by the CAS server. With this component the deployer may define a role attribute, e.g. memberOf, which could be backed by LDAP group membership information. In that case the user would be added to all roles defined in the SAML attribute assertion for values of the the `memberOf` attribute. + #### Valves A number of Tomcat valves are provided to handle functionality outside Realms and Authenticators. @@ -693,9 +820,11 @@ The `org.jasig.cas.client.tomcat.v6.SingleSignOutValve` allows the container to ##### ProxyCallbackValve The `org.jasig.cas.client.tomcat.v6.ProxyCallbackValve` provides a handler for watching request URIs for requests that contain a proxy callback request in support of the CAS 2.0 protocol proxy feature. + ### Container Setup The version-specific CAS libraries must be placed on the container classpath, `$CATALINA_HOME/lib`. + ### Context Configuration The Realm, Authenticator, and Valve components are wired together inside a Tomcat Context configuration element. The location and scope of the Context determines the scope of the applied configuration. To apply a CAS configuration to every Web application hosted in the container, configure the default Context at `$CATALINA_HOME/conf/context.xml`. Note that individual Web applications/servlets can override the default context; see the Context Container reference for more information. @@ -783,11 +912,14 @@ The following example shows how to configure a Context for dynamic role data pro ``` + ## Atlassian Integration The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators. + ### Configuration + #### $JIRA_HOME Location - WAR/EAR Installation: /webapp @@ -796,15 +928,18 @@ The clien includes Atlassian Confluence and JIRA support. Support is enabled by - Standalone: /atlassian-jira `/opt/atlassian/jira/atlassian-jira-enterprise-x.y.z-standalone/atlassian-jira` + #### $CONFLUENCE_INSTALL Description - /confluence `/opt/atlassian/confluence/confluence-x.y.z/confluence` + #### Changes to web.xml Add the CAS filters to the end of the filter list. See `web.xml` configuration of the client. + #### Modify the seraph-config.xml To rely on the Single Sign Out functionality to sign off of Jira, comment out the normal logout URL and replace it with the CAS logout URL. Also, change the login links to point to the CAS login service. @@ -845,6 +980,7 @@ To rely on the Single Sign Out functionality to sign off of Jira, comment out th ``` + #### CAS Authenticator Comment out the `DefaultAuthenticator` like so in `[$JIRA_HOME|$CONFLUENCE_INSTALL]/WEB-INF/classes/seraph-config.xml`: @@ -872,6 +1008,7 @@ For Confluence, add in the Client Confluence Authenticator: ``` + #### Confluence CAS Logout As of this writing, Atlassian doesn't support a config option yet (like Jira). To rely on the Single Sign Out functionality to sign off of Confluence we need to modify the logout link. @@ -892,12 +1029,15 @@ As of this writing, Atlassian doesn't support a config option yet (like Jira). T ``` + #### Copy Jars Copy cas-client-core-x.y.x.jar and cas-client-integration-atlassian-x.y.x.jar to `$JIRA_HOME/WEB-INF/lib` + ## Spring Security Integration This configuration tested against the sample application that is included with Spring Security. As of this writing, replacing the `applicationContext-security.xml` in the sample application with the one below would enable this alternative configuration. We can not guarantee this version will work without modification in future versions of Spring Security. + ### Changes to web.xml ```xml @@ -960,6 +1100,7 @@ This configuration tested against the sample application that is included with S The important additions to the `web.xml` include the addition of the 403 error page. 403 is what the CAS Validation Filter will throw if it has a problem with the ticket. Also, if you want Single Log Out, you should enable the `SingleSignOutHttpSessionListener`. + ### Changes to applicationContext-security.xml ```xml @@ -1068,10 +1209,11 @@ The important additions to the `web.xml` include the addition of the 403 error p ... ``` -1. You should replace the userService with something that checks your user storage. +1. You should replace the `userService` with something that checks your user storage. 2. Replace the `serverName` and `casServerLoginUrl` with your values (or better yet, externalize them). 3. Replace the URLs with the URL configuration for your application. + ## Build ```bash From 50fc28034df7326369c83b7e699cf0b003b13d3d Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 22:50:52 +0400 Subject: [PATCH 49/57] Update README.md --- README.md | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/README.md b/README.md index 680ef01..dab9c52 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,5 @@ # Java Apereo CAS Client [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas.client/cas-client-core/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.jasig.cas/cas-server) - - -- [Intro][intro] -- [Components][components] -- [Configurtion][configurtion] - - [Client Configuration Using `web.xml`][client-configuration-using-webxml] - - [org.jasig.cas.client.authentication.AuthenticationFilter][orgjasigcasclientauthenticationauthenticationfilter] - - [org.jasig.cas.client.authentication.Saml11AuthenticationFilter][orgjasigcasclientauthenticationsaml11authenticationfilter] - - [rg.jasig.cas.client.validation.Cas10TicketValidationFilter][rgjasigcasclientvalidationcas10ticketvalidationfilter] - - [org.jasig.cas.client.validation.Saml11TicketValidationFilter][orgjasigcasclientvalidationsaml11ticketvalidationfilter] - - [org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter][orgjasigcasclientvalidationcas20proxyreceivingticketvalidationfilter] - - [org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter][orgjasigcasclientvalidationcas30proxyreceivingticketvalidationfilter] - - [org.jasig.cas.client.util.HttpServletRequestWrapperFilter][orgjasigcasclientutilhttpservletrequestwrapperfilter] - - [org.jasig.cas.client.util.AssertionThreadLocalFilter][orgjasigcasclientutilassertionthreadlocalfilter] - - [Client Configuration Using Spring][client-configuration-using-spring] - - [Bean Configuration][bean-configuration] - - [Client Configuration Using JNDI][client-configuration-using-jndi] - - [Example][example] - - [Configuring Single Sign Out][configuring-single-sign-out] - - [Configuration][configuration] - - [CAS Protocol][cas-protocol] - - [SAML Protocol][saml-protocol] - - [Recommend Logout Procedure][recommend-logout-procedure] -- [JAAS][jaas] - - [Configure CasLoginModule][configure-casloginmodule] - - [Programmatic JAAS login using the Servlet 3][programmatic-jaas-login-using-the-servlet-3] -- [JBoss Integration][jboss-integration] - - [Configure Servlet Filters][configure-servlet-filters] -- [Tomcat 6/7 Integration][tomcat-67-integration] - - [Component Overview][component-overview] - - [Authenticators][authenticators] - - [Realms][realms] - - [Valves][valves] - - [Container Setup][container-setup] - - [Context Configuration][context-configuration] -- [Atlassian Integration][atlassian-integration] - - [Configuration][configuration-1] - - [$JIRA_HOME Location][jira_home-location] - - [$CONFLUENCE_INSTALL Description][confluence_install-description] - - [Changes to web.xml][changes-to-webxml] - - [Modify the seraph-config.xml][modify-the-seraph-configxml] - - [CAS Authenticator][cas-authenticator] - - [Confluence CAS Logout][confluence-cas-logout] - - [Copy Jars][copy-jars] -- [Spring Security Integration][spring-security-integration] - - [Changes to web.xml][changes-to-webxml-1] - - [Changes to applicationContext-security.xml][changes-to-applicationcontext-securityxml] -- [Build][build] - - - - ## Intro This is the official home of the Java Apereo CAS client. The client consists of a collection of Servlet filters that are suitable for most Java-based web applications. It also serves as an API platform to interact with the CAS server programmatically to make authentication requests, validate tickets and consume principal attributes. From dc028a6652daba7b88d74434e63efdc84f52ca7d Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 23:08:50 +0400 Subject: [PATCH 50/57] Update README.md --- README.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dab9c52..3983941 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,35 @@ All client artifacts are published to Maven central. Depending on functionality, ## Configurtion +### Strategies +The client provide multiple strategies/options for the deployer to provide options and settings. The following strategies are supported: + +- JNDI (`JNDI`) +- Properties File (`PROPERTY_FILE`). The configuration is provided via an external properties file. The path may be specified in the web context as such: + +```xml + + configFileLocation + /etc/cas/file.properties + +``` +If no location is specified, by default `/etc/java-cas-client.properties` will be used. + +- System Properties (`SYSTEM_PROPERTIES`) +- Web Context (`WEB_XML`) +- Default (`DEFAULT`) + +In order to instruct the client to pick a strategy, strategy name must be specified in the web application's context: + +```xml + + configurationStrategy + DEFAULT + +``` + +If no `configurationStrategy` is defined, `DEFAULT` is used which is a combination of `WEB_XML` and `JNDI`. + ### Client Configuration Using `web.xml` @@ -270,7 +299,6 @@ Validates the tickets using the CAS 2.0 protocol. If you provide either the `acc | `ticketValidatorClass` | Ticket validator class to use/create | No | `hostnameVerifier` | Hostname verifier class name, used when making back-channel calls | No - #### org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter Validates the tickets using the CAS 3.0 protocol. If you provide either the `acceptAnyProxy` or the `allowedProxyChains` parameters, a `Cas30ProxyTicketValidator` will be constructed. Otherwise a general `Cas30ServiceTicketValidator` will be constructed that does not accept proxy tickets. Supports all configurations that are available for `Cas20ProxyReceivingTicketValidationFilter`. @@ -526,7 +554,6 @@ The Single Sign Out support in CAS consists of configuring one `SingleSignOutFil The `SingleSignOutFilter` can affect character encoding. This becomes most obvious when used in conjunction with applications such as Atlassian Confluence. Its recommended you explicitly configure either the [VT Character Encoding Filter](http://code.google.com/p/vt-middleware/wiki/vtservletfilters#CharacterEncodingFilter) or the [Spring Character Encoding Filter](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html) with explicit encodings. - #### Configuration | Property | Description | Required @@ -632,7 +659,6 @@ cas { | `cacheTimeout` | Assertion cache timeout in minutes. | No | `tolerance` | The tolerance for drifting clocks when validating SAML tickets. | No - ### Programmatic JAAS login using the Servlet 3 A `org.jasig.cas.client.jaas.Servlet3AuthenticationFilter` servlet filter that performs a programmatic JAAS login using the Servlet 3.0 `HttpServletRequest#login()` facility. This component should be compatible with any servlet container that supports the Servlet 3.0/JEE6 specification. @@ -864,7 +890,7 @@ The following example shows how to configure a Context for dynamic role data pro ## Atlassian Integration The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators. - + ### Configuration From 573976cda9674d87245debae98af930ac2e89646 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 23 May 2015 23:09:30 +0400 Subject: [PATCH 51/57] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3983941..b99a844 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ All client artifacts are published to Maven central. Depending on functionality, ``` -## Configurtion +## Configuration ### Strategies The client provide multiple strategies/options for the deployer to provide options and settings. The following strategies are supported: From 77e5340c3cbb4a3ddb1736d5fef7d2ae07159a0e Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 24 May 2015 18:59:20 +0400 Subject: [PATCH 52/57] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b99a844..d21ecef 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ All client artifacts are published to Maven central. Depending on functionality, ## Configuration ### Strategies -The client provide multiple strategies/options for the deployer to provide options and settings. The following strategies are supported: +The client provides multiple strategies for the deployer to provide client settings. The following strategies are supported: - JNDI (`JNDI`) - Properties File (`PROPERTY_FILE`). The configuration is provided via an external properties file. The path may be specified in the web context as such: @@ -124,7 +124,7 @@ If no `configurationStrategy` is defined, `DEFAULT` is used which is a combinati ### Client Configuration Using `web.xml` -The client can be configured via `web.xml` via a series of `context-param`s and filter `init-param`s. Each filter for the client has a required (and optional) set of properties. The filters are designed to look for these properties in the following way: +The client can be configured in `web.xml` via a series of `context-param`s and filter `init-param`s. Each filter for the client has a required (and optional) set of properties. The filters are designed to look for these properties in the following way: - Check the filter's local `init-param`s for a parameter matching the required property name. - Check the `context-param`s for a parameter matching the required property name. From c6c106c3758f51e9f06848018c54617eb74aea96 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 7 Jun 2015 13:18:19 -0700 Subject: [PATCH 53/57] deprecated unused const --- .../jasig/cas/client/configuration/ConfigurationKeys.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java index 9418151..14ec120 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -54,6 +54,12 @@ public interface ConfigurationKeys { ConfigurationKey CAS_SERVER_URL_PREFIX = new ConfigurationKey("casServerUrlPrefix", null); ConfigurationKey ENCODING = new ConfigurationKey("encoding", null); ConfigurationKey TOLERANCE = new ConfigurationKey("tolerance", 1000L); + + /** + * @deprecated As of 3.4. This constant is not used by the client and will + * be removed in future versions. + */ + @Deprecated ConfigurationKey DISABLE_XML_SCHEMA_VALIDATION = new ConfigurationKey("disableXmlSchemaValidation", Boolean.FALSE); ConfigurationKey IGNORE_PATTERN = new ConfigurationKey("ignorePattern", null); ConfigurationKey IGNORE_URL_PATTERN_TYPE = new ConfigurationKey("ignoreUrlPatternType", "REGEX"); From f1ac21943d73a9b5a9886064661d14eba14460dd Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 7 Jun 2015 13:24:12 -0700 Subject: [PATCH 54/57] upgrade to commons-lang3 v3.4 --- cas-client-core/pom.xml | 6 +++--- .../cas/client/configuration/BaseConfigurationStrategy.java | 4 ++-- .../org/jasig/cas/client/session/SingleSignOutHandler.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index e8d0a31..8e6420b 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -29,9 +29,9 @@ - commons-lang - commons-lang - 2.6 + org.apache.commons + commons-lang3 + 3.4 diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java index 79872c5..dbf4e89 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/BaseConfigurationStrategy.java @@ -18,8 +18,8 @@ */ package org.jasig.cas.client.configuration; -import org.apache.commons.lang.BooleanUtils; -import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.ReflectUtils; import org.slf4j.Logger; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index 162c7b9..4efc018 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.jasig.cas.client.Protocol; import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.CommonUtils; From 8bc89e648a7852a1775a20f8f7f17a9c7c1e75ac Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 7 Jun 2015 13:27:32 -0700 Subject: [PATCH 55/57] Create .travis.yml --- .travis.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7ac7e80 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +before_install: +- mvn -v +- java -version +script: mvn install +language: java From 05873137dccf11febe911dd5f39161510fae37f2 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 7 Jun 2015 13:29:05 -0700 Subject: [PATCH 56/57] Update README.md --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d21ecef..8399606 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,19 @@ This is the official home of the Java Apereo CAS client. The client consists of All client artifacts are published to Maven central. Depending on functionality, applications will need include one or more of the listed dependencies in their configuration. + +## Build [![Build Status](https://travis-ci.org/Jasig/java-cas-client.png?branch=master)](https://travis-ci.org/Jasig/java-cas-client) + +```bash +git clone git@github.com:Jasig/java-cas-client.git +cd java-cas-client +mvn clean package +``` + +Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache +Clients). In order to build the clients, you must enable the commented out repositories in the appropriate `pom.xml` +files in the modules (`cas-client-integration-jboss` and `cas-client-support-distributed-memcached`) or follow the instructions on how to install the file manually. + ## Components @@ -1186,16 +1199,3 @@ The important additions to the `web.xml` include the addition of the 403 error p 1. You should replace the `userService` with something that checks your user storage. 2. Replace the `serverName` and `casServerLoginUrl` with your values (or better yet, externalize them). 3. Replace the URLs with the URL configuration for your application. - - -## Build - -```bash -git clone git@github.com:Jasig/java-cas-client.git -cd java-cas-client -mvn clean package -``` - -Please note that to be deployed in Maven Central, we mark a number of JARs as provided (related to JBoss and Memcache -Clients). In order to build the clients, you must enable the commented out repositories in the appropriate `pom.xml` -files in the modules (`cas-client-integration-jboss` and `cas-client-support-distributed-memcached`) or follow the instructions on how to install the file manually. From 853450a8a6ef47bd4163d450002e540003d4bfab Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 7 Jun 2015 17:05:47 -0700 Subject: [PATCH 57/57] added additional logs to proxy validation --- .../validation/Cas20ProxyTicketValidator.java | 21 ++++++++++++++++++- .../validation/Cas30ProxyTicketValidator.java | 2 +- .../cas/client/validation/ProxyList.java | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java index 592c330..c97cf21 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidator.java @@ -18,6 +18,7 @@ */ package org.jasig.cas.client.validation; +import java.util.Arrays; import java.util.List; import org.jasig.cas.client.util.XmlUtils; @@ -53,8 +54,22 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator { throws TicketValidationException { final List proxies = XmlUtils.getTextForElements(response, "proxy"); + if (proxies == null) { + throw new InvalidProxyChainTicketValidationException( + "Invalid proxy chain: No proxy could be retrieved from response. " + + "This indicates a problem with CAS validation. Review logs/configuration to find the root cause." + ); + } // this means there was nothing in the proxy chain, which is okay - if ((this.allowEmptyProxyChain && proxies.isEmpty()) || this.acceptAnyProxy) { + if ((this.allowEmptyProxyChain && proxies.isEmpty())) { + logger.debug("Found an empty proxy chain, permitted by client configuration"); + return; + } + + if (this.acceptAnyProxy) { + logger.debug("Client configuration accepts any proxy. " + + "It is generally dangerous to use a non-proxied CAS filter " + + "specially for protecting resources that require proxy access."); return; } @@ -63,6 +78,10 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator { return; } + logger.warn("Proxies received from the CAS validation response are {}. " + + "However, none are allowed by allowed proxy chain of the client which is {}", + Arrays.toString(proxiedList), this.allowedProxyChains); + throw new InvalidProxyChainTicketValidationException("Invalid proxy chain: " + proxies.toString()); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java index 2cdb641..6dfffc8 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas30ProxyTicketValidator.java @@ -26,7 +26,7 @@ package org.jasig.cas.client.validation; */ public class Cas30ProxyTicketValidator extends Cas20ProxyTicketValidator { - public Cas30ProxyTicketValidator(String casServerUrlPrefix) { + public Cas30ProxyTicketValidator(final String casServerUrlPrefix) { super(casServerUrlPrefix); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java index 3585d5b..35642d3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java @@ -43,7 +43,7 @@ public final class ProxyList { this(new ArrayList()); } - public boolean contains(String[] proxiedList) { + public boolean contains(final String[] proxiedList) { for (final String[] list : this.proxyChains) { if (Arrays.equals(proxiedList, list)) { return true;