From b54cd179e2aeb462184d3819d5f1098a29081776 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 24 Jan 2013 12:01:47 -0700 Subject: [PATCH 01/10] CASC-180 - Add support for Client Side Certificates In order to utilize client side certificates, this commit facilitates the creation of a SSLSocketFactory on HttpsURLConnection for the client. The configuration is encapsulated inside a url factory instance that applies the adjustments where necessary. This commit is continuation of the posted pending pull on github that is at: https://github.com/Jasig/java-cas-client/pull/26 ...and applies the suggestions and fixes that were brought to light during the code review. --- .../cas/client/proxy/Cas20ProxyRetriever.java | 5 +- .../jasig/cas/client/util/CommonUtils.java | 46 ++++--- .../util/HttpsURLConnectionFactory.java | 126 ++++++++++++++++++ .../cas/client/util/URLConnectionFactory.java | 44 ++++++ ...actCasProtocolUrlBasedTicketValidator.java | 6 +- .../AbstractTicketValidationFilter.java | 27 ++++ .../AbstractUrlBasedTicketValidator.java | 28 ++-- .../Cas10TicketValidationFilter.java | 7 +- ...0ProxyReceivingTicketValidationFilter.java | 5 +- .../Saml11TicketValidationFilter.java | 8 +- .../validation/Saml11TicketValidator.java | 21 ++- pom.xml | 2 + 12 files changed, 269 insertions(+), 56 deletions(-) create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java create mode 100644 cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java 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 2910f5f..42c21ef 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 @@ -29,20 +29,19 @@ import java.net.URLEncoder; /** * Implementation of a ProxyRetriever that follows the CAS 2.0 specification. * For more information on the CAS 2.0 specification, please see the specification + * href="http://www.jasig.org/cas/protocol">specification * document. *

* In general, this class will make a call to the CAS server with some specified * parameters and receive an XML response to parse. * * @author Scott Battaglia - * @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $ * @since 3.0 */ public final class Cas20ProxyRetriever implements ProxyRetriever { /** Unique Id for serialization. */ - private static final long serialVersionUID = 560409469568911791L; + private static final long serialVersionUID = 560409469568911791L; /** * Instance of Commons Logging. 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 91a3aaa..9f30256 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 @@ -24,20 +24,20 @@ import org.jasig.cas.client.validation.ProxyListEditor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.Closeable; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URLConnection; import java.net.URLEncoder; import java.net.URL; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; @@ -323,28 +323,16 @@ public final class CommonUtils { * Contacts the remote URL and returns the response. * * @param constructedUrl the url to contact. + * @param factory connection factory to prepare the URL connection instance * @param encoding the encoding to use. * @return the response. */ - public static String getResponseFromServer(final URL constructedUrl, final String encoding) { - return getResponseFromServer(constructedUrl, HttpsURLConnection.getDefaultHostnameVerifier(), encoding); - } + public static String getResponseFromServer(final URL constructedUrl, final URLConnectionFactory factory, final String encoding) { - /** - * Contacts the remote URL and returns the response. - * - * @param constructedUrl the url to contact. - * @param hostnameVerifier Host name verifier to use for HTTPS connections. - * @param encoding the encoding to use. - * @return the response. - */ - public static String getResponseFromServer(final URL constructedUrl, final HostnameVerifier hostnameVerifier, final String encoding) { URLConnection conn = null; try { - conn = constructedUrl.openConnection(); - if (conn instanceof HttpsURLConnection) { - ((HttpsURLConnection)conn).setHostnameVerifier(hostnameVerifier); - } + conn = factory.getURLConnection(constructedUrl.openConnection()); + final BufferedReader in; if (CommonUtils.isEmpty(encoding)) { @@ -371,6 +359,7 @@ public final class CommonUtils { } } + /** * Contacts the remote URL and returns the response. * @@ -380,12 +369,12 @@ public final class CommonUtils { */ public static String getResponseFromServer(final String url, String encoding) { try { - return getResponseFromServer(new URL(url), encoding); + return getResponseFromServer(new URL(url), new HttpsURLConnectionFactory(), encoding); } catch (final MalformedURLException e) { throw new IllegalArgumentException(e); } } - + public static ProxyList createProxyList(final String proxies) { if (CommonUtils.isBlank(proxies)) { return new ProxyList(); @@ -410,4 +399,19 @@ public final class CommonUtils { } } + + /** + * Unconditionally close a {@link Closeable}. Equivalent to {@link java.io.Closeable#close()}close(), except any exceptions + * will be ignored. This is typically used in finally blocks. + * @param resource + */ + public static void closeQuietly(final Closeable resource) { + try { + if (resource != null) { + resource.close(); + } + } catch (final IOException e) { + //ignore + } + } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java new file mode 100644 index 0000000..e87335a --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java @@ -0,0 +1,126 @@ +package org.jasig.cas.client.util; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URLConnection; +import java.security.KeyStore; +import java.util.Properties; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of the {@link URLConnectionFactory} whose responsible to configure + * the underlying https connection, if needed, with a given hostname and SSL socket factory based on the + * configuration provided. + * + * @author Misagh Moayyed + * @since 3.3 + * @see #setHostnameVerifier(HostnameVerifier) + * @see #setSSLConfiguration(Properties) + */ +public final class HttpsURLConnectionFactory implements URLConnectionFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class); + + /** + * Hostname verifier used when making an SSL request to the CAS server. + * Defaults to {@link HttpsURLConnection#getDefaultHostnameVerifier()} + */ + private HostnameVerifier hostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + + /** + * Properties file that can contains key/trust info for Client Side Certificates + */ + private Properties sslConfiguration = new Properties(); + + public HttpsURLConnectionFactory() {} + + public HttpsURLConnectionFactory(final HostnameVerifier verifier, final Properties config) { + setHostnameVerifier(verifier); + setSSLConfiguration(config); + } + + public final void setSSLConfiguration(final Properties config) { + this.sslConfiguration = config; + } + + public final void setHostnameVerifier(final HostnameVerifier verifier) { + this.hostnameVerifier = verifier; + } + + public URLConnection getURLConnection(final URLConnection url) { + return this.configureHttpsConnectionIfNeeded(url); + } + + /** + * Configures the connection with specific settings for secure http connections + * If the connection instance is not a {@link HttpsURLConnection}, + * no additional changes will be made and the connection itself is simply returned. + * + * @param conn the http connection + */ + private URLConnection configureHttpsConnectionIfNeeded(final URLConnection conn) { + if (conn instanceof HttpsURLConnection) { + final HttpsURLConnection httpsConnection = (HttpsURLConnection) conn; + final SSLSocketFactory socketFactory = this.createSSLSocketFactory(); + if (socketFactory != null) { + httpsConnection.setSSLSocketFactory(socketFactory); + } + + if (this.hostnameVerifier != null) { + httpsConnection.setHostnameVerifier(this.hostnameVerifier); + } + } + return conn; + } + + /** + * Creates a {@link SSLSocketFactory} based on the configuration specified + *

+ * Sample properties file: + *

+     * protocol=TLS
+     * keyStoreType=JKS
+     * keyStorePath=/var/secure/location/.keystore
+     * keyStorePass=changeit
+     * certificatePassword=aGoodPass
+     * 
+ * @param sslConfig {@link Properties} + * @return the {@link SSLSocketFactory} + */ + private SSLSocketFactory createSSLSocketFactory() { + InputStream keyStoreIS = null; + try { + final SSLContext sslContext = SSLContext.getInstance(this.sslConfiguration.getProperty("protocol", "SSL")); + + if (this.sslConfiguration.getProperty("keyStoreType") != null) { + final KeyStore keyStore = KeyStore.getInstance(this.sslConfiguration.getProperty("keyStoreType")); + if (this.sslConfiguration.getProperty("keyStorePath") != null) { + keyStoreIS = new FileInputStream(this.sslConfiguration.getProperty("keyStorePath")); + if (this.sslConfiguration.getProperty("keyStorePass") != null) { + keyStore.load(keyStoreIS, this.sslConfiguration.getProperty("keyStorePass").toCharArray()); + LOGGER.debug("Keystore has {} keys", keyStore.size()); + final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(this.sslConfiguration.getProperty("keyManagerType", "SunX509")); + keyManager.init(keyStore, this.sslConfiguration.getProperty("certificatePassword").toCharArray()); + sslContext.init(keyManager.getKeyManagers(), null, null); + } + } + } + + return sslContext.getSocketFactory(); + } catch (final Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + CommonUtils.closeQuietly(keyStoreIS); + } + return null; + } + +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java new file mode 100644 index 0000000..9a08fe0 --- /dev/null +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java @@ -0,0 +1,44 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.util; + +import java.net.URL; +import java.net.URLConnection; + +/** + * A factory to prepare and configure {@link java.net.URLConnection} instances. + * + * @author Misagh Moayyed + * @since 3.3 + */ +public interface URLConnectionFactory { + + /** + * Receives a {@link URLConnection} instance typically as a result of a {@link URL} + * opening a connection to a remote resource. The received url connection is then + * configured and prepared appropriately depending on its type and is then returned to the caller + * to accommodate method chaining. + * + * @param url The url connection that needs to be configured + * @return The configured {@link URLConnection} instance + * + * @see {@link HttpsURLConnectionFactory} + */ + URLConnection getURLConnection(final URLConnection url); +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java index 7e736d7..c19ec9f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractCasProtocolUrlBasedTicketValidator.java @@ -43,10 +43,6 @@ public abstract class AbstractCasProtocolUrlBasedTicketValidator extends Abstrac * Retrieves the response from the server by opening a connection and merely reading the response. */ protected final String retrieveResponseFromServer(final URL validationUrl, final String ticket) { - if (this.hostnameVerifier != null) { - return CommonUtils.getResponseFromServer(validationUrl, this.hostnameVerifier, getEncoding()); - } else { - return CommonUtils.getResponseFromServer(validationUrl, getEncoding()); - } + return CommonUtils.getResponseFromServer(validationUrl, getURLConnectionFactory(), getEncoding()); } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java index 00339b4..5edabb9 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java @@ -31,6 +31,8 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.FileInputStream; +import java.util.Properties; /** * The filter that handles all the work of validating ticket requests. @@ -81,6 +83,31 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { return this.ticketValidator; } + /** + * Gets the ssl config to use for HTTPS connections + * if one is configured for this filter. + * @param filterConfig Servlet filter configuration. + * @return Properties that can contains key/trust info for Client Side Certificates + */ + protected Properties getSSLConfig(final FilterConfig filterConfig) { + final Properties properties = new Properties(); + final String fileName = getPropertyFromInitParams(filterConfig, "sslConfigFile", null); + + if (fileName != null) { + FileInputStream fis = null; + try { + fis = new FileInputStream(fileName); + properties.load(fis); + logger.trace("Loaded {} entries from {}", properties.size(), fileName); + } catch(final IOException ioe) { + logger.error(ioe.getMessage(), ioe); + } finally { + CommonUtils.closeQuietly(fis); + } + } + return properties; + } + /** * Gets the configured {@link HostnameVerifier} to use for HTTPS connections * if one is configured for this filter. diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index 5606ac5..b1df5ad 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -19,6 +19,8 @@ package org.jasig.cas.client.validation; import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.HttpsURLConnectionFactory; +import org.jasig.cas.client.util.URLConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,24 +31,22 @@ import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; -import javax.net.ssl.HostnameVerifier; - /** * Abstract validator implementation for tickets that must be validated against a server. * * @author Scott Battaglia - * @version $Revision$ $Date$ * @since 3.1 */ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator { protected final Logger logger = LoggerFactory.getLogger(getClass()); - + /** - * Hostname verifier used when making an SSL request to the CAS server. + * URLConnection factory instance to use when making validation requests to the CAS server. + * Defaults to {@link HttpsURLConnectionFactory} */ - protected HostnameVerifier hostnameVerifier; - + private URLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory(); + /** * Prefix for the CAS server. Should be everything up to the url endpoint, including the /. * @@ -217,10 +217,6 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator public final void setCustomParameters(final Map customParameters) { this.customParameters = customParameters; } - - public final void setHostnameVerifier(final HostnameVerifier verifier) { - this.hostnameVerifier = verifier; - } public final void setEncoding(final String encoding) { this.encoding = encoding; @@ -241,4 +237,12 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator protected final Map getCustomParameters() { return this.customParameters; } -} \ No newline at end of file + + protected URLConnectionFactory getURLConnectionFactory() { + return this.urlConnectionFactory; + } + + public void setURLConnectionFactory(final URLConnectionFactory urlConnectionFactory) { + this.urlConnectionFactory = urlConnectionFactory; + } +} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java index 657f1e8..dc910c3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java @@ -20,6 +20,9 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; +import org.jasig.cas.client.util.HttpsURLConnectionFactory; +import org.jasig.cas.client.util.URLConnectionFactory; + /** * Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator. *

Deployers can provide the "casServerPrefix" and the "renew" attributes via the standard context or filter init @@ -35,7 +38,9 @@ public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter final String casServerUrlPrefix = getPropertyFromInitParams(filterConfig, "casServerUrlPrefix", null); final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix); validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - validator.setHostnameVerifier(getHostnameVerifier(filterConfig)); + + final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + validator.setURLConnectionFactory(factory); validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); return validator; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index 5d31060..8767e40 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 @@ -31,7 +31,9 @@ import javax.servlet.http.HttpServletResponse; import org.jasig.cas.client.proxy.*; import org.jasig.cas.client.util.CommonUtils; +import org.jasig.cas.client.util.HttpsURLConnectionFactory; import org.jasig.cas.client.util.ReflectUtils; +import org.jasig.cas.client.util.URLConnectionFactory; /** * Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the @@ -159,7 +161,8 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal } validator.setCustomParameters(additionalParameters); - validator.setHostnameVerifier(getHostnameVerifier(filterConfig)); + final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + validator.setURLConnectionFactory(factory); return validator; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 8ac6e52..25f74f0 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -21,6 +21,9 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import org.jasig.cas.client.util.HttpsURLConnectionFactory; +import org.jasig.cas.client.util.URLConnectionFactory; + /** * Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator. *

@@ -53,7 +56,10 @@ public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter final String tolerance = getPropertyFromInitParams(filterConfig, "tolerance", "1000"); validator.setTolerance(Long.parseLong(tolerance)); validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - validator.setHostnameVerifier(getHostnameVerifier(filterConfig)); + + final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + validator.setURLConnectionFactory(factory); + validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); validator.setDisableXmlSchemaValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "disableXmlSchemaValidation", "false"))); return validator; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 8a1d775..0f97a94 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -45,13 +45,10 @@ import java.net.URL; import java.nio.charset.Charset; import java.util.*; -import javax.net.ssl.HttpsURLConnection; - /** * TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response. * * @author Scott Battaglia - * @version $Revision$ $Date$ * @since 3.1 */ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator { @@ -232,12 +229,11 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator + "" + ticket + ""; HttpURLConnection conn = null; - + DataOutputStream out = null; + BufferedReader in = null; + try { - conn = (HttpURLConnection) validationUrl.openConnection(); - if (this.hostnameVerifier != null && conn instanceof HttpsURLConnection) { - ((HttpsURLConnection)conn).setHostnameVerifier(this.hostnameVerifier); - } + conn = (HttpURLConnection) this.getURLConnectionFactory().getURLConnection(validationUrl.openConnection()); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "text/xml"); conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length())); @@ -246,12 +242,11 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator conn.setDoInput(true); conn.setDoOutput(true); - final DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out = new DataOutputStream(conn.getOutputStream()); out.writeBytes(MESSAGE_TO_SEND); out.flush(); - out.close(); - - final BufferedReader in = new BufferedReader(CommonUtils.isNotBlank(getEncoding()) ? new InputStreamReader(conn.getInputStream(), Charset.forName(getEncoding())) : new InputStreamReader(conn.getInputStream())); + + in = new BufferedReader(CommonUtils.isNotBlank(getEncoding()) ? new InputStreamReader(conn.getInputStream(), Charset.forName(getEncoding())) : new InputStreamReader(conn.getInputStream())); final StringBuilder buffer = new StringBuilder(256); String line; @@ -263,6 +258,8 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator } catch (final IOException e) { throw new RuntimeException(e); } finally { + CommonUtils.closeQuietly(out); + CommonUtils.closeQuietly(in); if (conn != null) { conn.disconnect(); } diff --git a/pom.xml b/pom.xml index db7b342..3f96307 100644 --- a/pom.xml +++ b/pom.xml @@ -75,6 +75,7 @@ org.apache.maven.plugins maven-compiler-plugin + 3.0 1.5 1.5 @@ -94,6 +95,7 @@ maven-source-plugin + 2.2.1 attach-sources From d1ae0f5bbf8424e6e86c4ee7c1694991891bddeb Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 24 Jan 2013 12:07:22 -0700 Subject: [PATCH 02/10] Fixed javadoc for unused parameter. --- .../org/jasig/cas/client/util/HttpsURLConnectionFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java index e87335a..b9e6f60 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java @@ -92,7 +92,6 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { * keyStorePass=changeit * certificatePassword=aGoodPass * - * @param sslConfig {@link Properties} * @return the {@link SSLSocketFactory} */ private SSLSocketFactory createSSLSocketFactory() { From d102c5077932c8884ea72ae47b17a1d5dc9a5492 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 24 Jan 2013 15:47:22 -0700 Subject: [PATCH 03/10] CASC-180 - Add support for Client Side Certificates Moved url connection factory interface and its https impl into the ssl package. --- .../{util => ssl}/HttpsURLConnectionFactory.java | 10 +++++++++- .../cas/client/{util => ssl}/URLConnectionFactory.java | 2 +- .../java/org/jasig/cas/client/util/CommonUtils.java | 2 ++ .../validation/AbstractUrlBasedTicketValidator.java | 4 ++-- .../client/validation/Cas10TicketValidationFilter.java | 4 ++-- .../Cas20ProxyReceivingTicketValidationFilter.java | 4 ++-- .../validation/Saml11TicketValidationFilter.java | 4 ++-- 7 files changed, 20 insertions(+), 10 deletions(-) rename cas-client-core/src/main/java/org/jasig/cas/client/{util => ssl}/HttpsURLConnectionFactory.java (94%) rename cas-client-core/src/main/java/org/jasig/cas/client/{util => ssl}/URLConnectionFactory.java (97%) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java similarity index 94% rename from cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java rename to cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index b9e6f60..2fc3ed2 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -1,4 +1,4 @@ -package org.jasig.cas.client.util; +package org.jasig.cas.client.ssl; import java.io.FileInputStream; import java.io.InputStream; @@ -12,6 +12,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; +import org.jasig.cas.client.util.CommonUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +52,13 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { this.sslConfiguration = config; } + /** + * Set the host name verifier for the https connection received. + * + * @see AnyHostnameVerifier + * @see RegexHostnameVerifier + * @see WhitelistHostnameVerifier + */ public final void setHostnameVerifier(final HostnameVerifier verifier) { this.hostnameVerifier = verifier; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java similarity index 97% rename from cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java rename to cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java index 9a08fe0..45b7dd0 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/URLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jasig.cas.client.util; +package org.jasig.cas.client.ssl; import java.net.URL; import java.net.URLConnection; 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 9f30256..fe264ac 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 @@ -19,6 +19,8 @@ package org.jasig.cas.client.util; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; +import org.jasig.cas.client.ssl.URLConnectionFactory; import org.jasig.cas.client.validation.ProxyList; import org.jasig.cas.client.validation.ProxyListEditor; import org.slf4j.Logger; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index b1df5ad..6d7a71f 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -18,9 +18,9 @@ */ package org.jasig.cas.client.validation; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; +import org.jasig.cas.client.ssl.URLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; -import org.jasig.cas.client.util.HttpsURLConnectionFactory; -import org.jasig.cas.client.util.URLConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java index dc910c3..47e6eb3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java @@ -20,8 +20,8 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; -import org.jasig.cas.client.util.HttpsURLConnectionFactory; -import org.jasig.cas.client.util.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; +import org.jasig.cas.client.ssl.URLConnectionFactory; /** * Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator. 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 8767e40..45f5473 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 @@ -30,10 +30,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jasig.cas.client.proxy.*; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; +import org.jasig.cas.client.ssl.URLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; -import org.jasig.cas.client.util.HttpsURLConnectionFactory; import org.jasig.cas.client.util.ReflectUtils; -import org.jasig.cas.client.util.URLConnectionFactory; /** * Creates either a CAS20ProxyTicketValidator or a CAS20ServiceTicketValidator depending on whether any of the diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 25f74f0..30f5ae3 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -21,8 +21,8 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import org.jasig.cas.client.util.HttpsURLConnectionFactory; -import org.jasig.cas.client.util.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; +import org.jasig.cas.client.ssl.URLConnectionFactory; /** * Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator. From 6e12f43b16c8139d8e626832e9acf696dc991a1c Mon Sep 17 00:00:00 2001 From: "Marvin S. Addison" Date: Mon, 4 Mar 2013 10:43:55 -0500 Subject: [PATCH 04/10] CASC-204 Prevent renew misconfiguration. Prevent renew from being configured via filter init param, which can lead to a half-configured state where authentication filter is configured for renew without validation filter. With this change in place, renew MUST be configured by a global configuration facility such as context parameter or JNDI to ensure proper configuration. --- .../util/AbstractConfigurationFilter.java | 4 ++ .../AuthenticationFilterTests.java | 43 +++++++++++--- .../Cas10TicketValidationFilterTests.java | 58 +++++++++++++++++++ ...yReceivingTicketValidationFilterTests.java | 30 +++++++++- .../Saml11TicketValidationFilterTests.java | 58 +++++++++++++++++++ 5 files changed, 183 insertions(+), 10 deletions(-) create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java create mode 100644 cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java index e9e2183..e242510 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractConfigurationFilter.java @@ -67,6 +67,10 @@ public abstract class AbstractConfigurationFilter implements Filter { final String value = filterConfig.getInitParameter(propertyName); if (CommonUtils.isNotBlank(value)) { + if ("renew".equals(propertyName)) { + throw new IllegalArgumentException( + "Renew MUST be specified via context parameter or JNDI environment to avoid misconfiguration."); + } logger.info("Property [{}] loaded from FilterConfig.getInitParameter with value [{}]", propertyName, value); return value; } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java index 9b41a74..b2a520b 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java @@ -18,6 +18,15 @@ */ package org.jasig.cas.client.authentication; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URLEncoder; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + import junit.framework.TestCase; import org.jasig.cas.client.util.AbstractCasFilter; import org.jasig.cas.client.validation.AssertionImpl; @@ -25,13 +34,7 @@ import org.springframework.mock.web.MockFilterConfig; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import java.io.IOException; -import java.net.URLEncoder; +import org.springframework.mock.web.MockServletContext; /** * Tests for the AuthenticationFilter. @@ -177,4 +180,30 @@ public final class AuthenticationFilterTests extends TestCase { assertNull(session.getAttribute(DefaultGatewayResolverImpl.CONST_CAS_GATEWAY)); assertNull(response2.getRedirectedUrl()); } + + public void testRenewInitParamThrows() throws Exception { + final AuthenticationFilter f = new AuthenticationFilter(); + final MockFilterConfig config = new MockFilterConfig(); + config.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); + config.addInitParameter("service", "https://localhost:8443/service"); + config.addInitParameter("renew", "true"); + try { + f.init(config); + fail("Should have thrown IllegalArgumentException."); + } catch (final IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Renew MUST")); + } + } + + public void testAllowsRenewContextParam() throws Exception { + final AuthenticationFilter f = new AuthenticationFilter(); + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerLoginUrl", "https://cas.example.com/login"); + context.addInitParameter("service", "https://localhost:8443/service"); + context.addInitParameter("renew", "true"); + f.init(new MockFilterConfig(context)); + final Field renewField = AuthenticationFilter.class.getDeclaredField("renew"); + renewField.setAccessible(true); + assertTrue((Boolean) renewField.get(f)); + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java new file mode 100644 index 0000000..e15e7f2 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java @@ -0,0 +1,58 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * * + * http://www.apache.org/licenses/LICENSE-2.0 + * * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.validation; + +import org.junit.Test; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockServletContext; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Unit test for {@link Cas10TicketValidationFilter}. + * + * @author Marvin S. Addison + */ +public class Cas10TicketValidationFilterTests { + @Test + public void testThrowsRenewInitParam() throws Exception { + final Cas10TicketValidationFilter f = new Cas10TicketValidationFilter(); + final MockFilterConfig config = new MockFilterConfig(); + config.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + config.addInitParameter("renew", "true"); + try { + f.init(config); + fail("Should have thrown IllegalArgumentException."); + } catch (final IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Renew MUST")); + } + } + + @Test + public void testAllowsRenewContextParam() throws Exception { + final Cas10TicketValidationFilter f = new Cas10TicketValidationFilter(); + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + context.addInitParameter("renew", "true"); + final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + assertTrue(validator instanceof Cas10TicketValidator); + assertTrue(((Cas10TicketValidator) validator).isRenew()); + } +} diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java index 073ad3f..eeb59dd 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilterTests.java @@ -18,15 +18,16 @@ */ package org.jasig.cas.client.validation; +import java.util.Timer; +import java.util.TimerTask; + import junit.framework.TestCase; import org.jasig.cas.client.proxy.CleanUpTimerTask; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; import org.jasig.cas.client.util.MethodFlag; import org.springframework.mock.web.MockFilterConfig; - -import java.util.Timer; -import java.util.TimerTask; +import org.springframework.mock.web.MockServletContext; /** * Unit test for {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter} @@ -179,6 +180,29 @@ public void testCallsCleanAllOnSchedule() throws Exception { assertNotNull(filter.getTicketValidator(config3)); } + public void testRenewInitParamThrows() throws Exception { + final Cas20ProxyReceivingTicketValidationFilter f = new Cas20ProxyReceivingTicketValidationFilter(); + final MockFilterConfig config = new MockFilterConfig(); + config.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + config.addInitParameter("renew", "true"); + try { + f.init(config); + fail("Should have thrown IllegalArgumentException."); + } catch (final IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Renew MUST")); + } + } + + public void testAllowsRenewContextParam() throws Exception { + final Cas20ProxyReceivingTicketValidationFilter f = new Cas20ProxyReceivingTicketValidationFilter(); + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + context.addInitParameter("renew", "true"); + final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + assertTrue(validator instanceof AbstractUrlBasedTicketValidator); + assertTrue(((AbstractUrlBasedTicketValidator) validator).isRenew()); + } + /** * construct a working {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter} */ diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java new file mode 100644 index 0000000..cb64c63 --- /dev/null +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java @@ -0,0 +1,58 @@ +/* + * Licensed to Jasig under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Jasig licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at the following location: + * * + * http://www.apache.org/licenses/LICENSE-2.0 + * * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jasig.cas.client.validation; + +import org.junit.Test; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockServletContext; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Unit test for {@link Saml11TicketValidationFilter}. + * + * @author Marvin S. Addison + */ +public class Saml11TicketValidationFilterTests { + @Test + public void testRenewInitParamThrows() throws Exception { + final Saml11TicketValidationFilter f = new Saml11TicketValidationFilter(); + final MockFilterConfig config = new MockFilterConfig(); + config.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + config.addInitParameter("renew", "true"); + try { + f.init(config); + fail("Should have thrown IllegalArgumentException."); + } catch (final IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Renew MUST")); + } + } + + @Test + public void testAllowsRenewContextParam() throws Exception { + final Saml11TicketValidationFilter f = new Saml11TicketValidationFilter(); + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + context.addInitParameter("renew", "true"); + final TicketValidator validator = f.getTicketValidator(new MockFilterConfig(context)); + assertTrue(validator instanceof Saml11TicketValidator); + assertTrue(((Saml11TicketValidator) validator).isRenew()); + } +} From c34ff785dd853d6d5bc7b8002cbac069fe567cb6 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Mon, 4 Mar 2013 14:17:55 -0700 Subject: [PATCH 05/10] CASC-180: Fix the issue with casting to http url connections and provide a default instance for the http url factory. --- .../cas/client/ssl/HttpsURLConnectionFactory.java | 9 ++++++--- .../org/jasig/cas/client/ssl/URLConnectionFactory.java | 5 +++-- .../java/org/jasig/cas/client/util/CommonUtils.java | 10 +++++----- .../cas/client/validation/Saml11TicketValidator.java | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index 2fc3ed2..3082607 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -2,6 +2,7 @@ package org.jasig.cas.client.ssl; import java.io.FileInputStream; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.URLConnection; import java.security.KeyStore; import java.util.Properties; @@ -30,6 +31,8 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class); + public static final HttpsURLConnectionFactory INSTANCE = new HttpsURLConnectionFactory(); + /** * Hostname verifier used when making an SSL request to the CAS server. * Defaults to {@link HttpsURLConnection#getDefaultHostnameVerifier()} @@ -63,7 +66,7 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { this.hostnameVerifier = verifier; } - public URLConnection getURLConnection(final URLConnection url) { + public HttpURLConnection buildHttpURLConnection(final URLConnection url) { return this.configureHttpsConnectionIfNeeded(url); } @@ -74,7 +77,7 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { * * @param conn the http connection */ - private URLConnection configureHttpsConnectionIfNeeded(final URLConnection conn) { + private HttpURLConnection configureHttpsConnectionIfNeeded(final URLConnection conn) { if (conn instanceof HttpsURLConnection) { final HttpsURLConnection httpsConnection = (HttpsURLConnection) conn; final SSLSocketFactory socketFactory = this.createSSLSocketFactory(); @@ -86,7 +89,7 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { httpsConnection.setHostnameVerifier(this.hostnameVerifier); } } - return conn; + return (HttpURLConnection)conn; } /** diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java index 45b7dd0..28bbadc 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java @@ -18,6 +18,7 @@ */ package org.jasig.cas.client.ssl; +import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; @@ -36,9 +37,9 @@ public interface URLConnectionFactory { * to accommodate method chaining. * * @param url The url connection that needs to be configured - * @return The configured {@link URLConnection} instance + * @return The configured {@link HttpURLConnection} instance * * @see {@link HttpsURLConnectionFactory} */ - URLConnection getURLConnection(final URLConnection url); + HttpURLConnection buildHttpURLConnection(final URLConnection url); } 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 fe264ac..03f481d 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 @@ -331,9 +331,9 @@ public final class CommonUtils { */ public static String getResponseFromServer(final URL constructedUrl, final URLConnectionFactory factory, final String encoding) { - URLConnection conn = null; + HttpURLConnection conn = null; try { - conn = factory.getURLConnection(constructedUrl.openConnection()); + conn = factory.buildHttpURLConnection(constructedUrl.openConnection()); final BufferedReader in; @@ -355,8 +355,8 @@ public final class CommonUtils { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } finally { - if (conn != null && conn instanceof HttpURLConnection) { - ((HttpURLConnection)conn).disconnect(); + if (conn != null) { + conn.disconnect(); } } @@ -371,7 +371,7 @@ public final class CommonUtils { */ public static String getResponseFromServer(final String url, String encoding) { try { - return getResponseFromServer(new URL(url), new HttpsURLConnectionFactory(), encoding); + return getResponseFromServer(new URL(url), HttpsURLConnectionFactory.INSTANCE, encoding); } catch (final MalformedURLException e) { throw new IllegalArgumentException(e); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 0f97a94..7176a9d 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -233,7 +233,7 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator BufferedReader in = null; try { - conn = (HttpURLConnection) this.getURLConnectionFactory().getURLConnection(validationUrl.openConnection()); + conn = this.getURLConnectionFactory().buildHttpURLConnection(validationUrl.openConnection()); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "text/xml"); conn.setRequestProperty("Content-Length", Integer.toString(MESSAGE_TO_SEND.length())); From 3964e739c0c45229bd6c759599b6e1549a1a9ec5 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Wed, 6 Mar 2013 09:34:39 -0700 Subject: [PATCH 06/10] CASC-180: Removed the default url connection factory, allowed proxy retrieval to use the configured factory instance. --- .../AttributePrincipalImpl.java | 3 +- .../cas/client/proxy/Cas20ProxyRetriever.java | 37 ++++++++++++------- .../client/ssl/HttpsURLConnectionFactory.java | 4 +- .../jasig/cas/client/util/CommonUtils.java | 16 -------- ...0ProxyReceivingTicketValidationFilter.java | 9 +++-- .../Cas20ServiceTicketValidator.java | 5 +-- .../Cas20ProxyTicketValidatorTests.java | 1 - 7 files changed, 33 insertions(+), 42 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java index c7ca08f..acc9823 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AttributePrincipalImpl.java @@ -30,7 +30,6 @@ import java.util.Map; * Concrete implementation of the AttributePrincipal interface. * * @author Scott Battaglia - * @version $Revision$ $Date$ * @since 3.1 */ public class AttributePrincipalImpl extends SimplePrincipal implements AttributePrincipal { @@ -80,7 +79,7 @@ public class AttributePrincipalImpl extends SimplePrincipal implements Attribute } /** - * Constructs a new principal witht he supplied name, attributes, and proxying capabilities. + * Constructs a new principal with the supplied name, attributes, and proxying capabilities. * * @param name the unique identifier for the principal. * @param attributes the key/value pairs for this principal. 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 42c21ef..90cb084 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 @@ -18,12 +18,15 @@ */ package org.jasig.cas.client.proxy; +import org.jasig.cas.client.ssl.URLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLEncoder; /** @@ -43,7 +46,7 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { /** Unique Id for serialization. */ private static final long serialVersionUID = 560409469568911791L; - /** + /** * Instance of Commons Logging. */ private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -55,31 +58,39 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { private final String encoding; + /** Url connection factory to use when communicating with the server **/ + private final URLConnectionFactory urlConnectionFactory; + /** * Main Constructor. * * @param casServerUrl the URL to the CAS server (i.e. http://localhost/cas/) * @param encoding the encoding to use. + * @param urlFactory url connection factory use when retrieving proxy responses from the server */ - public Cas20ProxyRetriever(final String casServerUrl, final String encoding) { + public Cas20ProxyRetriever(final String casServerUrl, final String encoding, final URLConnectionFactory urlFactory) { CommonUtils.assertNotNull(casServerUrl, "casServerUrl cannot be null."); this.casServerUrl = casServerUrl; this.encoding = encoding; + this.urlConnectionFactory = urlFactory; } - + public String getProxyTicketIdFor(final String proxyGrantingTicketId, final String targetService) { - - final String url = constructUrl(proxyGrantingTicketId, targetService); - final String response = CommonUtils.getResponseFromServer(url, this.encoding); - final String error = XmlUtils.getTextForElement(response, "proxyFailure"); - - if (CommonUtils.isNotEmpty(error)) { - logger.debug(error); - return null; + try { + final String url = constructUrl(proxyGrantingTicketId, targetService); + final String response = CommonUtils.getResponseFromServer(new URL(url), this.urlConnectionFactory, this.encoding); + final String error = XmlUtils.getTextForElement(response, "proxyFailure"); + + if (CommonUtils.isNotEmpty(error)) { + logger.debug(error); + return null; + } + + return XmlUtils.getTextForElement(response, "proxyTicket"); + } catch (final MalformedURLException ex) { + throw new RuntimeException(ex); } - - return XmlUtils.getTextForElement(response, "proxyTicket"); } private String constructUrl(final String proxyGrantingTicketId, final String targetService) { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index 3082607..67e442d 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -31,8 +31,6 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class); - public static final HttpsURLConnectionFactory INSTANCE = new HttpsURLConnectionFactory(); - /** * Hostname verifier used when making an SSL request to the CAS server. * Defaults to {@link HttpsURLConnection#getDefaultHostnameVerifier()} @@ -89,7 +87,7 @@ public final class HttpsURLConnectionFactory implements URLConnectionFactory { httpsConnection.setHostnameVerifier(this.hostnameVerifier); } } - return (HttpURLConnection)conn; + return (HttpURLConnection) conn; } /** 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 03f481d..c592711 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 @@ -359,22 +359,6 @@ public final class CommonUtils { conn.disconnect(); } } - - } - - /** - * Contacts the remote URL and returns the response. - * - * @param url the url to contact. - * @param encoding the encoding to use. - * @return the response. - */ - public static String getResponseFromServer(final String url, String encoding) { - try { - return getResponseFromServer(new URL(url), HttpsURLConnectionFactory.INSTANCE, encoding); - } catch (final MalformedURLException e) { - throw new IllegalArgumentException(e); - } } public static ProxyList createProxyList(final String proxies) { 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 45f5473..6e58142 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 @@ -145,7 +145,11 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal } validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null)); validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage); - validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig, "encoding", null))); + + final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + validator.setURLConnectionFactory(factory); + + validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig, "encoding", null), factory)); validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); @@ -161,9 +165,6 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal } validator.setCustomParameters(additionalParameters); - final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); - validator.setURLConnectionFactory(factory); - return validator; } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java index c626d6d..9c90eaf 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ServiceTicketValidator.java @@ -25,7 +25,6 @@ import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyRetriever; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; -import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -41,7 +40,6 @@ import java.util.*; * Implementation of the TicketValidator that will validate Service Tickets in compliance with the CAS 2. * * @author Scott Battaglia - * @version $Revision$ $Date$ * @since 3.1 */ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTicketValidator { @@ -60,10 +58,11 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick * CAS server url prefix. * * @param casServerUrlPrefix the CAS Server URL prefix. + * @param urlFactory URL connection factory to use when communicating with the server */ public Cas20ServiceTicketValidator(final String casServerUrlPrefix) { super(casServerUrlPrefix); - this.proxyRetriever = new Cas20ProxyRetriever(casServerUrlPrefix, getEncoding()); + this.proxyRetriever = new Cas20ProxyRetriever(casServerUrlPrefix, getEncoding(), getURLConnectionFactory()); } /** diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java index b374cae..ce6f415 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java @@ -22,7 +22,6 @@ import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl; import org.jasig.cas.client.proxy.ProxyRetriever; -import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; From 2e6df8c5b7c443fbbe24182a5d64088130dccf82 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sat, 9 Mar 2013 15:00:45 -0700 Subject: [PATCH 07/10] CASC-180: Fixed try/catch block issue with URL creation. --- .../cas/client/proxy/Cas20ProxyRetriever.java | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java b/cas-client-core/src/main/java/org/jasig/cas/client/proxy/Cas20ProxyRetriever.java index 90cb084..bca497a 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 @@ -75,30 +75,28 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { this.urlConnectionFactory = urlFactory; } - public String getProxyTicketIdFor(final String proxyGrantingTicketId, - final String targetService) { - try { - final String url = constructUrl(proxyGrantingTicketId, targetService); - final String response = CommonUtils.getResponseFromServer(new URL(url), this.urlConnectionFactory, this.encoding); - final String error = XmlUtils.getTextForElement(response, "proxyFailure"); + public String getProxyTicketIdFor(final String proxyGrantingTicketId, final String targetService) { + CommonUtils.assertNotNull(proxyGrantingTicketId, "proxyGrantingTicketId cannot be null."); + CommonUtils.assertNotNull(targetService, "targetService cannot be null."); + + final URL url = constructUrl(proxyGrantingTicketId, targetService); + final String response = CommonUtils.getResponseFromServer(url, this.urlConnectionFactory, this.encoding); + final String error = XmlUtils.getTextForElement(response, "proxyFailure"); - if (CommonUtils.isNotEmpty(error)) { - logger.debug(error); - return null; - } - - return XmlUtils.getTextForElement(response, "proxyTicket"); - } catch (final MalformedURLException ex) { - throw new RuntimeException(ex); + if (CommonUtils.isNotEmpty(error)) { + logger.debug(error); + return null; } + + return XmlUtils.getTextForElement(response, "proxyTicket"); } - private String constructUrl(final String proxyGrantingTicketId, final String targetService) { + private URL constructUrl(final String proxyGrantingTicketId, final String targetService) { try { - return this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxy" + "?pgt=" - + proxyGrantingTicketId + "&targetService=" - + URLEncoder.encode(targetService, "UTF-8"); - } catch (final UnsupportedEncodingException e) { + return new URL(this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxy" + + "?pgt=" + proxyGrantingTicketId + + "&targetService=" + URLEncoder.encode(targetService, "UTF-8")); + } catch (final Exception e) { throw new RuntimeException(e); } } From 4f79cd101407f7d62ea83baf17c0c2f8d8db4c5f Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Sun, 10 Mar 2013 20:51:27 -0700 Subject: [PATCH 08/10] CASC-180: Renamed factory to be HttpURLConnectionFactory. --- .../org/jasig/cas/client/proxy/Cas20ProxyRetriever.java | 6 +++--- ...nnectionFactory.java => HttpURLConnectionFactory.java} | 2 +- .../jasig/cas/client/ssl/HttpsURLConnectionFactory.java | 4 ++-- .../main/java/org/jasig/cas/client/util/CommonUtils.java | 4 ++-- .../validation/AbstractUrlBasedTicketValidator.java | 8 ++++---- .../client/validation/Cas10TicketValidationFilter.java | 4 ++-- .../Cas20ProxyReceivingTicketValidationFilter.java | 4 ++-- .../client/validation/Saml11TicketValidationFilter.java | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) rename cas-client-core/src/main/java/org/jasig/cas/client/ssl/{URLConnectionFactory.java => HttpURLConnectionFactory.java} (97%) 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 bca497a..a77b11f 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 @@ -18,7 +18,7 @@ */ package org.jasig.cas.client.proxy; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; import org.slf4j.Logger; @@ -59,7 +59,7 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { private final String encoding; /** Url connection factory to use when communicating with the server **/ - private final URLConnectionFactory urlConnectionFactory; + private final HttpURLConnectionFactory urlConnectionFactory; /** * Main Constructor. @@ -68,7 +68,7 @@ public final class Cas20ProxyRetriever implements ProxyRetriever { * @param encoding the encoding to use. * @param urlFactory url connection factory use when retrieving proxy responses from the server */ - public Cas20ProxyRetriever(final String casServerUrl, final String encoding, final URLConnectionFactory urlFactory) { + public Cas20ProxyRetriever(final String casServerUrl, final String encoding, final HttpURLConnectionFactory urlFactory) { CommonUtils.assertNotNull(casServerUrl, "casServerUrl cannot be null."); this.casServerUrl = casServerUrl; this.encoding = encoding; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java similarity index 97% rename from cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java rename to cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java index 28bbadc..c3a33ce 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/URLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpURLConnectionFactory.java @@ -28,7 +28,7 @@ import java.net.URLConnection; * @author Misagh Moayyed * @since 3.3 */ -public interface URLConnectionFactory { +public interface HttpURLConnectionFactory { /** * Receives a {@link URLConnection} instance typically as a result of a {@link URL} diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index 67e442d..2475e5a 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -18,7 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * An implementation of the {@link URLConnectionFactory} whose responsible to configure + * An implementation of the {@link HttpURLConnectionFactory} whose responsible to configure * the underlying https connection, if needed, with a given hostname and SSL socket factory based on the * configuration provided. * @@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory; * @see #setHostnameVerifier(HostnameVerifier) * @see #setSSLConfiguration(Properties) */ -public final class HttpsURLConnectionFactory implements URLConnectionFactory { +public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory { private static final Logger LOGGER = LoggerFactory.getLogger(HttpsURLConnectionFactory.class); 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 c592711..e754941 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 @@ -20,7 +20,7 @@ package org.jasig.cas.client.util; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.validation.ProxyList; import org.jasig.cas.client.validation.ProxyListEditor; import org.slf4j.Logger; @@ -329,7 +329,7 @@ public final class CommonUtils { * @param encoding the encoding to use. * @return the response. */ - public static String getResponseFromServer(final URL constructedUrl, final URLConnectionFactory factory, final String encoding) { + public static String getResponseFromServer(final URL constructedUrl, final HttpURLConnectionFactory factory, final String encoding) { HttpURLConnection conn = null; try { diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java index 6d7a71f..5410669 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractUrlBasedTicketValidator.java @@ -19,7 +19,7 @@ package org.jasig.cas.client.validation; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +45,7 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator * URLConnection factory instance to use when making validation requests to the CAS server. * Defaults to {@link HttpsURLConnectionFactory} */ - private URLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory(); + private HttpURLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory(); /** * Prefix for the CAS server. Should be everything up to the url endpoint, including the /. @@ -238,11 +238,11 @@ public abstract class AbstractUrlBasedTicketValidator implements TicketValidator return this.customParameters; } - protected URLConnectionFactory getURLConnectionFactory() { + protected HttpURLConnectionFactory getURLConnectionFactory() { return this.urlConnectionFactory; } - public void setURLConnectionFactory(final URLConnectionFactory urlConnectionFactory) { + public void setURLConnectionFactory(final HttpURLConnectionFactory urlConnectionFactory) { this.urlConnectionFactory = urlConnectionFactory; } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java index 47e6eb3..2e8424c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas10TicketValidationFilter.java @@ -21,7 +21,7 @@ package org.jasig.cas.client.validation; import javax.servlet.FilterConfig; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; /** * Implementation of AbstractTicketValidatorFilter that instanciates a Cas10TicketValidator. @@ -39,7 +39,7 @@ public class Cas10TicketValidationFilter extends AbstractTicketValidationFilter final Cas10TicketValidator validator = new Cas10TicketValidator(casServerUrlPrefix); validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); validator.setURLConnectionFactory(factory); validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); 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 6e58142..48935c5 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 @@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletResponse; import org.jasig.cas.client.proxy.*; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.ReflectUtils; @@ -146,7 +146,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal validator.setProxyCallbackUrl(getPropertyFromInitParams(filterConfig, "proxyCallbackUrl", null)); validator.setProxyGrantingTicketStorage(this.proxyGrantingTicketStorage); - final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); validator.setURLConnectionFactory(factory); validator.setProxyRetriever(new Cas20ProxyRetriever(casServerUrlPrefix, getPropertyFromInitParams(filterConfig, "encoding", null), factory)); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java index 30f5ae3..e35bf83 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidationFilter.java @@ -22,7 +22,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; import org.jasig.cas.client.ssl.HttpsURLConnectionFactory; -import org.jasig.cas.client.ssl.URLConnectionFactory; +import org.jasig.cas.client.ssl.HttpURLConnectionFactory; /** * Implementation of TicketValidationFilter that can instanciate a SAML 1.1 Ticket Validator. @@ -57,7 +57,7 @@ public class Saml11TicketValidationFilter extends AbstractTicketValidationFilter validator.setTolerance(Long.parseLong(tolerance)); validator.setRenew(parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false"))); - final URLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); + final HttpURLConnectionFactory factory = new HttpsURLConnectionFactory(getHostnameVerifier(filterConfig), getSSLConfig(filterConfig)); validator.setURLConnectionFactory(factory); validator.setEncoding(getPropertyFromInitParams(filterConfig, "encoding", null)); From e6e0f907b8e17727dccb4596130c8a5ea744d577 Mon Sep 17 00:00:00 2001 From: mores Date: Thu, 25 Apr 2013 09:11:11 -0400 Subject: [PATCH 09/10] Fix to allow client to work with Server 3.5.2 --- .../org/jasig/cas/client/validation/Saml11TicketValidator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java index 7176a9d..6f467d8 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Saml11TicketValidator.java @@ -36,6 +36,7 @@ import org.opensaml.xml.io.UnmarshallingException; import org.opensaml.xml.parse.BasicParserPool; import org.opensaml.xml.parse.XMLParserException; import org.opensaml.xml.schema.XSAny; +import org.opensaml.xml.schema.XSString; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -217,6 +218,8 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator for (final Object o : attribute.getAttributeValues()) { if (o instanceof XSAny) { list.add(((XSAny) o).getTextContent()); + } else if (o instanceof XSString) { + list.add(((XSString) o).getValue()); } else { list.add(o.toString()); } From 2b53bdf88248b5842f12a14eef7f63c959d06c6f Mon Sep 17 00:00:00 2001 From: mores Date: Mon, 6 May 2013 13:46:47 -0400 Subject: [PATCH 10/10] getSocketFactory() should only be called on a sslContext that has been initialized. --- .../org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java index 2475e5a..298069a 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/ssl/HttpsURLConnectionFactory.java @@ -118,11 +118,11 @@ public final class HttpsURLConnectionFactory implements HttpURLConnectionFactory final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(this.sslConfiguration.getProperty("keyManagerType", "SunX509")); keyManager.init(keyStore, this.sslConfiguration.getProperty("certificatePassword").toCharArray()); sslContext.init(keyManager.getKeyManagers(), null, null); + return sslContext.getSocketFactory(); } } } - return sslContext.getSocketFactory(); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); } finally {