From b54cd179e2aeb462184d3819d5f1098a29081776 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 24 Jan 2013 12:01:47 -0700 Subject: [PATCH] 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