From 69bba0c21a057a1af0579e00fd340d0898e2aa05 Mon Sep 17 00:00:00 2001 From: Xu Huisheng Date: Tue, 4 Aug 2015 18:20:31 +0800 Subject: [PATCH 01/43] When serverName contains schema, the URIBuilder will throw an UnsupportedOperationException while adding a parameter. --- .../java/org/jasig/cas/client/util/URIBuilder.java | 2 +- .../jasig/cas/client/util/CommonUtilsTests.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java index ef0db52..f57499d 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java @@ -126,7 +126,7 @@ public final class URIBuilder { } catch (final UnsupportedEncodingException e) { LOGGER.error(e.getMessage(), e); } - return Collections.emptyList(); + return new ArrayList(); } /** 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 aaac4e6..8ec0541 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 @@ -152,6 +152,20 @@ public final class CommonUtilsTests extends TestCase { assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl); } + public void testConstructServiceUrlWithParamsCasAndServerNameWithSchema() { + final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/"; + final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/"); + request.setScheme("https"); + request.setSecure(true); + request.setQueryString("service=this&ticket=that&custom=custom"); + + final MockHttpServletResponse response = new MockHttpServletResponse(); + final String constructedUrl = CommonUtils.constructServiceUrl(request, response, null, "https://www.myserver.com", + Protocol.CAS3.getServiceParameterName(), Protocol.CAS3.getArtifactParameterName() , false); + + assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl); + } + public void testConstructServiceUrlWithParamsSaml() { final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/"; From 618a99a24517b33da7b7f03bceb4ca0ef35b3270 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 12 Aug 2015 12:36:50 -0700 Subject: [PATCH 02/43] URIBuilder test cases --- .../org/jasig/cas/client/util/URIBuilder.java | 63 +++- .../cas/client/util/URIBuilderTests.java | 316 ++++++++++++++++++ 2 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java index f57499d..7a6874a 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/URIBuilder.java @@ -238,8 +238,9 @@ public final class URIBuilder { return this.encode ? CommonUtils.urlEncode(fragment) : fragment; } - public void setEncode(boolean encode) { + public URIBuilder setEncode(boolean encode) { this.encode = encode; + return this; } /** @@ -469,6 +470,18 @@ public final class URIBuilder { return this; } + public URIBuilder setEncodedFragment(final String fragment) { + this.fragment = null; + this.encodedFragment = fragment; + return this; + } + + public URIBuilder setEncodedQuery(final String query) { + this.query = null; + this.encodedFragment = query; + return this; + } + public boolean isAbsolute() { return this.scheme != null; } @@ -531,6 +544,54 @@ public final class URIBuilder { return s; } + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final URIBuilder that = (URIBuilder) o; + + if (port != that.port) return false; + if (encode != that.encode) return false; + if (scheme != null ? !scheme.equals(that.scheme) : that.scheme != null) return false; + if (encodedSchemeSpecificPart != null ? !encodedSchemeSpecificPart.equals(that.encodedSchemeSpecificPart) : that.encodedSchemeSpecificPart != null) + return false; + if (encodedAuthority != null ? !encodedAuthority.equals(that.encodedAuthority) : that.encodedAuthority != null) + return false; + if (userInfo != null ? !userInfo.equals(that.userInfo) : that.userInfo != null) return false; + if (encodedUserInfo != null ? !encodedUserInfo.equals(that.encodedUserInfo) : that.encodedUserInfo != null) + return false; + if (host != null ? !host.equals(that.host) : that.host != null) return false; + if (path != null ? !path.equals(that.path) : that.path != null) return false; + if (encodedPath != null ? !encodedPath.equals(that.encodedPath) : that.encodedPath != null) return false; + if (encodedQuery != null ? !encodedQuery.equals(that.encodedQuery) : that.encodedQuery != null) return false; + if (queryParams != null ? !queryParams.equals(that.queryParams) : that.queryParams != null) return false; + if (query != null ? !query.equals(that.query) : that.query != null) return false; + if (fragment != null ? !fragment.equals(that.fragment) : that.fragment != null) return false; + return !(encodedFragment != null ? !encodedFragment.equals(that.encodedFragment) : that.encodedFragment != null); + + } + + @Override + public int hashCode() { + int result = scheme != null ? scheme.hashCode() : 0; + result = 31 * result + (encodedSchemeSpecificPart != null ? encodedSchemeSpecificPart.hashCode() : 0); + result = 31 * result + (encodedAuthority != null ? encodedAuthority.hashCode() : 0); + result = 31 * result + (userInfo != null ? userInfo.hashCode() : 0); + result = 31 * result + (encodedUserInfo != null ? encodedUserInfo.hashCode() : 0); + result = 31 * result + (host != null ? host.hashCode() : 0); + result = 31 * result + port; + result = 31 * result + (path != null ? path.hashCode() : 0); + result = 31 * result + (encodedPath != null ? encodedPath.hashCode() : 0); + result = 31 * result + (encodedQuery != null ? encodedQuery.hashCode() : 0); + result = 31 * result + (queryParams != null ? queryParams.hashCode() : 0); + result = 31 * result + (query != null ? query.hashCode() : 0); + result = 31 * result + (encode ? 1 : 0); + result = 31 * result + (fragment != null ? fragment.hashCode() : 0); + result = 31 * result + (encodedFragment != null ? encodedFragment.hashCode() : 0); + return result; + } + public static class BasicNameValuePair implements Cloneable, Serializable { private static final long serialVersionUID = -6437800749411518984L; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java new file mode 100644 index 0000000..5144d13 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java @@ -0,0 +1,316 @@ +/* + + * 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.Test; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author Misagh Moayyed + */ +public class URIBuilderTests { + + @Test + public void allPartsUsed() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString()); + } + + @Test + public void noSchemeUsed() { + URIBuilder builder = new URIBuilder() + .setHost("apache.org") + .setPath("/shindig") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("//apache.org/shindig?hello=world#foo", builder.toString()); + } + + @Test + public void noAuthorityUsed() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setPath("/shindig") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("http:/shindig?hello=world#foo", builder.toString()); + } + + @Test + public void noPathUsed() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("http://apache.org?hello=world#foo", builder.toString()); + } + + @Test + public void noQueryUsed() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setFragment("foo"); + assertEquals("http://apache.org/shindig#foo", builder.toString()); + } + + @Test + public void noFragmentUsed() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setCustomQuery("hello=world"); + assertEquals("http://apache.org/shindig?hello=world", builder.toString()); + } + + @Test + public void hostRelativePaths() { + URIBuilder builder = new URIBuilder() + .setPath("/shindig") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("/shindig?hello=world#foo", builder.toString()); + } + + @Test + public void relativePaths() { + URIBuilder builder = new URIBuilder() + .setPath("foo") + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("foo?hello=world#foo", builder.toString()); + } + + @Test + public void noPathNoHostNoAuthority() { + URIBuilder builder = new URIBuilder() + .setCustomQuery("hello=world") + .setFragment("foo"); + assertEquals("?hello=world#foo", builder.toString()); + } + + @Test + public void justSchemeAndAuthority() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org"); + assertEquals("http://apache.org", builder.toString()); + } + + @Test + public void justPath() { + URIBuilder builder = new URIBuilder() + .setPath("/shindig"); + assertEquals("/shindig", builder.toString()); + } + + @Test + public void justAuthorityAndPath() { + URIBuilder builder = new URIBuilder() + .setHost("apache.org") + .setPath("/shindig"); + assertEquals("//apache.org/shindig", builder.toString()); + } + + @Test + public void justQuery() { + URIBuilder builder = new URIBuilder() + .setCustomQuery("hello=world"); + assertEquals("?hello=world", builder.toString()); + } + + @Test + public void justFragment() { + URIBuilder builder = new URIBuilder() + .setFragment("foo"); + assertEquals("#foo", builder.toString()); + } + + @Test + public void addSingleQueryParameter() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .addParameter("hello", "world") + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString()); + } + + @Test + public void addTwoQueryParameters() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .addParameter("hello", "world") + .addParameter("foo", "bar") + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello=world&foo=bar#foo", builder.toString()); + } + + @Test + public void iterableQueryParameters() { + List list = new ArrayList(); + list.add(new URIBuilder.BasicNameValuePair("hello", "world")); + list.add(new URIBuilder.BasicNameValuePair("hello", "monde")); + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .addParameters(list) + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello=world&hello=monde#foo", builder.toString()); + } + + @Test + public void removeQueryParameter() { + URIBuilder uri = new URIBuilder("http://www.example.com/foo?bar=baz&quux=baz"); + uri.removeQuery(); + assertEquals("http://www.example.com/foo", uri.toString()); + } + + @Test + public void addIdenticalParameters() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .addParameter("hello", "world") + .addParameter("hello", "goodbye") + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello=world&hello=goodbye#foo", builder.toString()); + } + + @Test + public void queryStringIsUnescaped() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setCustomQuery("hello+world=world%26bar"); + assertEquals("world&bar", builder.build().getQuery().split("=")[1]); + } + + @Test + public void queryParamsAreEscaped() { + URIBuilder builder = new URIBuilder(true) + .setScheme("http") + .setHost("apache.org") + .setEncodedPath("/shindig") + .addParameter("hello world", "foo&bar") + .setFragment("foo"); + assertEquals("http://apache.org/shindig?hello+world=foo%26bar#foo", builder.toString()); + assertEquals("hello+world=foo&bar", builder.build().getQuery()); + } + + @Test + public void addSingleFragmentParameter() { + URIBuilder builder = new URIBuilder() + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setFragment("hello=world") + .setCustomQuery("foo"); + assertEquals("http://apache.org/shindig?foo#hello=world", builder.toString()); + } + + @Test + public void fragmentStringIsUnescaped() { + URIBuilder builder = new URIBuilder(true) + .setScheme("http") + .setHost("apache.org") + .setPath("/shindig") + .setEncodedFragment("hello+world=world%26bar"); + + assertEquals("world&bar", builder.build().getFragment().split("=")[1]); + } + + @Test + public void parse() { + URIBuilder builder = new URIBuilder() + .digestURI(URI.create("http://apache.org/shindig?foo=bar%26baz&foo=three#blah")); + + assertEquals("http", builder.getScheme()); + assertEquals("apache.org", builder.getHost()); + assertEquals("/shindig", builder.getPath()); + + List list = builder.getQueryParams(); + for (URIBuilder.BasicNameValuePair pair : list) { + assertEquals(pair.getName(), "foo"); + assertTrue(pair.getValue().equals("three") || pair.getValue().equals("bar")); + } + assertEquals(list.size(), 2); + assertEquals("blah", builder.getFragment()); + } + + @Test + public void constructFromUriAndBack() { + URI uri = URI.create("http://apache.org/foo/bar?foo=bar&a=b&c=d&y=z&foo=zoo#foo"); + URIBuilder builder = new URIBuilder(uri); + + assertEquals(uri, builder.build()); + } + + @Test + public void constructFromUriAndModify() { + URI uri = URI.create("http://apache.org/foo/bar?foo=bar#foo"); + URIBuilder builder = new URIBuilder(uri); + + builder.setHost("example.org"); + builder.addParameter("bar", "foo"); + + assertEquals("http://example.org/foo/bar?foo=bar&bar=foo#foo", builder.toString()); + } + + @Test + public void equalsAndHashCodeOk() { + URIBuilder uri = new URIBuilder().digestURI(URI.create("http://example.org/foo/bar/baz?blah=blah#boo")); + URIBuilder uri2 = new URIBuilder(URI.create("http://example.org/foo/bar/baz?blah=blah#boo")); + + assertEquals(uri, uri2); + assertEquals(uri2, uri); + + assertEquals(uri, uri); + + assertNotNull(uri); + assertNotSame(uri, "http://example.org/foo/bar/baz?blah=blah#boo"); + assertNotSame(uri, URI.create("http://example.org/foo/bar/baz?blah=blah#boo")); + assertEquals(uri.hashCode(), uri2.hashCode()); + } + + +} From 335d3f3a3eafcb9d3a952713d32e3a8d48686218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LELEU=20J=C3=A9r=C3=B4me?= Date: Thu, 13 Aug 2015 11:36:24 +0200 Subject: [PATCH 03/43] Update .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8357e8e..e5c3fda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,6 @@ before_install: language: java -sudo: false - script: "mvn install --settings travis/settings.xml" jdk: From d7538dfd61de061842c19b396c69963f2eb64ae2 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 13 Aug 2015 02:59:36 -0700 Subject: [PATCH 04/43] Update .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8357e8e..fda4494 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,7 @@ before_install: - mvn -v - java -version - language: java - sudo: false script: "mvn install --settings travis/settings.xml" From 4f746b3b580703f6b6df483bbc23e8101ce1cbba Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 13 Aug 2015 03:00:26 -0700 Subject: [PATCH 05/43] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fda4494..e5c3fda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ before_install: - mvn -v - java -version + language: java -sudo: false script: "mvn install --settings travis/settings.xml" From 1f3a745ec8ed995e46688cb066d38a2737c22b1f Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 19 Aug 2015 02:28:20 -0700 Subject: [PATCH 06/43] overload constructServiceUrl to keep backward compatibility --- .../jasig/cas/client/util/CommonUtils.java | 45 +++++++++++++++++-- .../cas/client/util/CommonUtilsTests.java | 14 ++++++ 2 files changed, 55 insertions(+), 4 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 a95fb9a..d8881e3 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 @@ -26,6 +26,8 @@ import java.net.URLEncoder; import java.util.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import org.jasig.cas.client.Protocol; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; @@ -259,6 +261,38 @@ public final class CommonUtils { return serverPort == 80 || serverPort == 443; } + /** + * Constructs a service url from the HttpServletRequest or from the given + * serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a + * serviceName. Compiles a list of all service parameters for supported protocols + * and removes them all from the query string. + * + * @param request the HttpServletRequest + * @param response the HttpServletResponse + * @param service the configured service url (this will be used if not null) + * @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value. + * As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public + * method. + * @param artifactParameterName the artifact parameter name to remove (i.e. ticket) + * @param encode whether to encode the url or not (i.e. Jsession). + * @return the service url to use. + */ + @Deprecated + public static String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response, + final String service, final String serverNames, + final String artifactParameterName, final boolean encode) { + final Set serviceParameterSet = new HashSet(4); + for (final Protocol protocol : Protocol.values()) { + serviceParameterSet.add(protocol.getServiceParameterName()); + } + final String serviceParameterNames = serviceParameterSet.toString() + .replaceAll("\\[|\\]", "") + .replaceAll("\\s", ""); + + return constructServiceUrl(request, response, service, serverNames, serviceParameterNames + , artifactParameterName, encode); + } + /** * Constructs a service url from the HttpServletRequest or from the given * serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a @@ -267,7 +301,7 @@ public final class CommonUtils { * @param request the HttpServletRequest * @param response the HttpServletResponse * @param service the configured service url (this will be used if not null) - * @param serverNames the server name to use to constuct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value. + * @param serverNames the server name to use to construct the service url if the service param is empty. Note, prior to CAS Client 3.3, this was a single value. * As of 3.3, it can be a space-separated value. We keep it as a single value, but will convert it to an array internally to get the matching value. This keeps backward compatability with anything using this public * method. * @param serviceParameterName the service parameter name to remove (i.e. service) @@ -305,9 +339,12 @@ public final class CommonUtils { builder.setEncodedPath(request.getRequestURI()); - for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) { - if (!pair.getName().equals(artifactParameterName) && !pair.getName().equals(serviceParameterName)) { - builder.addParameter(pair.getName(), pair.getValue()); + final List serviceParameterNames = Arrays.asList(serviceParameterName.split(",")); + if (!serviceParameterNames.isEmpty() && !originalRequestUrl.getQueryParams().isEmpty()) { + for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) { + if (!pair.getName().equals(artifactParameterName) && !serviceParameterNames.contains(pair.getName())) { + builder.addParameter(pair.getName(), pair.getValue()); + } } } 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 8ec0541..b2a9d13 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 @@ -195,6 +195,20 @@ public final class CommonUtilsTests extends TestCase { assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl); } + public void testConstructServiceUrlWithNoServiceParametersPassed() { + final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/"; + final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/"); + request.setScheme("https"); + request.setSecure(true); + request.setQueryString("TARGET=Test1&service=Test2&custom=custom"); + + final MockHttpServletResponse response = new MockHttpServletResponse(); + final String constructedUrl = CommonUtils.constructServiceUrl(request, response, null, "www.myserver.com", + Protocol.SAML11.getArtifactParameterName() , true); + + assertEquals("https://www.myserver.com/hello/hithere/?custom=custom", constructedUrl); + } + public void testConstructServiceUrlWithEncodedParams2Saml() { final String CONST_MY_URL = "https://www.myserver.com/hello/hithere/"; final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hello/hithere/"); From ab105cdcfaf19407778301d2193dada1ac647399 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 19 Aug 2015 08:51:28 -0700 Subject: [PATCH 07/43] initialize service parameter names once, statically --- .../jasig/cas/client/util/CommonUtils.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 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 d8881e3..639b3b4 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 @@ -59,10 +59,21 @@ public final class CommonUtils { private static final HttpURLConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new HttpsURLConnectionFactory(); + private static final String SERVICE_PARAMETER_NAMES; + private CommonUtils() { // nothing to do } + static { + final Set serviceParameterSet = new HashSet(4); + for (final Protocol protocol : Protocol.values()) { + serviceParameterSet.add(protocol.getServiceParameterName()); + } + SERVICE_PARAMETER_NAMES = serviceParameterSet.toString() + .replaceAll("\\[|\\]", "") + .replaceAll("\\s", ""); + } /** * Check whether the object is null or not. If it is, throw an exception and * display the message. @@ -281,15 +292,7 @@ public final class CommonUtils { public static String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response, final String service, final String serverNames, final String artifactParameterName, final boolean encode) { - final Set serviceParameterSet = new HashSet(4); - for (final Protocol protocol : Protocol.values()) { - serviceParameterSet.add(protocol.getServiceParameterName()); - } - final String serviceParameterNames = serviceParameterSet.toString() - .replaceAll("\\[|\\]", "") - .replaceAll("\\s", ""); - - return constructServiceUrl(request, response, service, serverNames, serviceParameterNames + return constructServiceUrl(request, response, service, serverNames, SERVICE_PARAMETER_NAMES , artifactParameterName, encode); } From 2eb132c0b47ff9d97131701bf3cfbe6ddca75eb3 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 9 Sep 2015 23:30:53 -0400 Subject: [PATCH 08/43] Issue #131 - ConfigurationStrategyName does not Properly Resolve Custom classes Problem: The assignable check was reversed, always resulting in a false return value. Solution: Add test to confirm failure and then swap check. Unit tests pass. --- .../ConfigurationStrategyName.java | 2 +- .../ConfigurationStrategyNameTests.java | 21 +++++++++++++++++++ 2 files changed, 22 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 2d3146f..b298d99 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 @@ -62,7 +62,7 @@ public enum ConfigurationStrategyName { try { final Class clazz = Class.forName(value); - if (clazz.isAssignableFrom(ConfigurationStrategy.class)) { + if (ConfigurationStrategy.class.isAssignableFrom(clazz)) { return (Class) clazz; } } catch (final ClassNotFoundException e) { 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 5c2da1e..449ace5 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 @@ -20,6 +20,9 @@ package org.jasig.cas.client.configuration; import org.junit.Test; +import javax.servlet.Filter; +import javax.servlet.FilterConfig; + import static org.junit.Assert.*; public final class ConfigurationStrategyNameTests { @@ -33,4 +36,22 @@ public final class ConfigurationStrategyNameTests { assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy(ConfigurationStrategyName.DEFAULT.name())); assertEquals(LegacyConfigurationStrategyImpl.class, ConfigurationStrategyName.resolveToConfigurationStrategy("bleh!")); } + + + @Test + public void resolveToClass() { + assertEquals(TestClass.class, ConfigurationStrategyName.resolveToConfigurationStrategy(TestClass.class.getName())); + } + + private class TestClass extends BaseConfigurationStrategy { + + @Override + protected String get(ConfigurationKey configurationKey) { + return null; + } + + public void init(FilterConfig filterConfig, Class filterClazz) { + + } + } } From 80677142567bde5a8c34b5bf9d4e8221f6842cbd Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Sep 2015 00:11:09 -0400 Subject: [PATCH 09/43] Added missing license headers. --- .../cas/client/util/URIBuilderTests.java | 18 +++++++++++++++++ travis/deploy-to-sonatype.sh | 19 ++++++++++++++++++ travis/settings.xml | 20 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java index 5144d13..e41ca27 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/URIBuilderTests.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. + */ /* * Licensed to Jasig under one or more contributor license diff --git a/travis/deploy-to-sonatype.sh b/travis/deploy-to-sonatype.sh index 80f2154..63b409e 100644 --- a/travis/deploy-to-sonatype.sh +++ b/travis/deploy-to-sonatype.sh @@ -1,4 +1,23 @@ #!/bin/bash +# +# 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. +# + # Only invoke the deployment to Sonatype when it's not a PR and only for master if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then diff --git a/travis/settings.xml b/travis/settings.xml index de99f77..32a6804 100644 --- a/travis/settings.xml +++ b/travis/settings.xml @@ -1,3 +1,23 @@ + org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 53b1f15..0a36f5c 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index c0113c2..62561d5 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.2-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 4a688a8..337ca4f 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.4.1-SNAPSHOT + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index ce874f2..15e34df 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.4.1-SNAPSHOT + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 7399f8c..ea870cb 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.4.1-SNAPSHOT + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index b8e6db1..b50bc69 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.4.1-SNAPSHOT + 3.4.2-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 fcabc69..bdd7986 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.4.1-SNAPSHOT + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index 26aef5b..ce40fd9 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/pom.xml b/pom.xml index ac95973..964d669 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.2-SNAPSHOT cas-client pom From e5f933754b7eb66c2c1ffbbc371874ad424e90c2 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Sep 2015 00:18:34 -0400 Subject: [PATCH 11/43] [maven-release-plugin] rollback the release of cas-client-3.4.1 --- 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 +- cas-client-support-saml/pom.xml | 2 +- pom.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index cb8cddf..522f05a 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.2-SNAPSHOT + 3.4.1-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 0a36f5c..53b1f15 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.2-SNAPSHOT + 3.4.1-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index 62561d5..c0113c2 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.2-SNAPSHOT + 3.4.1-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 337ca4f..4a688a8 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.4.2-SNAPSHOT + 3.4.1-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 15e34df..ce874f2 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.4.2-SNAPSHOT + 3.4.1-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index ea870cb..7399f8c 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.4.2-SNAPSHOT + 3.4.1-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index b50bc69..b8e6db1 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.4.2-SNAPSHOT + 3.4.1-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 bdd7986..fcabc69 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.4.2-SNAPSHOT + 3.4.1-SNAPSHOT 4.0.0 diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index ce40fd9..26aef5b 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.2-SNAPSHOT + 3.4.1-SNAPSHOT cas-client 4.0.0 diff --git a/pom.xml b/pom.xml index 964d669..ac95973 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.4.2-SNAPSHOT + 3.4.1-SNAPSHOT cas-client pom From 650cee05bc04f18bc5b0ed7ecd3c40b0f7d7bba3 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Sep 2015 00:19:52 -0400 Subject: [PATCH 12/43] [maven-release-plugin] prepare release cas-client-3.4.1 --- 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 +- cas-client-support-saml/pom.xml | 2 +- pom.xml | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 522f05a..5ca3ec8 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.1 cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 53b1f15..aebb4bb 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.1 cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index c0113c2..ec10fd0 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.1 cas-client 4.0.0 diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index 4a688a8..6812b04 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.4.1-SNAPSHOT + 3.4.1 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index ce874f2..8e99b75 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.4.1-SNAPSHOT + 3.4.1 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index 7399f8c..b088782 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.4.1-SNAPSHOT + 3.4.1 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index b8e6db1..e6d4e29 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.4.1-SNAPSHOT + 3.4.1 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 fcabc69..4063424 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.4.1-SNAPSHOT + 3.4.1 4.0.0 diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index 26aef5b..41d9335 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.1 cas-client 4.0.0 diff --git a/pom.xml b/pom.xml index ac95973..4a53b84 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.4.1-SNAPSHOT + 3.4.1 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.4.1 2006 From a5e2b8ae616e426fb6696132989e2b2de683925e Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Sep 2015 00:23:55 -0400 Subject: [PATCH 13/43] [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 +- cas-client-support-saml/pom.xml | 2 +- pom.xml | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index 5ca3ec8..cb8cddf 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1 + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index aebb4bb..0a36f5c 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1 + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index ec10fd0..62561d5 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1 + 3.4.2-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 6812b04..337ca4f 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.4.1 + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 8e99b75..15e34df 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.4.1 + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index b088782..ea870cb 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.4.1 + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-support-distributed-ehcache/pom.xml b/cas-client-support-distributed-ehcache/pom.xml index e6d4e29..b50bc69 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.4.1 + 3.4.2-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 4063424..bdd7986 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.4.1 + 3.4.2-SNAPSHOT 4.0.0 diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index 41d9335..ce40fd9 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -1,7 +1,7 @@ org.jasig.cas.client - 3.4.1 + 3.4.2-SNAPSHOT cas-client 4.0.0 diff --git a/pom.xml b/pom.xml index 4a53b84..964d669 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.jasig.cas.client - 3.4.1 + 3.4.2-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.4.1 + HEAD 2006 From a417f7852178e2eb8f3109f71d7604dab83e2a5c Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 13 Sep 2015 08:16:18 -0700 Subject: [PATCH 14/43] Fix badge link for maven version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91d9fbb..23e04e7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 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) +# 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.client/cas-client) ## Intro From 598fb02dda441de23d4b07ff8fc7fcc0319f50a8 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Thu, 5 Nov 2015 16:44:05 -0500 Subject: [PATCH 15/43] Issue-141 Remove redundant Content-Length header. --- .../org/jasig/cas/client/validation/Saml11TicketValidator.java | 3 --- 1 file changed, 3 deletions(-) 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 4a59081..8e9561a 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 @@ -198,7 +198,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-Length", Integer.toString(request.length())); conn.setRequestProperty("SOAPAction", "http://www.oasis-open.org/committees/security"); conn.setUseCaches(false); conn.setDoInput(true); @@ -208,8 +207,6 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator final Charset charset = CommonUtils.isNotBlank(getEncoding()) ? Charset.forName(getEncoding()) : IOUtils.UTF8; conn.getOutputStream().write(request.getBytes(charset)); - conn.getOutputStream().flush(); - return IOUtils.readString(conn.getInputStream(), charset); } catch (final IOException e) { throw new RuntimeException("IO error sending HTTP request to /samlValidate", e); From 32963967d49f6c25615faf90998ebdebc274ecb8 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 8 Nov 2015 13:53:33 -0700 Subject: [PATCH 16/43] updated docs on SSOFilter and ErrorRedirectFilter --- README.md | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 23e04e7..df8340b 100644 --- a/README.md +++ b/README.md @@ -421,12 +421,42 @@ Places the `Assertion` in a `ThreadLocal` for portions of the application that n ``` + +#### org.jasig.cas.client.util.ErrorRedirectFilter +Filters that redirects to the supplied url based on an exception. Exceptions and the urls are configured via init filter name/param values. + +| Property | Description | Required +|----------|-------|----------- +| `defaultErrorRedirectPage` | Default url to redirect to, in case no erorr matches are found. | Yes +| `java.lang.Exception` | Fully qualified exception name. Its value must be redirection url | No + + +```xml + + CAS Error Redirect Filter + org.jasig.cas.client.util.ErrorRedirectFilter + + java.lang.Exception + /error.jsp + + + defaultErrorRedirectPage + /defaulterror.jsp + + + + CAS Error Redirect Filter + /* + +``` + + ### 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` +As the `HttpServletRequestWrapperFilter` and `AssertionThreadLocalFilter` have no configuration options, we recommend you just configure them in the `web.xml` ```xml @@ -614,6 +644,10 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter + + casServerUrlPrefix + https://cas.example.com/cas + ... @@ -637,6 +671,10 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio artifactParameterName SAMLart + + casServerUrlPrefix + https://cas.example.com/cas + ... @@ -1079,6 +1117,10 @@ This configuration tested against the sample application that is included with S CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter + + casServerUrlPrefix + https://cas.example.com/cas + From 4b63e06418b2aa0d2a022b7bb3a58d962ad7930c Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 8 Nov 2015 13:54:31 -0700 Subject: [PATCH 17/43] updated docs on SSOFilter and ErrorRedirectFilter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df8340b..29c66b7 100644 --- a/README.md +++ b/README.md @@ -644,7 +644,7 @@ The `SingleSignOutFilter` can affect character encoding. This becomes most obvio CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter - + casServerUrlPrefix https://cas.example.com/cas From 346374ebc83257e98c9c2d7c75b7b32a45dc2f45 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 18 Nov 2015 21:58:06 -0500 Subject: [PATCH 18/43] CASC-127 Remove Commons Codec Dependency Problem: We rely on Commons Codec for some simple Base64 decoding/encoding, most of which is available in Java 1.6+ Solution: Set minimum version to Java 1.6 and rely on provided methods. QA Notes: Unit tests pass --- cas-client-core/pom.xml | 8 -------- .../jasig/cas/client/session/SingleSignOutHandler.java | 7 ++++--- .../jasig/cas/client/session/LogoutMessageGenerator.java | 5 ++--- pom.xml | 4 ++-- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index cb8cddf..ea484e1 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -36,14 +36,6 @@ true - - commons-codec - commons-codec - 1.4 - jar - true - - org.springframework spring-beans 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 5d07095..de13582 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 @@ -19,6 +19,7 @@ package org.jasig.cas.client.session; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.zip.Inflater; @@ -26,8 +27,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.xml.bind.DatatypeConverter; -import org.apache.commons.codec.binary.Base64; import org.jasig.cas.client.Protocol; import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.util.CommonUtils; @@ -146,7 +147,7 @@ public final class SingleSignOutHandler { if (this.artifactParameterOverPost) { this.safeParameters = Arrays.asList(this.logoutParameterName, this.artifactParameterName); } else { - this.safeParameters = Arrays.asList(this.logoutParameterName); + this.safeParameters = Collections.singletonList(this.logoutParameterName); } } } @@ -256,7 +257,7 @@ public final class SingleSignOutHandler { * @return the uncompressed logout message. */ private String uncompressLogoutMessage(final String originalMessage) { - final byte[] binaryMessage = Base64.decodeBase64(originalMessage); + final byte[] binaryMessage = DatatypeConverter.parseBase64Binary(originalMessage); Inflater decompresser = null; try { 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 861fffc..84b9a8d 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 @@ -18,12 +18,11 @@ */ package org.jasig.cas.client.session; +import javax.xml.bind.DatatypeConverter; import java.nio.charset.Charset; import java.util.Date; import java.util.zip.Deflater; -import org.apache.commons.codec.binary.Base64; - /** * Logout message generator to perform tests on Single Sign Out feature. * Greatly inspired by the source code in the CAS server itself. @@ -51,6 +50,6 @@ public final class LogoutMessageGenerator { final int resultSize = deflater.deflate(buffer); final byte[] output = new byte[resultSize]; System.arraycopy(buffer, 0, output, 0, resultSize); - return Base64.encodeBase64String(output); + return DatatypeConverter.printBase64Binary(output); } } diff --git a/pom.xml b/pom.xml index 964d669..75886fa 100644 --- a/pom.xml +++ b/pom.xml @@ -76,8 +76,8 @@ maven-compiler-plugin 3.0 - 1.5 - 1.5 + 1.6 + 1.6 From 61bd0eeb86b0747a69fec9f8f7481f52949c11cb Mon Sep 17 00:00:00 2001 From: BernhardLenz Date: Thu, 4 Feb 2016 18:45:03 -0500 Subject: [PATCH 19/43] Added cas-client-integration-tomcat-v8 --- cas-client-integration-tomcat-v8/NOTICE | 30 +++ cas-client-integration-tomcat-v8/pom.xml | 70 +++++++ .../tomcat/v8/AbstractAuthenticator.java | 198 ++++++++++++++++++ .../tomcat/v8/AbstractCasAuthenticator.java | 47 +++++ .../client/tomcat/v8/AbstractCasRealm.java | 85 ++++++++ .../client/tomcat/v8/AbstractLogoutValve.java | 55 +++++ .../client/tomcat/v8/AssertionCasRealm.java | 49 +++++ .../tomcat/v8/Cas10CasAuthenticator.java | 56 +++++ .../tomcat/v8/Cas20CasAuthenticator.java | 62 ++++++ .../tomcat/v8/Cas20ProxyCasAuthenticator.java | 77 +++++++ .../client/tomcat/v8/PropertiesCasRealm.java | 63 ++++++ .../client/tomcat/v8/ProxyCallbackValve.java | 90 ++++++++ .../client/tomcat/v8/RegexUriLogoutValve.java | 55 +++++ .../client/tomcat/v8/Saml11Authenticator.java | 84 ++++++++ .../client/tomcat/v8/SingleSignOutValve.java | 97 +++++++++ .../tomcat/v8/StaticUriLogoutValve.java | 55 +++++ pom.xml | 1 + 17 files changed, 1174 insertions(+) create mode 100644 cas-client-integration-tomcat-v8/NOTICE create mode 100644 cas-client-integration-tomcat-v8/pom.xml create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractAuthenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasAuthenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasRealm.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java create mode 100644 cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java diff --git a/cas-client-integration-tomcat-v8/NOTICE b/cas-client-integration-tomcat-v8/NOTICE new file mode 100644 index 0000000..f5ce3c0 --- /dev/null +++ b/cas-client-integration-tomcat-v8/NOTICE @@ -0,0 +1,30 @@ +Licensed to Apereo under one or more contributor license +agreements. See the NOTICE file distributed with this work +for additional information regarding copyright ownership. +Apereo licenses this file to you under the Apache License, +Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a +copy of the License at the following location: + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +This project includes: + Jasig CAS Client for Java - Common Tomcat Integration Support under Apache License Version 2.0 + Jasig CAS Client for Java - Core under Apache License Version 2.0 + Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0 + Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0 + Java Servlet API under CDDL + GPLv2 with classpath exception + JCL 1.1.1 implemented over SLF4J under MIT License + Joda-Time under Apache 2 + JUnit under Common Public License Version 1.0 + SLF4J API Module under MIT License + SLF4J Simple Binding under MIT License + tomcat-catalina under Apache License, Version 2.0 + diff --git a/cas-client-integration-tomcat-v8/pom.xml b/cas-client-integration-tomcat-v8/pom.xml new file mode 100644 index 0000000..531abde --- /dev/null +++ b/cas-client-integration-tomcat-v8/pom.xml @@ -0,0 +1,70 @@ + + + + cas-client + org.jasig.cas.client + 3.4.2-SNAPSHOT + + 4.0.0 + + org.jasig.cas.client + cas-client-integration-tomcat-v8 + jar + Jasig CAS Client for Java - Tomcat 8.x Integration + + + + org.jasig.cas.client + cas-client-integration-tomcat-common + ${project.version} + jar + compile + + + org.jasig.cas.client + cas-client-support-saml + ${project.version} + jar + compile + true + + + org.apache.tomcat + tomcat-catalina + 8.0.1 + jar + provided + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-juli + + + org.apache.tomcat + tomcat-annotations-api + + + org.apache.tomcat + tomcat-api + + + org.apache.tomcat + tomcat-util + + + + + + org.jasig.cas.client + cas-client-core + ${project.version} + jar + compile + + + + diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractAuthenticator.java new file mode 100644 index 0000000..6ad0d4b --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractAuthenticator.java @@ -0,0 +1,198 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.io.IOException; +import java.security.Principal; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.*; +import org.apache.catalina.authenticator.AuthenticatorBase; +import org.apache.catalina.connector.Request; +import org.jasig.cas.client.tomcat.AuthenticatorDelegate; +import org.jasig.cas.client.tomcat.CasRealm; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.validation.TicketValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base authenticator for all authentication protocols supported by CAS. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public abstract class AbstractAuthenticator extends AuthenticatorBase implements LifecycleListener { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final AuthenticatorDelegate delegate = new AuthenticatorDelegate(); + + private String casServerUrlPrefix; + + private String encoding; + + private boolean encode; + + private boolean renew; + + protected abstract String getAuthenticationMethod(); + + /** + * Provided for Tomcat 7.0.8 support. + * + * @return the authentication method. + */ + protected String getAuthMethod() { + return getAuthenticationMethod(); + } + + /** + * Abstract method that subclasses should use to provide the name of the artifact parameter (i.e. ticket) + * + * @return the artifact parameter name. CANNOT be NULL. + */ + protected abstract String getArtifactParameterName(); + + /** + * Abstract method that subclasses should use to provide the name of the service parameter (i.e. service) + * + * @return the service parameter name. CANNOT be NULL. + */ + protected abstract String getServiceParameterName(); + + /** + * Returns the single instance of the ticket validator to use to validate tickets. Sub classes should include + * the one appropriate for the + * + * @return a fully configured ticket validator. CANNOT be NULL. + */ + protected abstract TicketValidator getTicketValidator(); + + protected void startInternal() throws LifecycleException { + super.startInternal(); + logger.debug("{} starting.", getName()); + final Realm realm = this.context.getRealm(); + try { + CommonUtils.assertTrue(realm instanceof CasRealm, "Expected CasRealm but got " + realm.getClass()); + CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); + CommonUtils.assertNotNull(this.delegate.getCasServerLoginUrl(), "casServerLoginUrl cannot be null."); + CommonUtils.assertTrue(this.delegate.getServerName() != null || this.delegate.getServiceUrl() != null, + "either serverName or serviceUrl must be set."); + this.delegate.setRealm((CasRealm) realm); + } catch (final Exception e) { + throw new LifecycleException(e); + } + // Complete delegate initialization after the component is started. + // See #lifecycleEvent() method. + addLifecycleListener(this); + } + + protected final String getCasServerUrlPrefix() { + return this.casServerUrlPrefix; + } + + public final void setCasServerUrlPrefix(final String casServerUrlPrefix) { + this.casServerUrlPrefix = casServerUrlPrefix; + } + + public final void setCasServerLoginUrl(final String casServerLoginUrl) { + this.delegate.setCasServerLoginUrl(casServerLoginUrl); + } + + public final boolean isEncode() { + return this.encode; + } + + public final void setEncode(final boolean encode) { + this.encode = encode; + } + + protected final boolean isRenew() { + return this.renew; + } + + public void setRenew(final boolean renew) { + this.renew = renew; + } + + public final void setServerName(final String serverName) { + this.delegate.setServerName(serverName); + } + + public final void setServiceUrl(final String serviceUrl) { + this.delegate.setServiceUrl(serviceUrl); + } + + protected final String getEncoding() { + return this.encoding; + } + + public final void setEncoding(final String encoding) { + this.encoding = encoding; + } + + /** {@inheritDoc} */ + public final boolean authenticate(final Request request, final HttpServletResponse response) throws IOException { + Principal principal = request.getUserPrincipal(); + boolean result = false; + if (principal == null) { + // Authentication sets the response headers for status and redirect if needed + principal = this.delegate.authenticate(request.getRequest(), response); + if (principal != null) { + register(request, response, principal, getAuthenticationMethod(), null, null); + result = true; + } + } else { + result = true; + } + return result; + } + + /** {@inheritDoc} */ + public void lifecycleEvent(final LifecycleEvent event) { + if (AFTER_START_EVENT.equals(event.getType())) { + logger.debug("{} processing lifecycle event {}", getName(), AFTER_START_EVENT); + this.delegate.setTicketValidator(getTicketValidator()); + this.delegate.setArtifactParameterName(getArtifactParameterName()); + this.delegate.setServiceParameterName(getServiceParameterName()); + } + } + + /** {@inheritDoc} */ + public String getInfo() { + return getName() + "/1.0"; + } + + /** {@inheritDoc} + * @throws LifecycleException */ + protected synchronized void setState(LifecycleState state, Object data) throws LifecycleException { + super.setState(state, data); + if (LifecycleState.STARTED.equals(state)) { + logger.info("{} started.", getName()); + } + } + + /** + * @return Authenticator descriptive name. + */ + protected abstract String getName(); +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasAuthenticator.java new file mode 100644 index 0000000..3be3db8 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasAuthenticator.java @@ -0,0 +1,47 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +/** + * Base class for all CAS protocol authenticators. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public abstract class AbstractCasAuthenticator extends AbstractAuthenticator { + + private String proxyCallbackUrl; + + protected final String getProxyCallbackUrl() { + return this.proxyCallbackUrl; + } + + public final void setProxyCallbackUrl(final String proxyCallbackUrl) { + this.proxyCallbackUrl = proxyCallbackUrl; + } + + protected final String getArtifactParameterName() { + return "ticket"; + } + + protected final String getServiceParameterName() { + return "service"; + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasRealm.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasRealm.java new file mode 100644 index 0000000..c3b2144 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractCasRealm.java @@ -0,0 +1,85 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.security.Principal; +import org.apache.catalina.Wrapper; +import org.apache.catalina.realm.RealmBase; +import org.jasig.cas.client.tomcat.CasRealm; + +/** + * Base Realm implementation for all CAS realms. + * + * @author Marvin S. Addison + * @version $Revision$ + * + */ +public abstract class AbstractCasRealm extends RealmBase implements CasRealm { + + /** {@inheritDoc} */ + public Principal authenticate(final Principal p) { + return getDelegate().authenticate(p); + } + + /** {@inheritDoc} */ + public String[] getRoles(final Principal p) { + return getDelegate().getRoles(p); + } + + public boolean hasRole(final Principal principal, final String role) { + return getDelegate().hasRole(principal, role); + } + + /** + * Tomcat 7.0.8 changed their APIs so {@link #hasRole(java.security.Principal, String)} is only valid for 7.0.7 and below. + */ + public boolean hasRole(final Wrapper wrapper, final Principal principal, final String role) { + return hasRole(principal, role); + } + + /** {@inheritDoc} */ + public String toString() { + return getName(); + } + + /** {@inheritDoc} */ + public String getInfo() { + return getClass().getName() + "/1.0"; + } + + /** {@inheritDoc} */ + protected String getName() { + return getClass().getSimpleName(); + } + + /** {@inheritDoc} */ + protected String getPassword(final String userName) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + protected Principal getPrincipal(final String userName) { + throw new UnsupportedOperationException(); + } + + /** + * @return Delegate that all {@link CasRealm} operations are delegated to. + */ + protected abstract CasRealm getDelegate(); +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java new file mode 100644 index 0000000..4264c0d --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AbstractLogoutValve.java @@ -0,0 +1,55 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.jasig.cas.client.tomcat.LogoutHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract base class for Container-managed log out. Removes the attributes + * from the session. + * + * @author Scott Battaglia + * @author Marvin S. Addison + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public abstract class AbstractLogoutValve extends ValveBase { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + public final void invoke(final Request request, final Response response) throws IOException, ServletException { + if (getLogoutHandler().isLogoutRequest(request)) { + getLogoutHandler().logout(request, response); + // Do not proceed up valve chain + return; + } + + logger.debug("URI is not a logout request: {}", request.getRequestURI()); + getNext().invoke(request, response); + } + + protected abstract LogoutHandler getLogoutHandler(); +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java new file mode 100644 index 0000000..422f48a --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/AssertionCasRealm.java @@ -0,0 +1,49 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.jasig.cas.client.tomcat.AssertionCasRealmDelegate; +import org.jasig.cas.client.tomcat.CasRealm; + +/** + * Tomcat Realm that implements {@link CasRealm} for principal and + * role data backed by the CAS {@link org.jasig.cas.client.validation.Assertion}. + *

+ * Authentication always succeeds and simply returns the given principal. + * + * @author Marvin S. Addison + * @version $Revision$ + * + */ +public class AssertionCasRealm extends AbstractCasRealm { + + private final AssertionCasRealmDelegate delegate = new AssertionCasRealmDelegate(); + + /** + * @param name Name of the attribute in the principal that contains role data. + */ + public void setRoleAttributeName(final String name) { + delegate.setRoleAttributeName(name); + } + + /** {@inheritDoc} */ + protected CasRealm getDelegate() { + return delegate; + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java new file mode 100644 index 0000000..a518343 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas10CasAuthenticator.java @@ -0,0 +1,56 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Cas10TicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * Authenticator that handles CAS 1.0 protocol. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class Cas10CasAuthenticator extends AbstractCasAuthenticator { + + public static final String AUTH_METHOD = "CAS10"; + + private static final String NAME = Cas10CasAuthenticator.class.getName(); + + private Cas10TicketValidator ticketValidator; + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected String getAuthenticationMethod() { + return AUTH_METHOD; + } + + protected String getName() { + return NAME; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Cas10TicketValidator(getCasServerUrlPrefix()); + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java new file mode 100644 index 0000000..86d40b4 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20CasAuthenticator.java @@ -0,0 +1,62 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * Authenticator that handles the CAS 2.0 protocol. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class Cas20CasAuthenticator extends AbstractCasAuthenticator { + + public static final String AUTH_METHOD = "CAS20"; + + private static final String NAME = Cas20CasAuthenticator.class.getName(); + + private Cas20ServiceTicketValidator ticketValidator; + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected String getAuthenticationMethod() { + return AUTH_METHOD; + } + + protected String getName() { + return NAME; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Cas20ServiceTicketValidator(getCasServerUrlPrefix()); + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl()); + this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage()); + this.ticketValidator.setRenew(isRenew()); + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java new file mode 100644 index 0000000..b5fa702 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Cas20ProxyCasAuthenticator.java @@ -0,0 +1,77 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.validation.Cas20ProxyTicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * Authenticator that handles the CAS 2.0 protocol with proxying support. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class Cas20ProxyCasAuthenticator extends AbstractCasAuthenticator { + + public static final String AUTH_METHOD = "CAS20-PROXY"; + + private static final String NAME = Cas20ProxyCasAuthenticator.class.getName(); + + private Cas20ProxyTicketValidator ticketValidator; + + private boolean acceptAnyProxy; + + private String allowedProxyChains; + + public void setAcceptAnyProxy(final boolean acceptAnyProxy) { + this.acceptAnyProxy = acceptAnyProxy; + } + + public void setAllowedProxyChains(final String allowedProxyChains) { + this.allowedProxyChains = allowedProxyChains; + } + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected String getAuthenticationMethod() { + return AUTH_METHOD; + } + + protected String getName() { + return NAME; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Cas20ProxyTicketValidator(getCasServerUrlPrefix()); + this.ticketValidator.setRenew(isRenew()); + this.ticketValidator.setProxyCallbackUrl(getProxyCallbackUrl()); + this.ticketValidator.setProxyGrantingTicketStorage(ProxyCallbackValve.getProxyGrantingTicketStorage()); + this.ticketValidator.setAcceptAnyProxy(this.acceptAnyProxy); + this.ticketValidator.setAllowedProxyChains(CommonUtils.createProxyList(this.allowedProxyChains)); + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java new file mode 100644 index 0000000..9cbe8ea --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/PropertiesCasRealm.java @@ -0,0 +1,63 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.tomcat.CasRealm; +import org.jasig.cas.client.tomcat.PropertiesCasRealmDelegate; + +/** + * Tomcat Realm that implements {@link CasRealm} backed by properties file + * containing usernames/and roles of the following format: + *

+ * username1=role1,role2,role3
+ * username2=role1
+ * username3=role2,role3
+ * 
+ * User authentication succeeds if the name of the given principal exists as + * a username in the properties file. + * + * @author Marvin S. Addison + * @version $Revision$ + * @since 3.1.12 + * + */ +public class PropertiesCasRealm extends AbstractCasRealm { + + private final PropertiesCasRealmDelegate delegate = new PropertiesCasRealmDelegate(); + + /** + * @param path Path to properties file container username/role data. + */ + public void setPropertiesFilePath(final String path) { + this.delegate.setPropertiesFilePath(path); + } + + /** {@inheritDoc} */ + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.delegate.readProperties(); + } + + /** {@inheritDoc} */ + protected CasRealm getDelegate() { + return this.delegate; + } + +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java new file mode 100644 index 0000000..adc98cc --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/ProxyCallbackValve.java @@ -0,0 +1,90 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.ReflectUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles watching a url for the proxy callback. + *

+ * Because its tough to share state between valves, we expose the storage mechanism via a static variable. + *

+ * This valve should be ordered before the authentication valves. + * + * @author Scott Battaglia + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class ProxyCallbackValve extends ValveBase { + + private static ProxyGrantingTicketStorage PROXY_GRANTING_TICKET_STORAGE; + + /** Logger instance */ + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private String proxyGrantingTicketStorageClass; + + private String proxyCallbackUrl; + + public static ProxyGrantingTicketStorage getProxyGrantingTicketStorage() { + return PROXY_GRANTING_TICKET_STORAGE; + } + + public void setProxyGrantingTicketStorageClass(final String proxyGrantingTicketStorageClass) { + this.proxyGrantingTicketStorageClass = proxyGrantingTicketStorageClass; + } + + public void setProxyCallbackUrl(final String proxyCallbackUrl) { + this.proxyCallbackUrl = proxyCallbackUrl; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + + try { + CommonUtils.assertNotNull(this.proxyCallbackUrl, "the proxy callback url cannot be null"); + CommonUtils.assertTrue(this.proxyCallbackUrl.startsWith("/"), "proxy callback url must start with \"/\""); + + PROXY_GRANTING_TICKET_STORAGE = ReflectUtils.newInstance(proxyGrantingTicketStorageClass); + } catch (final Exception e) { + throw new LifecycleException(e); + } + logger.info("Startup completed."); + } + + public void invoke(final Request request, final Response response) throws IOException, ServletException { + if (this.proxyCallbackUrl.equals(request.getRequestURI())) { + logger.debug("Processing proxy callback request."); + CommonUtils.readAndRespondToProxyReceptorRequest(request, response, PROXY_GRANTING_TICKET_STORAGE); + return; + } + + getNext().invoke(request, response); + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java new file mode 100644 index 0000000..fc8999f --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/RegexUriLogoutValve.java @@ -0,0 +1,55 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.tomcat.LogoutHandler; +import org.jasig.cas.client.tomcat.RegexUriLogoutHandler; + +/** + * Performs CAS logout when the request URI matches a regular expression. + * + * @author Scott Battaglia + * @author Marvin S. Addison + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class RegexUriLogoutValve extends AbstractLogoutValve { + + private RegexUriLogoutHandler logoutHandler = new RegexUriLogoutHandler(); + + public void setRedirectUrl(final String redirectUrl) { + this.logoutHandler.setRedirectUrl(redirectUrl); + } + + public void setLogoutUriRegex(final String regex) { + this.logoutHandler.setLogoutUriRegex(regex); + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.logoutHandler.init(); + logger.info("Startup completed."); + } + + /** {@inheritDoc} */ + protected LogoutHandler getLogoutHandler() { + return this.logoutHandler; + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java new file mode 100644 index 0000000..fc44569 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/Saml11Authenticator.java @@ -0,0 +1,84 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.validation.Saml11TicketValidator; +import org.jasig.cas.client.validation.TicketValidator; + +/** + * CAS authenticator that uses the SAML 1.1 protocol. + * + * @author Marvin S. Addison + * @version $Revision$ + * @since 3.1.12 + * + */ +public final class Saml11Authenticator extends AbstractAuthenticator { + + public static final String AUTH_METHOD = "SAML11"; + + private static final String NAME = Saml11Authenticator.class.getName(); + + private Saml11TicketValidator ticketValidator; + + /** SAML protocol clock drift tolerance in ms */ + private int tolerance = -1; + + /** + * @param ms SAML clock drift tolerance in milliseconds. + */ + public void setTolerance(final int ms) { + this.tolerance = ms; + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.ticketValidator = new Saml11TicketValidator(getCasServerUrlPrefix()); + if (this.tolerance > -1) { + this.ticketValidator.setTolerance(this.tolerance); + } + if (getEncoding() != null) { + this.ticketValidator.setEncoding(getEncoding()); + } + this.ticketValidator.setRenew(isRenew()); + } + + protected TicketValidator getTicketValidator() { + return this.ticketValidator; + } + + protected String getAuthenticationMethod() { + return AUTH_METHOD; + } + + /** {@inheritDoc} */ + protected String getArtifactParameterName() { + return "SAMLart"; + } + + /** {@inheritDoc} */ + protected String getServiceParameterName() { + return "TARGET"; + } + + protected String getName() { + return NAME; + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java new file mode 100644 index 0000000..02fe955 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java @@ -0,0 +1,97 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.jasig.cas.client.session.SessionMappingStorage; +import org.jasig.cas.client.session.SingleSignOutHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles logout request messages sent from the CAS server by ending the current + * HTTP session. + * + * @author Marvin S. Addison + * @version $Revision$ $Date$ + * @since 3.1.12 + * + */ +public class SingleSignOutValve extends ValveBase implements SessionListener { + + /** Logger instance */ + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final SingleSignOutHandler handler = new SingleSignOutHandler(); + + public void setArtifactParameterName(final String name) { + this.handler.setArtifactParameterName(name); + } + + public void setLogoutParameterName(final String name) { + this.handler.setLogoutParameterName(name); + } + + public void setFrontLogoutParameterName(final String name) { + this.handler.setFrontLogoutParameterName(name); + } + + public void setRelayStateParameterName(final String name) { + this.handler.setRelayStateParameterName(name); + } + + public void setCasServerUrlPrefix(final String casServerUrlPrefix) { + this.handler.setCasServerUrlPrefix(casServerUrlPrefix); + } + + public void setSessionMappingStorage(final SessionMappingStorage storage) { + this.handler.setSessionMappingStorage(storage); + } + + /** {@inheritDoc} */ + public void invoke(final Request request, final Response response) throws IOException, ServletException { + if (this.handler.process(request, response)) { + getNext().invoke(request, response); + } + } + + /** {@inheritDoc} */ + public void sessionEvent(final SessionEvent event) { + if (Session.SESSION_DESTROYED_EVENT.equals(event.getType())) { + logger.debug("Cleaning up SessionMappingStorage on destroySession event"); + this.handler.getSessionMappingStorage().removeBySessionById(event.getSession().getId()); + } + } + + /** {@inheritDoc} */ + protected void startInternal() throws LifecycleException { + super.startInternal(); + logger.info("Starting..."); + this.handler.init(); + logger.info("Startup completed."); + } +} diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java new file mode 100644 index 0000000..516f331 --- /dev/null +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/StaticUriLogoutValve.java @@ -0,0 +1,55 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.tomcat.v8; + +import org.apache.catalina.LifecycleException; +import org.jasig.cas.client.tomcat.LogoutHandler; +import org.jasig.cas.client.tomcat.StaticUriLogoutHandler; + +/** + * Monitors a specific request URI for logout requests. + * + * @author Scott Battaglia + * @author Marvin S. Addison + * @version $Revision$ $Date$ + * @since 3.1.12 + */ +public final class StaticUriLogoutValve extends AbstractLogoutValve { + + private StaticUriLogoutHandler logoutHandler = new StaticUriLogoutHandler(); + + public void setRedirectUrl(final String redirectUrl) { + this.logoutHandler.setRedirectUrl(redirectUrl); + } + + public void setLogoutUri(final String logoutUri) { + this.logoutHandler.setLogoutUri(logoutUri); + } + + protected void startInternal() throws LifecycleException { + super.startInternal(); + this.logoutHandler.init(); + logger.info("Startup completed."); + } + + /** {@inheritDoc} */ + protected LogoutHandler getLogoutHandler() { + return this.logoutHandler; + } +} diff --git a/pom.xml b/pom.xml index 75886fa..a5d3ba8 100644 --- a/pom.xml +++ b/pom.xml @@ -252,6 +252,7 @@ cas-client-integration-tomcat-common cas-client-integration-tomcat-v6 cas-client-integration-tomcat-v7 + cas-client-integration-tomcat-v8 From 53dbb488820a38000421954734f2cbe5a3f2109b Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Thu, 11 Feb 2016 14:53:14 -0500 Subject: [PATCH 20/43] Issue #152 Jetty container-based authn. --- .../jasig/cas/client/util/ReflectUtils.java | 32 +++ .../cas/client/util/ReflectUtilsTests.java | 24 ++ cas-client-integration-jetty/pom.xml | 106 ++++++++ .../cas/client/jetty/CasAuthentication.java | 45 ++++ .../cas/client/jetty/CasAuthenticator.java | 249 ++++++++++++++++++ .../cas/client/jetty/CasUserIdentity.java | 66 +++++ .../client/jetty/CasAuthenticatorTest.java | 210 +++++++++++++++ .../src/test/resources/jetty/webapp.xml | 14 + .../src/test/webapp/index.jsp | 9 + .../src/test/webapp/secure.jsp | 9 + pom.xml | 1 + 11 files changed, 765 insertions(+) create mode 100644 cas-client-integration-jetty/pom.xml create mode 100644 cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java create mode 100644 cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java create mode 100644 cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java create mode 100644 cas-client-integration-jetty/src/test/java/org/jasig/cas/client/jetty/CasAuthenticatorTest.java create mode 100644 cas-client-integration-jetty/src/test/resources/jetty/webapp.xml create mode 100644 cas-client-integration-jetty/src/test/webapp/index.jsp create mode 100644 cas-client-integration-jetty/src/test/webapp/secure.jsp diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java index 1ec2116..8759593 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/ReflectUtils.java @@ -22,6 +22,7 @@ import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; /** @@ -148,4 +149,35 @@ public final class ReflectUtils { throw new RuntimeException("Error setting property " + propertyName, e); } } + + /** + * Gets the value of the given declared field on the target object or any of its superclasses. + * + * @param fieldName Name of field to get. + * @param target Target object that possesses field. + * + * @return Field value. + */ + public static Object getField(final String fieldName, final Object target) { + Class clazz = target.getClass(); + Field field = null; + do { + try { + field = clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } while (field == null && clazz != null); + if (field == null) { + throw new IllegalArgumentException(fieldName + " does not exist on " + target); + } + try { + if (!field.isAccessible()) { + field.setAccessible(true); + } + return field.get(target); + } catch (Exception e) { + throw new IllegalArgumentException("Error getting field " + fieldName, e); + } + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java index d39e3bb..57d741c 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/util/ReflectUtilsTests.java @@ -54,6 +54,18 @@ public class ReflectUtilsTests extends TestCase { assertTrue(bean.isFlag()); } + public void testGetField() { + final TestBean bean = new TestBean(); + bean.setName("bob"); + assertEquals(bean.getName(), ReflectUtils.getField("name", bean)); + } + + public void testGetFieldSuperclass() { + final TestSubBean bean = new TestSubBean(); + bean.setName("bob"); + assertEquals(bean.getName(), ReflectUtils.getField("name", bean)); + } + static class TestBean { private int count; private boolean flag; @@ -102,4 +114,16 @@ public class ReflectUtilsTests extends TestCase { } } + + static class TestSubBean extends TestBean { + private String state; + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + } } diff --git a/cas-client-integration-jetty/pom.xml b/cas-client-integration-jetty/pom.xml new file mode 100644 index 0000000..96a28ac --- /dev/null +++ b/cas-client-integration-jetty/pom.xml @@ -0,0 +1,106 @@ + + + + cas-client + org.jasig.cas.client + 3.4.2-SNAPSHOT + + 4.0.0 + + org.jasig.cas.client + cas-client-integration-jetty + jar + Jasig CAS Client for Java - Jetty Container Integration + + + 9.2.14.v20151106 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.jasig.cas.client + cas-client-core + ${project.version} + + + org.eclipse.jetty + jetty-security + ${jetty.version} + + + + + org.jasig.cas.client + cas-client-core + ${project.version} + test-jar + test + + + org.eclipse.jetty + jetty-webapp + ${jetty.version} + test + + + org.eclipse.jetty + jetty-plus + ${jetty.version} + test + + + org.eclipse.jetty + jetty-annotations + ${jetty.version} + test + + + org.eclipse.jetty + apache-jsp + ${jetty.version} + test + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + + diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java new file mode 100644 index 0000000..0b8fb2a --- /dev/null +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java @@ -0,0 +1,45 @@ +package org.jasig.cas.client.jetty; + +import org.eclipse.jetty.security.UserAuthentication; +import org.jasig.cas.client.validation.Assertion; + +/** + * CAS-specific user authentication. + * + * @author Marvin S. Addison + */ +public class CasAuthentication extends UserAuthentication { + + /** CAS authenticator that produced this authentication. */ + private final CasAuthenticator authenticator; + + /** CAS ticket that was successfully validated to permit authentication. */ + private final String ticket; + + + /** + * Creates a new instance. + * + * @param authenticator The authenticator that produced this authentication. + * @param ticket The CAS ticket that was successfully validated to permit authentication. + * @param assertion The CAS assertion produced from successful ticket validation. + */ + public CasAuthentication(final CasAuthenticator authenticator, final String ticket, final Assertion assertion) { + super(authenticator.getAuthMethod(), new CasUserIdentity(assertion, authenticator.getRoleAttribute())); + assert ticket != null : "Ticket cannot be null"; + assert authenticator != null : "CasAuthenticator cannot be null"; + this.authenticator = authenticator; + this.ticket = ticket; + } + + /** @return The CAS ticket that was successfully validated to permit authentication. */ + public String getTicket() { + return ticket; + } + + @Override + public void logout() { + super.logout(); + this.authenticator.clearCachedAuthentication(ticket); + } +} diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java new file mode 100644 index 0000000..01c2c37 --- /dev/null +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -0,0 +1,249 @@ +/* + * 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.jetty; + +import org.eclipse.jetty.security.Authenticator; +import org.eclipse.jetty.security.ServerAuthException; +import org.eclipse.jetty.server.Authentication; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.jasig.cas.client.Protocol; +import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.ReflectUtils; +import org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator; +import org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator; +import org.jasig.cas.client.validation.Assertion; +import org.jasig.cas.client.validation.TicketValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Jetty authenticator component for container-managed CAS authentication. + *

NOTE: This component does not support CAS gateway mode.

+ * + * @author Marvin S. Addison + * @since 3.4.2 + */ +public class CasAuthenticator extends AbstractLifeCycle implements Authenticator { + + /** Name of authentication method provided by this authenticator. */ + public static final String AUTH_METHOD = "CAS"; + + /** Session attribute used to cache CAS authentication data. */ + private static final String CACHED_AUTHN_ATTRIBUTE = "org.jasig.cas.client.jetty.Authentication"; + + /** Logger instance. */ + private final Logger logger = LoggerFactory.getLogger(CasAuthenticator.class); + + /** Map of tickets to sessions. */ + private final ConcurrentMap sessionMap = new ConcurrentHashMap(); + + /** CAS ticket validator component. */ + private TicketValidator ticketValidator; + + /** Space-delimited ist of server names. */ + private String serverNames; + + /** CAS principal attribute containing role data. */ + private String roleAttribute; + + /** URL to /login URI on CAS server. */ + private String casServerLoginUrl; + + /** Protocol used by ticket validator. */ + private Protocol protocol; + + /** CAS renew parameter. */ + private boolean renew; + + + /** + * Sets the CAS ticket validator component. + * + * @param ticketValidator Ticket validator, MUST NOT be null. + */ + public void setTicketValidator(final TicketValidator ticketValidator) { + assert ticketValidator != null : "TicketValidator cannot be null"; + if (ticketValidator instanceof AbstractUrlBasedTicketValidator) { + if (ticketValidator instanceof AbstractCasProtocolUrlBasedTicketValidator) { + protocol = Protocol.CAS2; + } else { + protocol = Protocol.SAML11; + } + casServerLoginUrl = ReflectUtils.getField("casServerUrlPrefix", ticketValidator) + "/login"; + renew = (Boolean) ReflectUtils.getField("renew", ticketValidator); + } else { + throw new IllegalArgumentException("Unsupported ticket validator " + ticketValidator); + } + this.ticketValidator = ticketValidator; + } + + /** + * Sets the names of the server host running Jetty. + * + * @param nameList Space-delimited list of one or more server names, e.g. "www1.example.com www2.example.com". + * MUST NOT be blank. + */ + public void setServerNames(final String nameList) { + CommonUtils.isNotBlank(nameList); + this.serverNames = nameList; + } + + /** @return The name of the CAS principal attribute that contains role data. */ + public String getRoleAttribute() { + return roleAttribute; + } + + /** + * Sets the name of the CAS principal attribute that contains role data. + * + * @param roleAttribute Role attribute name. MUST NOT be blank. + */ + public void setRoleAttribute(final String roleAttribute) { + CommonUtils.isNotBlank(roleAttribute); + this.roleAttribute = roleAttribute; + } + + @Override + public void setConfiguration(final AuthConfiguration configuration) { + // Nothing to do + // All configuration must be via CAS-specific setter methods + } + + @Override + public String getAuthMethod() { + return AUTH_METHOD; + } + + @Override + public void prepareRequest(final ServletRequest request) { + // Nothing to do + } + + @Override + public Authentication validateRequest( + final ServletRequest servletRequest, final ServletResponse servletResponse, final boolean mandatory) + throws ServerAuthException { + + final HttpServletRequest request = (HttpServletRequest) servletRequest; + final HttpServletResponse response = (HttpServletResponse) servletResponse; + + CasAuthentication authentication = fetchCachedAuthentication(request); + if (!mandatory) { + if (authentication != null) { + return authentication; + } + return Authentication.UNAUTHENTICATED; + } + + String ticket; + for (final Protocol protocol : Protocol.values()) { + ticket = request.getParameter(protocol.getArtifactParameterName()); + if (ticket != null) { + try { + logger.debug("Attempting to validate {}", ticket); + final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response)); + logger.debug("Successfully authenticated {}", assertion.getPrincipal()); + authentication = new CasAuthentication(this, ticket, assertion); + cacheAuthentication(request, authentication); + } catch (Exception e) { + throw new ServerAuthException("CAS ticket validation failed", e); + } + } + } + + if (authentication != null) { + return authentication; + } + redirectToCas(request, response); + return Authentication.SEND_CONTINUE; + } + + @Override + public boolean secureResponse( + final ServletRequest request, + final ServletResponse response, + final boolean mandatory, + final Authentication.User user) throws ServerAuthException { + return true; + } + + @Override + protected void doStart() throws Exception { + if (ticketValidator == null) { + throw new RuntimeException("TicketValidator cannot be null"); + } + if (serverNames == null) { + throw new RuntimeException("ServerNames cannot be null"); + } + } + + protected void clearCachedAuthentication(final String ticket) { + sessionMap.remove(ticket); + } + + private void cacheAuthentication(final HttpServletRequest request, final CasAuthentication authentication) { + final HttpSession session = request.getSession(false); + if (session != null) { + session.setAttribute(CACHED_AUTHN_ATTRIBUTE, authentication); + sessionMap.put(authentication.getTicket(), session); + } + } + + private CasAuthentication fetchCachedAuthentication(final HttpServletRequest request) { + final HttpSession session = request.getSession(false); + if (session != null) { + return (CasAuthentication) session.getAttribute(CACHED_AUTHN_ATTRIBUTE); + } + return null; + } + + private String serviceUrl(final HttpServletRequest request, final HttpServletResponse response) { + return CommonUtils.constructServiceUrl( + request, + response, + null, + serverNames, + protocol.getServiceParameterName(), + protocol.getArtifactParameterName(), + true); + } + + private void redirectToCas( + final HttpServletRequest request, final HttpServletResponse response) throws ServerAuthException { + try { + final String redirectUrl = CommonUtils.constructRedirectUrl( + casServerLoginUrl, protocol.getServiceParameterName(), serviceUrl(request, response), renew, false); + logger.debug("Redirecting to {}", redirectUrl); + response.sendRedirect(redirectUrl); + } catch (IOException e) { + logger.debug("Redirect to CAS failed with error: {}", e); + throw new ServerAuthException("Redirect to CAS failed", e); + } + } + +} diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java new file mode 100644 index 0000000..200e626 --- /dev/null +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java @@ -0,0 +1,66 @@ +package org.jasig.cas.client.jetty; + +import org.eclipse.jetty.server.UserIdentity; +import org.jasig.cas.client.authentication.AttributePrincipal; +import org.jasig.cas.client.validation.Assertion; + +import javax.security.auth.Subject; +import java.security.Principal; +import java.util.Collection; + +/** + * CAS user identity backed by assertion data. + * + * @author Marvin S. Addison + */ +public class CasUserIdentity implements UserIdentity { + + /** CAS principal. */ + private AttributePrincipal principal; + + /** Assertion attribute containing role data. */ + private String roleAttribute; + + + /** + * Creates a new instance from a CAS assertion containing principal information. + * + * @param assertion CAS assertion resulting from successful ticket validation. + * @param roleAttribute Principal attribute containing role data. + */ + public CasUserIdentity(final Assertion assertion, final String roleAttribute) { + assert assertion != null : "Assertion cannot be null"; + this.principal = assertion.getPrincipal(); + this.roleAttribute = roleAttribute; + } + + @Override + public Subject getSubject() { + final Subject subject = new Subject(); + subject.getPrincipals().add(principal); + return subject; + } + + @Override + public Principal getUserPrincipal() { + return principal; + } + + @Override + public boolean isUserInRole(final String role, final Scope scope) { + if (roleAttribute != null) { + final Object value = principal.getAttributes().get(roleAttribute); + if (value instanceof Collection) { + return ((Collection) value).contains(role); + } else if (value instanceof String) { + return value.equals(role); + } + } + return false; + } + + @Override + public String toString() { + return principal.getName(); + } +} diff --git a/cas-client-integration-jetty/src/test/java/org/jasig/cas/client/jetty/CasAuthenticatorTest.java b/cas-client-integration-jetty/src/test/java/org/jasig/cas/client/jetty/CasAuthenticatorTest.java new file mode 100644 index 0000000..462f353 --- /dev/null +++ b/cas-client-integration-jetty/src/test/java/org/jasig/cas/client/jetty/CasAuthenticatorTest.java @@ -0,0 +1,210 @@ +package org.jasig.cas.client.jetty; + +import org.apache.tomcat.InstanceManager; +import org.apache.tomcat.SimpleInstanceManager; +import org.eclipse.jetty.annotations.ServletContainerInitializersStarter; +import org.eclipse.jetty.apache.jsp.JettyJasperInitializer; +import org.eclipse.jetty.jsp.JettyJspServlet; +import org.eclipse.jetty.plus.annotation.ContainerInitializer; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.webapp.WebAppContext; +import org.jasig.cas.client.PublicTestHttpServer; +import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Unit test for {@link CasAuthenticator}. + * + * @author Marvin S. Addison + */ +public class CasAuthenticatorTest { + + private static final Server server = new Server(8080); + private static final CasAuthenticator authenticator = new CasAuthenticator(); + + @BeforeClass + public static void beforeClass() throws Exception { + final WebAppContext context = new WebAppContext(); + context.setContextPath("/webapp"); + String workingDir = new File(".").getAbsolutePath(); + workingDir = workingDir.substring(0, workingDir.length() - 2); + final String webappDir; + if (workingDir.endsWith("/cas-client-integration-jetty")) { + webappDir = workingDir + "/src/test/webapp"; + } else { + webappDir = workingDir + "/cas-client-integration-jetty/src/test/webapp"; + } + context.setWar(webappDir); + + + // JSP config from https://github.com/jetty-project/embedded-jetty-jsp/ + System.setProperty("org.apache.jasper.compiler.disablejsr199", "false"); + context.setAttribute("javax.servlet.context.tempdir", getScratchDir()); + context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$"); + context.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers()); + context.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager()); + context.addBean(new ServletContainerInitializersStarter(context), true); + context.addServlet(jspServletHolder(), "*.jsp"); + + // Wire up CAS authentication + authenticator.setServerNames("localhost:8080"); + authenticator.setTicketValidator(new Cas20ServiceTicketValidator("http://localhost:8081/cas")); + + // Configure security handling for webapp context + final ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); + final Constraint constraint = new Constraint("CasRealm", Constraint.ANY_AUTH); + constraint.setAuthenticate(true); + final ConstraintMapping secureMapping = new ConstraintMapping(); + secureMapping.setPathSpec("/secure.jsp"); + secureMapping.setConstraint(constraint); + securityHandler.addConstraintMapping(secureMapping); + securityHandler.setAuthenticator(authenticator); + context.setSecurityHandler(securityHandler); + + // Add webapp context and start the server + server.setHandler(context); + server.start(); + } + + @Test + public void testValidateRequestPublicPageNoTicket() throws Exception { + final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/"); + try { + assertEquals(200, uc.getResponseCode()); + assertTrue(readOutput(uc).contains("Welcome everyone")); + } finally { + uc.disconnect(); + } + } + + @Test + public void testValidateRequestPublicPageWithTicket() throws Exception { + final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/?ticket=ST-12345"); + try { + assertEquals(200, uc.getResponseCode()); + assertTrue(readOutput(uc).contains("Welcome everyone")); + } finally { + uc.disconnect(); + } + } + + @Test + public void testValidateRequestSecurePageNoTicket() throws Exception { + final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp"); + try { + assertEquals(302, uc.getResponseCode()); + assertEquals( + "http://localhost:8081/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fwebapp%2Fsecure.jsp", + uc.getHeaderField("Location")); + } finally { + uc.disconnect(); + } + } + + @Test + public void testValidateRequestSecurePageWithTicket() throws Exception { + final String successResponse = "" + + "" + + "bob" + + "" + + ""; + final PublicTestHttpServer server = PublicTestHttpServer.instance(8081); + server.content = successResponse.getBytes(StandardCharsets.UTF_8); + final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp?ticket=ST-12345"); + try { + assertEquals(200, uc.getResponseCode()); + assertTrue(readOutput(uc).contains("Hello bob")); + } finally { + uc.disconnect(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + server.stop(); + } + + private String readOutput(final URLConnection connection) throws IOException { + final InputStreamReader reader = new InputStreamReader(connection.getInputStream()); + final StringBuilder builder = new StringBuilder(); + final CharBuffer buffer = CharBuffer.allocate(1024); + try { + while (reader.read(buffer) > 0) { + builder.append(buffer.flip()); + buffer.clear(); + } + } finally { + reader.close(); + } + return builder.toString(); + } + + private static File getScratchDir() throws IOException + { + final File tempDir = new File(System.getProperty("java.io.tmpdir")); + final File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp"); + + if (!scratchDir.exists()) + { + if (!scratchDir.mkdirs()) + { + throw new IOException("Unable to create scratch directory: " + scratchDir); + } + } + return scratchDir; + } + + /** + * Ensure the jsp engine is initialized correctly + */ + private static List jspInitializers() + { + return Collections.singletonList(new ContainerInitializer(new JettyJasperInitializer(), null)); + } + + /** + * Create JSP Servlet (must be named "jsp") + */ + private static ServletHolder jspServletHolder() + { + final ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class); + holderJsp.setInitOrder(0); + holderJsp.setInitParameter("logVerbosityLevel", "DEBUG"); + holderJsp.setInitParameter("fork", "false"); + holderJsp.setInitParameter("xpoweredBy", "false"); + holderJsp.setInitParameter("compilerTargetVM", "1.7"); + holderJsp.setInitParameter("compilerSourceVM", "1.7"); + holderJsp.setInitParameter("keepgenerated", "true"); + return holderJsp; + } + + private static HttpURLConnection openConnection(final String url) throws IOException { + final HttpURLConnection uc; + try { + uc = (HttpURLConnection) new URL(url).openConnection(); + } catch (IOException e) { + throw new RuntimeException("Invalid URL: " + url, e); + } + uc.setInstanceFollowRedirects(false); + uc.connect(); + return uc; + } +} \ No newline at end of file diff --git a/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml b/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml new file mode 100644 index 0000000..f3c4fc4 --- /dev/null +++ b/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml @@ -0,0 +1,14 @@ + + + + + localhost:8080 + + + http://localhost:8081/cas + + + + + + \ No newline at end of file diff --git a/cas-client-integration-jetty/src/test/webapp/index.jsp b/cas-client-integration-jetty/src/test/webapp/index.jsp new file mode 100644 index 0000000..6d505bb --- /dev/null +++ b/cas-client-integration-jetty/src/test/webapp/index.jsp @@ -0,0 +1,9 @@ + + + + + Welcome Page + +

Welcome everyone

+ + \ No newline at end of file diff --git a/cas-client-integration-jetty/src/test/webapp/secure.jsp b/cas-client-integration-jetty/src/test/webapp/secure.jsp new file mode 100644 index 0000000..9add84e --- /dev/null +++ b/cas-client-integration-jetty/src/test/webapp/secure.jsp @@ -0,0 +1,9 @@ + + + + + Secure Page + +

Hello <%=request.getUserPrincipal()%>

+ + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 75886fa..99bfe01 100644 --- a/pom.xml +++ b/pom.xml @@ -252,6 +252,7 @@ cas-client-integration-tomcat-common cas-client-integration-tomcat-v6 cas-client-integration-tomcat-v7 + cas-client-integration-jetty From f04dedd9bb03575b6565d3c69b95d51b4da813d8 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Thu, 11 Feb 2016 15:08:00 -0500 Subject: [PATCH 21/43] Issue #152 Use WeakReference to avoid resource leak. We don't want to hold a reference to HttpSession objects in the ticket-to-session mapping that would prevent orphaned or expired sessions from being purged. WeakReference ensures that won't happen. --- .../org/jasig/cas/client/jetty/CasAuthenticator.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 01c2c37..14b359b 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -38,6 +38,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -60,7 +61,8 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator private final Logger logger = LoggerFactory.getLogger(CasAuthenticator.class); /** Map of tickets to sessions. */ - private final ConcurrentMap sessionMap = new ConcurrentHashMap(); + private final ConcurrentMap> sessionMap = + new ConcurrentHashMap>(); /** CAS ticket validator component. */ private TicketValidator ticketValidator; @@ -203,14 +205,17 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator } protected void clearCachedAuthentication(final String ticket) { - sessionMap.remove(ticket); + final WeakReference sessionRef = sessionMap.remove(ticket); + if (sessionRef != null && sessionRef.get() != null) { + sessionRef.get().removeAttribute(CACHED_AUTHN_ATTRIBUTE); + } } private void cacheAuthentication(final HttpServletRequest request, final CasAuthentication authentication) { final HttpSession session = request.getSession(false); if (session != null) { session.setAttribute(CACHED_AUTHN_ATTRIBUTE, authentication); - sessionMap.put(authentication.getTicket(), session); + sessionMap.put(authentication.getTicket(), new WeakReference(session)); } } From 971d4b4854e58d56f257e1b6318654f951dca561 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Thu, 11 Feb 2016 15:12:39 -0500 Subject: [PATCH 22/43] Issue #152 Remove unused jetty-maven-plugin. --- cas-client-integration-jetty/pom.xml | 35 +--------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/cas-client-integration-jetty/pom.xml b/cas-client-integration-jetty/pom.xml index 96a28ac..480acbe 100644 --- a/cas-client-integration-jetty/pom.xml +++ b/cas-client-integration-jetty/pom.xml @@ -13,43 +13,10 @@ Jasig CAS Client for Java - Jetty Container Integration + 9.2.14.v20151106 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.jasig.cas.client From f09ee1c0e741eb58b7805af8748b3472d82c04db Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 12 Feb 2016 15:34:19 -0500 Subject: [PATCH 23/43] Issue #152 Fix multiple ticket validation attempt. --- .../cas/client/jetty/CasAuthenticator.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 14b359b..0cb10a0 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -162,22 +162,18 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator return Authentication.UNAUTHENTICATED; } - String ticket; - for (final Protocol protocol : Protocol.values()) { - ticket = request.getParameter(protocol.getArtifactParameterName()); - if (ticket != null) { - try { - logger.debug("Attempting to validate {}", ticket); - final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response)); - logger.debug("Successfully authenticated {}", assertion.getPrincipal()); - authentication = new CasAuthentication(this, ticket, assertion); - cacheAuthentication(request, authentication); - } catch (Exception e) { - throw new ServerAuthException("CAS ticket validation failed", e); - } + final String ticket = extractTicket(request); + if (ticket != null) { + try { + logger.debug("Attempting to validate {}", ticket); + final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response)); + logger.debug("Successfully authenticated {}", assertion.getPrincipal()); + authentication = new CasAuthentication(this, ticket, assertion); + cacheAuthentication(request, authentication); + } catch (Exception e) { + throw new ServerAuthException("CAS ticket validation failed", e); } } - if (authentication != null) { return authentication; } @@ -251,4 +247,14 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator } } + private String extractTicket(final HttpServletRequest request) { + String ticket; + for (final Protocol protocol : Protocol.values()) { + ticket = request.getParameter(protocol.getArtifactParameterName()); + if (ticket != null) { + return ticket; + } + } + return null; + } } From 5a68c92268b038ac21f7084bc6fae160831240a4 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 12 Feb 2016 16:20:56 -0500 Subject: [PATCH 24/43] Issue #152 Prevent dupe ticket validations. The ticket parameter can linger in the URL after authentication. Don't attempt ticket validation if we are already authenticated. Fixes ticket validation failures on refresh and similar cases. --- .../cas/client/jetty/CasAuthenticator.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 0cb10a0..513ff55 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -155,15 +155,12 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator final HttpServletResponse response = (HttpServletResponse) servletResponse; CasAuthentication authentication = fetchCachedAuthentication(request); - if (!mandatory) { - if (authentication != null) { - return authentication; - } - return Authentication.UNAUTHENTICATED; + if (authentication != null) { + return authentication; } final String ticket = extractTicket(request); - if (ticket != null) { + if (ticket != null && mandatory) { try { logger.debug("Attempting to validate {}", ticket); final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response)); @@ -176,9 +173,11 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator } if (authentication != null) { return authentication; + } else if (mandatory) { + redirectToCas(request, response); + return Authentication.SEND_CONTINUE; } - redirectToCas(request, response); - return Authentication.SEND_CONTINUE; + return Authentication.UNAUTHENTICATED; } @Override @@ -208,7 +207,7 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator } private void cacheAuthentication(final HttpServletRequest request, final CasAuthentication authentication) { - final HttpSession session = request.getSession(false); + final HttpSession session = request.getSession(true); if (session != null) { session.setAttribute(CACHED_AUTHN_ATTRIBUTE, authentication); sessionMap.put(authentication.getTicket(), new WeakReference(session)); From 184868b296f9e73801bc716fad3e00bf8ea47db4 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 12 Feb 2016 16:40:05 -0500 Subject: [PATCH 25/43] Issue #152 Add working Jetty context config files. --- .../src/test/resources/jetty/context-cas2.xml | 20 ++++++++++++++++++ .../test/resources/jetty/context-saml11.xml | 21 +++++++++++++++++++ .../src/test/resources/jetty/webapp.xml | 14 ------------- 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 cas-client-integration-jetty/src/test/resources/jetty/context-cas2.xml create mode 100644 cas-client-integration-jetty/src/test/resources/jetty/context-saml11.xml delete mode 100644 cas-client-integration-jetty/src/test/resources/jetty/webapp.xml diff --git a/cas-client-integration-jetty/src/test/resources/jetty/context-cas2.xml b/cas-client-integration-jetty/src/test/resources/jetty/context-cas2.xml new file mode 100644 index 0000000..a786496 --- /dev/null +++ b/cas-client-integration-jetty/src/test/resources/jetty/context-cas2.xml @@ -0,0 +1,20 @@ + + + + + / + /webapps/yourapp + + + + app.example.com + + + https://cas.example.com/cas + + + + + + + diff --git a/cas-client-integration-jetty/src/test/resources/jetty/context-saml11.xml b/cas-client-integration-jetty/src/test/resources/jetty/context-saml11.xml new file mode 100644 index 0000000..5e1d5ad --- /dev/null +++ b/cas-client-integration-jetty/src/test/resources/jetty/context-saml11.xml @@ -0,0 +1,21 @@ + + + + + / + /webapps/yourapp + + + + app.example.com + memberOf + + + https://cas.example.com/cas + + + + + + + diff --git a/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml b/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml deleted file mode 100644 index f3c4fc4..0000000 --- a/cas-client-integration-jetty/src/test/resources/jetty/webapp.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - localhost:8080 - - - http://localhost:8081/cas - - - - - - \ No newline at end of file From 40291a447874704d6392df25d7c3f6414e8533d3 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Fri, 19 Feb 2016 10:43:15 -0500 Subject: [PATCH 26/43] Issue #152 Log authentication success at INFO. --- .../main/java/org/jasig/cas/client/jetty/CasAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 513ff55..a9a3cfa 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -164,7 +164,7 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator try { logger.debug("Attempting to validate {}", ticket); final Assertion assertion = ticketValidator.validate(ticket, serviceUrl(request, response)); - logger.debug("Successfully authenticated {}", assertion.getPrincipal()); + logger.info("Successfully authenticated {}", assertion.getPrincipal()); authentication = new CasAuthentication(this, ticket, assertion); cacheAuthentication(request, authentication); } catch (Exception e) { From 812198b6a56d245a77e27ecd7aeb00751d0cd93b Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 7 Mar 2016 07:42:31 -0500 Subject: [PATCH 27/43] Issue #152 Use CommonUtils for null checks. --- .../java/org/jasig/cas/client/jetty/CasAuthentication.java | 5 +++-- .../java/org/jasig/cas/client/jetty/CasAuthenticator.java | 2 +- .../java/org/jasig/cas/client/jetty/CasUserIdentity.java | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java index 0b8fb2a..831ec75 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthentication.java @@ -1,6 +1,7 @@ package org.jasig.cas.client.jetty; import org.eclipse.jetty.security.UserAuthentication; +import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.validation.Assertion; /** @@ -26,8 +27,8 @@ public class CasAuthentication extends UserAuthentication { */ public CasAuthentication(final CasAuthenticator authenticator, final String ticket, final Assertion assertion) { super(authenticator.getAuthMethod(), new CasUserIdentity(assertion, authenticator.getRoleAttribute())); - assert ticket != null : "Ticket cannot be null"; - assert authenticator != null : "CasAuthenticator cannot be null"; + CommonUtils.assertNotNull(ticket, "Ticket cannot be null"); + CommonUtils.assertNotNull(authenticator, "CasAuthenticator cannot be null"); this.authenticator = authenticator; this.ticket = ticket; } diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index a9a3cfa..355e1d4 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -89,7 +89,7 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator * @param ticketValidator Ticket validator, MUST NOT be null. */ public void setTicketValidator(final TicketValidator ticketValidator) { - assert ticketValidator != null : "TicketValidator cannot be null"; + CommonUtils.assertNotNull(ticketValidator, "TicketValidator cannot be null"); if (ticketValidator instanceof AbstractUrlBasedTicketValidator) { if (ticketValidator instanceof AbstractCasProtocolUrlBasedTicketValidator) { protocol = Protocol.CAS2; diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java index 200e626..aee4212 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasUserIdentity.java @@ -2,6 +2,7 @@ package org.jasig.cas.client.jetty; import org.eclipse.jetty.server.UserIdentity; import org.jasig.cas.client.authentication.AttributePrincipal; +import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.validation.Assertion; import javax.security.auth.Subject; @@ -29,7 +30,7 @@ public class CasUserIdentity implements UserIdentity { * @param roleAttribute Principal attribute containing role data. */ public CasUserIdentity(final Assertion assertion, final String roleAttribute) { - assert assertion != null : "Assertion cannot be null"; + CommonUtils.assertNotNull(assertion, "Assertion cannot be null"); this.principal = assertion.getPrincipal(); this.roleAttribute = roleAttribute; } From 3f0a1c688376f3eca3a2dfc45a2199f29700d84d Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 7 Mar 2016 07:45:50 -0500 Subject: [PATCH 28/43] Issue #152 Fix javadoc typo. --- .../main/java/org/jasig/cas/client/jetty/CasAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 355e1d4..45167ca 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -67,7 +67,7 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator /** CAS ticket validator component. */ private TicketValidator ticketValidator; - /** Space-delimited ist of server names. */ + /** Space-delimited list of server names. */ private String serverNames; /** CAS principal attribute containing role data. */ From 06b566e2d6aed997b635fafff7a9c40c12266907 Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 7 Mar 2016 07:51:25 -0500 Subject: [PATCH 29/43] Issue #152 Simplify ticket lookup. --- .../jasig/cas/client/jetty/CasAuthenticator.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java index 45167ca..21d4c51 100644 --- a/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java +++ b/cas-client-integration-jetty/src/main/java/org/jasig/cas/client/jetty/CasAuthenticator.java @@ -159,7 +159,7 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator return authentication; } - final String ticket = extractTicket(request); + final String ticket = request.getParameter(protocol.getArtifactParameterName()); if (ticket != null && mandatory) { try { logger.debug("Attempting to validate {}", ticket); @@ -245,15 +245,4 @@ public class CasAuthenticator extends AbstractLifeCycle implements Authenticator throw new ServerAuthException("Redirect to CAS failed", e); } } - - private String extractTicket(final HttpServletRequest request) { - String ticket; - for (final Protocol protocol : Protocol.values()) { - ticket = request.getParameter(protocol.getArtifactParameterName()); - if (ticket != null) { - return ticket; - } - } - return null; - } } From f1908ba5fc68735a03cd8fe288ee0902da425e3a Mon Sep 17 00:00:00 2001 From: BernhardLenz Date: Mon, 28 Mar 2016 09:02:46 -0400 Subject: [PATCH 30/43] Added Tomcat client v8 to readme and notice files --- NOTICE | 1 + README.md | 53 +++++++++++++++---------- cas-client-integration-tomcat-v8/NOTICE | 2 +- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/NOTICE b/NOTICE index 1011bab..cde5123 100644 --- a/NOTICE +++ b/NOTICE @@ -39,6 +39,7 @@ This project includes: Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0 Jasig CAS Client for Java - Tomcat 6.x Integration under Apache License Version 2.0 Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0 + Jasig CAS Client for Java - Tomcat 8.x Integration under Apache License Version 2.0 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 diff --git a/README.md b/README.md index 29c66b7..637cfd3 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,15 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ``` +- Tomcat 8 is provided by this dependency: + +```xml + + org.jasig.cas + cas-client-integration-tomcat-v8 + ${java.cas.client.version} + +``` ## Configuration @@ -821,27 +830,27 @@ If you have any trouble, you can enable the log of cas in `jboss-logging.xml` by ``` - -## Tomcat 6/7 Integration + +## Tomcat 6/7/8 Integration The client supports container-based CAS authentication and authorization support for the Tomcat servlet container. 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.** +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 3 packages with similar components with the hope of supporting all 6.x, 7.x and 8.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`. +In the following discussion of components, only the Tomcat 8.x components are mentioned. The Tomcat 7.0.x and 6.0.x components have exactly the same name, but **are in the tomcat.v7 and tomcat.v6 packages**, e.g. `org.jasig.cas.client.tomcat.v7.Cas20CasAuthenticator` or `org.jasig.cas.client.tomcat.v6.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 +org.jasig.cas.client.tomcat.v8.Cas10CasAuthenticator +org.jasig.cas.client.tomcat.v8.Cas20CasAuthenticator +org.jasig.cas.client.tomcat.v8.Cas20ProxyCasAuthenticator +org.jasig.cas.client.tomcat.v8.Saml11Authenticator ``` @@ -849,8 +858,8 @@ org.jasig.cas.client.tomcat.v6.Saml11Authenticator 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 +org.jasig.cas.client.tomcat.v8.PropertiesCasRealm +org.jasig.cas.client.tomcat.v8.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. @@ -865,15 +874,15 @@ A number of Tomcat valves are provided to handle functionality outside Realms an 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 +org.jasig.cas.client.tomcat.v8.StaticUriLogoutValve +org.jasig.cas.client.tomcat.v8.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. +The `org.jasig.cas.client.tomcat.v8.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. +The `org.jasig.cas.client.tomcat.v8.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 @@ -903,11 +912,11 @@ Alternatively, CAS configuration can be applied to individual Web applications t This example also configures the container for CAS single sign-out. --> @@ -926,11 +935,11 @@ Alternatively, CAS configuration can be applied to individual Web applications t --> @@ -948,11 +957,11 @@ The following example shows how to configure a Context for dynamic role data pro The attribute used for role data is "memberOf". --> diff --git a/cas-client-integration-tomcat-v8/NOTICE b/cas-client-integration-tomcat-v8/NOTICE index f5ce3c0..4348c0c 100644 --- a/cas-client-integration-tomcat-v8/NOTICE +++ b/cas-client-integration-tomcat-v8/NOTICE @@ -19,7 +19,7 @@ This project includes: Jasig CAS Client for Java - Common Tomcat Integration Support under Apache License Version 2.0 Jasig CAS Client for Java - Core under Apache License Version 2.0 Jasig CAS Client for Java - SAML Protocol Support under Apache License Version 2.0 - Jasig CAS Client for Java - Tomcat 7.x Integration under Apache License Version 2.0 + Jasig CAS Client for Java - Tomcat 8.x Integration under Apache License Version 2.0 Java Servlet API under CDDL + GPLv2 with classpath exception JCL 1.1.1 implemented over SLF4J under MIT License Joda-Time under Apache 2 From f1cd2441cabc354c801887ff7ed7cc60ef01ae79 Mon Sep 17 00:00:00 2001 From: Carl Harris Date: Fri, 13 May 2016 11:03:11 -0400 Subject: [PATCH 31/43] change git clone URL to reflect new org slug --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 637cfd3..ce7106f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ All client artifacts are published to Maven central. Depending on functionality, ## 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 +git clone git@github.com:apereo/java-cas-client.git cd java-cas-client mvn clean package ``` From 771288475fb6efc258000229064e2b399cdbcbe3 Mon Sep 17 00:00:00 2001 From: cobolgis Date: Mon, 16 May 2016 16:04:12 +0200 Subject: [PATCH 32/43] Recommended fix for #167. --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ce7106f..48fdc21 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-support-saml ${java.cas.client.version} @@ -46,7 +46,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-support-distributed-ehcache ${java.cas.client.version} @@ -56,7 +56,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-support-distributed-memcached ${java.cas.client.version} @@ -66,7 +66,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-integration-atlassian ${java.cas.client.version} @@ -76,7 +76,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-integration-jboss ${java.cas.client.version} @@ -86,7 +86,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-integration-tomcat-v6 ${java.cas.client.version} @@ -96,7 +96,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-integration-tomcat-v7 ${java.cas.client.version} @@ -106,7 +106,7 @@ files in the modules (`cas-client-integration-jboss` and `cas-client-support-dis ```xml - org.jasig.cas + org.jasig.cas.client cas-client-integration-tomcat-v8 ${java.cas.client.version} From 7cb5380e75866800e255d5d1d39a8ad1cc54c63d Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Tue, 24 May 2016 07:53:15 -0400 Subject: [PATCH 33/43] Issue #152 Jetty integration docs. --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/README.md b/README.md index 48fdc21..a5bc844 100644 --- a/README.md +++ b/README.md @@ -976,6 +976,70 @@ The following example shows how to configure a Context for dynamic role data pro ``` + +## Jetty Integration +Since version 3.4.2, the Java CAS Client supports Jetty container integration via the following module: + +```xml + + org.jasig.cas.client + cas-client-integration-jetty + ${cas-client.version} + +``` + +Both programmatic (embedded) and context configuration are supported. + +### Jetty Embedded Configuration +``` +# CAS configuration parameters +String hostName = "app.example.com"; +String casServerBaseUrl = "cas.example.com/cas"; +String casRoleAttribute = "memberOf"; +boolean casRenew = false; +int casTolerance = 5000; + +# Jetty wiring +WebAppContext context = new WebAppContext("/path/to/context", "contextPath"); +context.setTempDirectory("/tmp/jetty/work")); +context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false"); +SessionCookieConfig config = context.getSessionHandler().getSessionManager().getSessionCookieConfig(); +config.setHttpOnly(true); +config.setSecure(true); +Saml11TicketValidator validator = new Saml11TicketValidator(casServerBaseUrl); +validator.setRenew(casRenew); +validator.setTolerance(casTolerance); +CasAuthenticator authenticator = new CasAuthenticator(); +authenticator.setRoleAttribute(casRoleAttribute); +authenticator.setServerNames(hostName); +authenticator.setTicketValidator(validator); +context.getSecurityHandler().setAuthenticator(authenticator); +``` + +### Jetty Context Configuration +```xml + + + + + / + /webapps/yourapp + + + + app.example.com + + + https://cas.example.com/cas + + + + + + + +``` + ## Atlassian Integration The clien includes Atlassian Confluence and JIRA support. Support is enabled by a custom CAS authenticator that extends the default authenticators. From 2e27e09f3b4fbe36badc1a205eede4d62e2cd4bb Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Thu, 1 Sep 2016 13:22:01 -0400 Subject: [PATCH 34/43] Log proxy ticket returned from /proxy protocol endpoint. --- .../java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 e80304a..21c770b 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 @@ -94,7 +94,9 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { return null; } - return XmlUtils.getTextForElement(response, "proxyTicket"); + final String ticket = XmlUtils.getTextForElement(response, "proxyTicket"); + logger.debug("Got proxy ticket {}", ticket); + return ticket; } private URL constructUrl(final String proxyGrantingTicketId, final String targetService) { From 9b71825e1a3104f03c490ba8a82ef0c20466a84f Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 7 Sep 2016 15:31:39 +0430 Subject: [PATCH 35/43] Let config keys log the name --- .../org/jasig/cas/client/configuration/ConfigurationKey.java | 5 +++++ 1 file changed, 5 insertions(+) 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 da6a3a1..3e22b2e 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 @@ -60,4 +60,9 @@ public final class ConfigurationKey { public E getDefaultValue() { return this.defaultValue; } + + @Override + public String toString() { + return getName(); + } } From 745fda61136afe622d44fd2410c2def6386420fa Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 7 Sep 2016 15:38:46 +0430 Subject: [PATCH 36/43] Minor code adjustments to CommonUtils to use String.isEmpty() --- .../java/org/jasig/cas/client/util/CommonUtils.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 639b3b4..7a11e8e 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 @@ -135,7 +135,7 @@ public final class CommonUtils { * @return true if its null or length of 0, false otherwise. */ public static boolean isEmpty(final String string) { - return string == null || string.length() == 0; + return string == null || string.isEmpty(); } /** @@ -157,7 +157,7 @@ public final class CommonUtils { * @return true if its blank, false otherwise. */ public static boolean isBlank(final String string) { - return isEmpty(string) || string.trim().length() == 0; + return isEmpty(string) || string.trim().isEmpty(); } /** @@ -193,7 +193,7 @@ public final class CommonUtils { * @param value the value to encode. * @return the encoded value. */ - public static String urlEncode(String value) { + public static String urlEncode(final String value) { try { return URLEncoder.encode(value, "UTF-8"); } catch (final UnsupportedEncodingException e) { @@ -228,7 +228,7 @@ public final class CommonUtils { protected static String findMatchingServerName(final HttpServletRequest request, final String serverName) { final String[] serverNames = serverName.split(" "); - if (serverNames == null || serverNames.length == 0 || serverNames.length == 1) { + if (serverNames.length == 0 || serverNames.length == 1) { return serverName; } @@ -323,7 +323,7 @@ public final class CommonUtils { final URIBuilder originalRequestUrl = new URIBuilder(request.getRequestURL().toString(), encode); originalRequestUrl.setParameters(request.getQueryString()); - URIBuilder builder = null; + final URIBuilder builder; boolean containsScheme = true; if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) { From 9d4cafd2c9de4e8cba63d0752bdde5e13bb09a6d Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 7 Sep 2016 15:47:04 +0430 Subject: [PATCH 37/43] Let assertion validity checks to be more flexible when comparing dates. --- .../java/org/jasig/cas/client/validation/AssertionImpl.java | 6 ++++++ .../org/jasig/cas/client/validation/AssertionImplTests.java | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java index 86e286f..14064c1 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java @@ -101,26 +101,32 @@ public final class AssertionImpl implements Assertion { CommonUtils.assertNotNull(this.attributes, "attributes cannot be null."); } + @Override public Date getAuthenticationDate() { return this.authenticationDate; } + @Override public Date getValidFromDate() { return this.validFromDate; } + @Override public Date getValidUntilDate() { return this.validUntilDate; } + @Override public Map getAttributes() { return this.attributes; } + @Override public AttributePrincipal getPrincipal() { return this.principal; } + @Override public boolean isValid() { if (this.validFromDate == null) { return true; diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java index de6e856..b175523 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java @@ -49,6 +49,11 @@ public final class AssertionImplTests extends TestCase { assertNull(assertion.getPrincipal().getProxyTicketFor("test")); } + public void testAssertionValidity() throws Exception { + final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, CONST_ATTRIBUTES); + assertTrue(assertion.isValid()); + } + public void testCompleteConstructor() { final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, CONST_ATTRIBUTES); From 9e95ee5825589c01221144f3153ddaf0f7a0134b Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 7 Sep 2016 16:10:16 +0430 Subject: [PATCH 38/43] Handle date equality when checking for saml assertion validity --- .../java/org/jasig/cas/client/validation/AssertionImpl.java | 3 ++- .../org/jasig/cas/client/validation/AssertionImplTests.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java index 14064c1..da40aba 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AssertionImpl.java @@ -133,6 +133,7 @@ public final class AssertionImpl implements Assertion { } final Date now = new Date(); - return this.validFromDate.before(now) && (this.validUntilDate == null || this.validUntilDate.after(now)); + return (this.validFromDate.before(now) || this.validFromDate.equals(now)) + && (this.validUntilDate == null || this.validUntilDate.after(now) || this.validUntilDate.equals(now)); } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java index b175523..335dbe6 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/AssertionImplTests.java @@ -18,6 +18,7 @@ */ package org.jasig.cas.client.validation; +import java.util.Date; import java.util.HashMap; import java.util.Map; import junit.framework.TestCase; @@ -50,7 +51,7 @@ public final class AssertionImplTests extends TestCase { } public void testAssertionValidity() throws Exception { - final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, CONST_ATTRIBUTES); + final Assertion assertion = new AssertionImpl(CONST_PRINCIPAL, new Date(), new Date(), new Date(), CONST_ATTRIBUTES); assertTrue(assertion.isValid()); } From 92371f794a50f8884f2620ce015c6e2d2aabddc3 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 7 Sep 2016 16:12:34 +0430 Subject: [PATCH 39/43] Remove redundant groupId from POM defns --- cas-client-core/pom.xml | 1 - cas-client-integration-atlassian/pom.xml | 1 - cas-client-integration-jboss/pom.xml | 1 - cas-client-integration-jetty/pom.xml | 1 - cas-client-integration-tomcat-common/pom.xml | 1 - cas-client-integration-tomcat-v6/pom.xml | 1 - cas-client-integration-tomcat-v7/pom.xml | 1 - cas-client-integration-tomcat-v8/pom.xml | 1 - cas-client-support-distributed-memcached/pom.xml | 1 - cas-client-support-saml/pom.xml | 1 - 10 files changed, 10 deletions(-) diff --git a/cas-client-core/pom.xml b/cas-client-core/pom.xml index ea484e1..ead56f8 100644 --- a/cas-client-core/pom.xml +++ b/cas-client-core/pom.xml @@ -5,7 +5,6 @@ cas-client 4.0.0 - org.jasig.cas.client cas-client-core jar Jasig CAS Client for Java - Core diff --git a/cas-client-integration-atlassian/pom.xml b/cas-client-integration-atlassian/pom.xml index 0a36f5c..e9193cb 100644 --- a/cas-client-integration-atlassian/pom.xml +++ b/cas-client-integration-atlassian/pom.xml @@ -5,7 +5,6 @@ cas-client 4.0.0 - org.jasig.cas.client cas-client-integration-atlassian jar Jasig CAS Client for Java - Atlassian Integration diff --git a/cas-client-integration-jboss/pom.xml b/cas-client-integration-jboss/pom.xml index 62561d5..b1cc9f8 100644 --- a/cas-client-integration-jboss/pom.xml +++ b/cas-client-integration-jboss/pom.xml @@ -5,7 +5,6 @@ cas-client 4.0.0 - org.jasig.cas.client cas-client-integration-jboss jar Jasig CAS Client for Java - JBoss Integration diff --git a/cas-client-integration-jetty/pom.xml b/cas-client-integration-jetty/pom.xml index 480acbe..c97cb12 100644 --- a/cas-client-integration-jetty/pom.xml +++ b/cas-client-integration-jetty/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client cas-client-integration-jetty jar Jasig CAS Client for Java - Jetty Container Integration diff --git a/cas-client-integration-tomcat-common/pom.xml b/cas-client-integration-tomcat-common/pom.xml index 337ca4f..88e5eff 100644 --- a/cas-client-integration-tomcat-common/pom.xml +++ b/cas-client-integration-tomcat-common/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client cas-client-integration-tomcat-common jar Jasig CAS Client for Java - Common Tomcat Integration Support diff --git a/cas-client-integration-tomcat-v6/pom.xml b/cas-client-integration-tomcat-v6/pom.xml index 15e34df..e4e7a41 100644 --- a/cas-client-integration-tomcat-v6/pom.xml +++ b/cas-client-integration-tomcat-v6/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client cas-client-integration-tomcat-v6 jar Jasig CAS Client for Java - Tomcat 6.x Integration diff --git a/cas-client-integration-tomcat-v7/pom.xml b/cas-client-integration-tomcat-v7/pom.xml index ea870cb..5a3355c 100644 --- a/cas-client-integration-tomcat-v7/pom.xml +++ b/cas-client-integration-tomcat-v7/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client cas-client-integration-tomcat-v7 jar Jasig CAS Client for Java - Tomcat 7.x Integration diff --git a/cas-client-integration-tomcat-v8/pom.xml b/cas-client-integration-tomcat-v8/pom.xml index 531abde..5dabb76 100644 --- a/cas-client-integration-tomcat-v8/pom.xml +++ b/cas-client-integration-tomcat-v8/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client cas-client-integration-tomcat-v8 jar Jasig CAS Client for Java - Tomcat 8.x Integration diff --git a/cas-client-support-distributed-memcached/pom.xml b/cas-client-support-distributed-memcached/pom.xml index bdd7986..e4eb1c2 100644 --- a/cas-client-support-distributed-memcached/pom.xml +++ b/cas-client-support-distributed-memcached/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.jasig.cas.client jar cas-client-support-distributed-memcached Jasig CAS Client for Java - Distributed Proxy Storage Support: diff --git a/cas-client-support-saml/pom.xml b/cas-client-support-saml/pom.xml index ce40fd9..d42ce3d 100644 --- a/cas-client-support-saml/pom.xml +++ b/cas-client-support-saml/pom.xml @@ -5,7 +5,6 @@ cas-client 4.0.0 - org.jasig.cas.client cas-client-support-saml jar Jasig CAS Client for Java - SAML Protocol Support From 7db200e8c6e58fd2f23229c681e7a43e86032746 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Fri, 9 Sep 2016 16:14:06 +0430 Subject: [PATCH 40/43] Updated front-channel SLO handling --- .../configuration/ConfigurationKeys.java | 1 - .../client/session/SingleSignOutFilter.java | 7 +- .../client/session/SingleSignOutHandler.java | 125 +++++------------- ...0ProxyReceivingTicketValidationFilter.java | 2 +- .../session/SingleSignOutFilterTests.java | 54 ++++---- .../session/SingleSignOutHandlerTests.java | 1 - .../client/tomcat/v6/SingleSignOutValve.java | 6 +- .../client/tomcat/v7/SingleSignOutValve.java | 6 +- .../client/tomcat/v8/SingleSignOutValve.java | 6 +- 9 files changed, 67 insertions(+), 141 deletions(-) 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 14ec120..109aadd 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 @@ -77,6 +77,5 @@ public interface ConfigurationKeys { 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/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index 5720a69..25d645c 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 @@ -46,7 +46,6 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { if (!isIgnoreInitConfiguration()) { 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)); @@ -63,11 +62,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { public void setLogoutParameterName(final String name) { HANDLER.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - HANDLER.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { HANDLER.setRelayStateParameterName(name); } 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 de13582..26932db 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 @@ -57,12 +57,9 @@ public final class SingleSignOutHandler { /** The name of the artifact parameter. This is used to capture the session identifier. */ private String artifactParameterName = Protocol.CAS2.getArtifactParameterName(); - /** Parameter name that stores logout request for back channel SLO */ + /** Parameter name that stores logout request for SLO */ private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(); - - /** Parameter name that stores logout request for front channel SLO */ - 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 = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(); @@ -75,7 +72,7 @@ public final class SingleSignOutHandler { private List safeParameters; - private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy(); + private final LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy(); public void setSessionMappingStorage(final SessionMappingStorage storage) { this.sessionMappingStorage = storage; @@ -97,7 +94,7 @@ public final class SingleSignOutHandler { } /** - * @param name Name of parameter containing CAS logout request message for back channel SLO. + * @param name Name of parameter containing CAS logout request message for SLO. */ public void setLogoutParameterName(final String name) { this.logoutParameterName = name; @@ -109,14 +106,7 @@ public final class SingleSignOutHandler { public void setCasServerUrlPrefix(final String casServerUrlPrefix) { this.casServerUrlPrefix = casServerUrlPrefix; } - - /** - * @param name Name of parameter containing CAS logout request message for front channel SLO. - */ - public void setFrontLogoutParameterName(final String name) { - this.frontLogoutParameterName = name; - } - + /** * @param name Name of parameter containing the state of the CAS server webflow. */ @@ -135,7 +125,6 @@ public final class SingleSignOutHandler { 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."); @@ -165,32 +154,25 @@ public final class SingleSignOutHandler { } /** - * Determines whether the given request is a CAS back channel logout request. + * Determines whether the given request is a CAS logout request. * * @param request HTTP request. * * @return True if request is logout request, false otherwise. */ - private boolean isBackChannelLogoutRequest(final HttpServletRequest request) { - return "POST".equals(request.getMethod()) - && !isMultipartRequest(request) - && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, - this.safeParameters)); + private boolean isLogoutRequest(final HttpServletRequest request) { + if ("POST".equalsIgnoreCase(request.getMethod())) { + return !isMultipartRequest(request) + && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, + this.safeParameters)); + } + + if ("GET".equalsIgnoreCase(request.getMethod())) { + return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters)); + } + return false; } - - /** - * 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()) && CommonUtils.isNotBlank(this.casServerUrlPrefix) - && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.frontLogoutParameterName)); - } - + /** * Process a request regarding the SLO process: record the session or destroy it. * @@ -203,26 +185,15 @@ public final class SingleSignOutHandler { logger.trace("Received a token request"); recordSession(request); return true; - - } else if (isBackChannelLogoutRequest(request)) { - logger.trace("Received a back channel logout request"); + } + + if (isLogoutRequest(request)) { + logger.trace("Received a logout request"); destroySession(request); return false; - - } else if (isFrontChannelLogoutRequest(request)) { - logger.trace("Received a front channel logout request"); - destroySession(request); - // redirection url to the CAS server - final String redirectionUrl = computeRedirectionToServer(request); - if (redirectionUrl != null) { - CommonUtils.sendRedirect(response, redirectionUrl); - } - return false; - - } else { - logger.trace("Ignoring URI for logout: {}", request.getRequestURI()); - return true; - } + } + logger.trace("Ignoring URI for logout: {}", request.getRequestURI()); + return true; } /** @@ -245,7 +216,7 @@ public final class SingleSignOutHandler { try { this.sessionMappingStorage.removeBySessionById(session.getId()); } catch (final Exception e) { - // ignore if the session is already marked as invalid. Nothing we can do! + // ignore if the session is already marked as invalid. Nothing we can do! } sessionMappingStorage.addSessionById(token, session); } @@ -286,16 +257,17 @@ public final class SingleSignOutHandler { * @param request HTTP request containing a CAS logout message. */ private void destroySession(final HttpServletRequest request) { - final String logoutMessage; - // front channel logout -> the message needs to be base64 decoded + decompressed - if (isFrontChannelLogoutRequest(request)) { - logoutMessage = uncompressLogoutMessage(CommonUtils.safeGetParameter(request, - this.frontLogoutParameterName)); - } else { - logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters); + String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters); + if (CommonUtils.isBlank(logoutMessage)) { + logger.error("Could not locate logout message of the request from {}", this.logoutParameterName); + return; } + + if (!logoutMessage.contains("SessionIndex")) { + logoutMessage = uncompressLogoutMessage(logoutMessage); + } + logger.trace("Logout request:\n{}", logoutMessage); - final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex"); if (CommonUtils.isNotBlank(token)) { final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token); @@ -314,33 +286,6 @@ public final class SingleSignOutHandler { } } - /** - * Compute the redirection url to the CAS server when it's a front channel SLO - * (depending on the relay state parameter). - * - * @param request The HTTP request. - * @return the redirection url to the CAS server. - */ - private String computeRedirectionToServer(final HttpServletRequest request) { - final String relayStateValue = CommonUtils.safeGetParameter(request, this.relayStateParameterName); - // if we have a state value -> redirect to the CAS server to continue the logout process - if (CommonUtils.isNotBlank(relayStateValue)) { - final StringBuilder buffer = new StringBuilder(); - buffer.append(casServerUrlPrefix); - if (!this.casServerUrlPrefix.endsWith("/")) { - buffer.append("/"); - } - buffer.append("logout?_eventId=next&"); - buffer.append(this.relayStateParameterName); - buffer.append("="); - buffer.append(CommonUtils.urlEncode(relayStateValue)); - final String redirectUrl = buffer.toString(); - logger.debug("Redirection url to the CAS server: {}", redirectUrl); - return redirectUrl; - } - return null; - } - private boolean isMultipartRequest(final HttpServletRequest request) { return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart"); } 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 5fe1337..22cb830 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 @@ -54,7 +54,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal 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() + PROXY_CALLBACK_URL.getName(), RELAY_STATE_PARAMETER_NAME.getName() }; /** 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 93fd665..1a4f4e4 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 @@ -84,32 +84,32 @@ public class SingleSignOutFilterTests { assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); } - @Test - public void frontChannelRequest() throws IOException, ServletException { - final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - 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); - filter.doFilter(request, response, filterChain); - assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); - assertNull(response.getRedirectedUrl()); - } +// @Test +// public void frontChannelRequest() throws IOException, ServletException { +// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); +// 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); +// filter.doFilter(request, response, filterChain); +// assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); +// assertNull(response.getRedirectedUrl()); +// } - @Test - public void frontChannelRequestRelayState() throws IOException, ServletException { - final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - 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&" + - ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); - } +// @Test +// public void frontChannelRequestRelayState() throws IOException, ServletException { +// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); +// 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&" + +// ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); +// } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java index 365a25e..661cb61 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java @@ -52,7 +52,6 @@ public final class SingleSignOutHandlerTests { public void setUp() throws Exception { handler = new SingleSignOutHandler(); handler.setLogoutParameterName(LOGOUT_PARAMETER_NAME); - handler.setFrontLogoutParameterName(FRONT_LOGOUT_PARAMETER_NAME); handler.setRelayStateParameterName(RELAY_STATE_PARAMETER_NAME); handler.setArtifactParameterName(ARTIFACT_PARAMETER_NAME); handler.setCasServerUrlPrefix(URL); diff --git a/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java b/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java index 9941651..00c63dc 100644 --- a/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java @@ -51,11 +51,7 @@ public class SingleSignOutValve extends AbstractLifecycleValve implements Sessio public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); } diff --git a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java index 62ac214..e7cd85d 100644 --- a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java @@ -55,11 +55,7 @@ public class SingleSignOutValve extends ValveBase implements SessionListener { public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); } diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java index 02fe955..de77527 100644 --- a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java @@ -55,11 +55,7 @@ public class SingleSignOutValve extends ValveBase implements SessionListener { public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); } From 6be07281d598a43fc872e942c70f26ed84d8e5ce Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Fri, 9 Sep 2016 16:22:32 +0430 Subject: [PATCH 41/43] Fixed test cases --- .../session/SingleSignOutFilterTests.java | 52 +++++++++---------- .../session/SingleSignOutHandlerTests.java | 20 +++---- 2 files changed, 33 insertions(+), 39 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 1a4f4e4..a5af91a 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 @@ -84,32 +84,30 @@ public class SingleSignOutFilterTests { assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); } -// @Test -// public void frontChannelRequest() throws IOException, ServletException { -// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); -// 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); -// filter.doFilter(request, response, filterChain); -// assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); -// assertNull(response.getRedirectedUrl()); -// } + @Test + public void frontChannelRequest() throws IOException, ServletException { + final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); + request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); + request.setQueryString(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage); + 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)); + assertNull(response.getRedirectedUrl()); + } -// @Test -// public void frontChannelRequestRelayState() throws IOException, ServletException { -// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); -// 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&" + -// ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); -// } + @Test + public void frontChannelRequestRelayState() throws IOException, ServletException { + final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); + request.setParameter(ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); + request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE); + request.setQueryString(ConfigurationKeys.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)); + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java index 661cb61..164a362 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java @@ -31,7 +31,6 @@ import org.springframework.mock.web.MockHttpSession; /** * @author Matt Brown - * @version $Revision$ $Date$ * @since 3.2.1 */ public final class SingleSignOutHandlerTests { @@ -39,9 +38,8 @@ public final class SingleSignOutHandlerTests { private final static String ANOTHER_PARAMETER = "anotherParameter"; private final static String TICKET = "ST-xxxxxxxx"; private final static String URL = "http://mycasserver"; - private final static String LOGOUT_PARAMETER_NAME = "logoutRequest2"; - private final static String FRONT_LOGOUT_PARAMETER_NAME = "SAMLRequest2"; - private final static String RELAY_STATE_PARAMETER_NAME = "RelayState2"; + private final static String LOGOUT_PARAMETER_NAME = "logoutRequest"; + private final static String RELAY_STATE_PARAMETER_NAME = "RelayState"; private final static String ARTIFACT_PARAMETER_NAME = "ticket2"; private SingleSignOutHandler handler; @@ -142,8 +140,8 @@ public final class SingleSignOutHandlerTests { @Test public void frontChannelLogoutFailsIfNoSessionIndex() { final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(""); - request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage); - request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage); + request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage); + request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage); request.setMethod("GET"); final MockHttpSession session = new MockHttpSession(); handler.getSessionMappingStorage().addSessionById(TICKET, session); @@ -154,8 +152,8 @@ public final class SingleSignOutHandlerTests { @Test public void frontChannelLogoutOK() { final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage); - request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage); + request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage); + request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage); request.setMethod("GET"); final MockHttpSession session = new MockHttpSession(); handler.getSessionMappingStorage().addSessionById(TICKET, session); @@ -167,15 +165,13 @@ public final class SingleSignOutHandlerTests { @Test public void frontChannelLogoutRelayStateOK() { final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(FRONT_LOGOUT_PARAMETER_NAME, logoutMessage); + request.setParameter(LOGOUT_PARAMETER_NAME, logoutMessage); request.setParameter(RELAY_STATE_PARAMETER_NAME, TICKET); - request.setQueryString(FRONT_LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET); + request.setQueryString(LOGOUT_PARAMETER_NAME + "=" + logoutMessage + "&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET); request.setMethod("GET"); final MockHttpSession session = new MockHttpSession(); handler.getSessionMappingStorage().addSessionById(TICKET, session); assertFalse(handler.process(request, response)); assertTrue(session.isInvalid()); - assertEquals(URL + "/logout?_eventId=next&" + RELAY_STATE_PARAMETER_NAME + "=" + TICKET, - response.getRedirectedUrl()); } } From 47fb9c0fbb2d7ad673351e844589bcbfca15a8ab Mon Sep 17 00:00:00 2001 From: lizhixiang Date: Thu, 5 Jan 2017 12:16:16 +0800 Subject: [PATCH 42/43] add setter to ignoreUrlPatternMatcherStrategyClass, with purpose of injecting UrlPatternMatcherStrategy to AuthenticationFilter by Spring IOC --- .../cas/client/authentication/AuthenticationFilter.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 d5e7fe4..f460c88 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 @@ -212,4 +212,10 @@ public class AuthenticationFilter extends AbstractCasFilter { final String requestUri = urlBuffer.toString(); return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri); } + + public final void setIgnoreUrlPatternMatcherStrategyClass( + final UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass) { + this.ignoreUrlPatternMatcherStrategyClass = ignoreUrlPatternMatcherStrategyClass; + } + } From 1561da75ad6a925d4b4e0a45fee68d42348ffb64 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Tue, 25 Apr 2017 09:28:10 -0700 Subject: [PATCH 43/43] Fix formatting issues with the markdown title --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5bc844..ebdfe9f 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ The SAML 1.1 `AuthenticationFilter` is what detects whether a user needs to be a | `encodeServiceUrl ` | Whether the client should auto encode the service url. Defaults to `true` | No -####org.jasig.cas.client.validation.Cas10TicketValidationFilter +#### org.jasig.cas.client.validation.Cas10TicketValidationFilter Validates tickets using the CAS 1.0 Protocol. ```xml