You are viewing a plain text version of this content. The canonical link for it is here.
Posted to httpclient-users@hc.apache.org by Mark Claassen <ma...@donnell.com> on 2011/02/17 20:48:49 UTC

Webstart problems with SSL and the DEFAULT SSLSocketFactory

I have been using HttpClient for a while now with success.  However, I have recently encountering some problems which I think have
an easy solution, although it is not accessible to me through the current API.

Situation (my test enviroment):

ServerA:
* Runs Tomcat 6
* Contains jar files that are downloaded via webstart
* Only accepts non-SSL connections

ServerB:
* Runs Tomcat 6
* Contains jar files that are downloaded via webstart
* Contains a servlet
* Only accepts SSL connections

If I connect to serverB (via webstart) and download the jars, my app connects to the servlet on ServerB and everything is fine.
However, if I connect to ServerA (via webstart), download the jars, and then the app tries to connect to ServerB, the SSL connection
cannot be established.

I need to use the default socket factory since it is managed by webstart and automatically prompts for certificate issues and allows
for automatic use of client certificates.

Theory
------
Terminology:
javax.SSLSocketFactory = javax.net.ssl.SSLSocketFactory apache.SSLSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory

I am confused about exactly why this is happening, but I have a theory.  In my theory, the crux of the problem is that the DEFAULT
apache.SSLSocketFactory is set in the static initializer of the apache.SSLSocketFactory class.  In the first scenario, webstart
creates a new javax.SSLSocketFactory for the jar download, and makes this the default.  This happens way before the
apache.SSLSocketFactory is loaded.  In the second scenario, this happens in the other order and the javax.SSLSocketFactory wrapped
by the apache.SSLSocketFactory is not the correct one.

If I could ensure that the javax.SSLSocketFactory is initialized first, and then create an apache.SSLSocketFactory to wrap this, I
think I would be in good shape.  The apache.SSLSocketFactory does have a wrapping construtor, but it is the private no-argument
constructor.  If this were public in some manner, I could ensure my apache.SSLSocketFactory wraps the correct one.

I don't really see a down-side to making this public.  However, if this needed to be private to prevent certain types of
subclassing, a static factory method could be added to create an apache.SSLSocketFactory that wraps a javax.SSLSocketFactory.

Theory Corroborated
--------------------
I downloaded the httpclient 4.01 source (the version we are currently using), changed the no-arg constructor to be public, and used
it to create a new apache.SSLSocketFactory after I initialized the HttpsURLConnection.  This did, indeed, solve the problem.
Perhaps there is more going on here than I realize, but it was easy and it worked.

Formal Request:
---------------
I would like to request that the API of apache.SSLSocketFactory be adjusted to handle this scenario.

My test Details:
----------------
This is how I initialized the default socket factory:

HttpsURLConnection conn = (HttpsURLConnection)new URL(urlString).openConnection(); conn.setDoOutput(true); OutputStream os =
conn.getOutputStream(); os.close(); conn.disconnect();

apache.SSLSocketFactory fact = new SSLSocketFactory();			
schemeRegistry.register(new Scheme(scheme, fact, port));

Appreviated Stack Trace when error occurs:
------------------------------------------

 ---- (1) ---- Throwable - Class (class javax.net.ssl.SSLException)
 	Message (Connection has been shutdown: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX
path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to
requested target)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkWrite(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.flushBuffer(AbstractSessionOutputBuffer.java:106)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:126)
 	at org.apache.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:99)
 	at org.apache.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:175)
 	...
 ---- (2) ---- Throwable - Class (class javax.net.ssl.SSLHandshakeException)
 	Message (sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target)
 	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.flushBuffer(AbstractSessionOutputBuffer.java:106)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:126)
 	at org.apache.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:99)
 	at org.apache.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:175)
	...
 ---- (3) ---- Throwable - Class (class sun.security.validator.ValidatorException)
 	Message (PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
certification path to requested target)
 	at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
 	at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
 	at sun.security.validator.Validator.validate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.flushBuffer(AbstractSessionOutputBuffer.java:106)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:126)
 	at org.apache.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:99)
 	at org.apache.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:175)
	...
 ---- (4) ---- Throwable - Class (class sun.security.provider.certpath.SunCertPathBuilderException)
 	Message (unable to find valid certification path to requested target)
 	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
 	at java.security.cert.CertPathBuilder.build(Unknown Source)
 	at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
 	at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
 	at sun.security.validator.Validator.validate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source)
 	at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.flushBuffer(AbstractSessionOutputBuffer.java:106)
 	at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:126)
 	at org.apache.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:99)
 	at org.apache.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:175)
	...


 






---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


RE: Webstart problems with SSL and the DEFAULT SSLSocketFactory

Posted by Mark Claassen <ma...@donnell.com>.
I will look into how to put a request in JIRA.

I didn't want to force you guys down a path that would not work for some reason.  My initial stance was just to make that constructor public, but I do not pretend to understand all the intricacies of a complex API like this.

So, here is a recommendation for a change with minimal impact on the API and existing clients:
* Make current getSocketFactory() deprecated, so others don't run into this problem
* Add method createSocketFactory(), as:

	public static SSLSocketFactory createSocketFactory() {
		return new SSLSocketFactory();
	}

This will:
1) Solve the problem
2) Preserve backwards compatibility
3) Encourage the new semantics
4) Ensure that any protections afforded by the private SSLSocketFactory are still in place

If the constructor is private just for historical reasons, than it may be easier to just make it public.  I think it is still a good idea to deprecate the getSocketFactory() method.  I would suspect that SocketFactories are not created often, so it does not seem that there is a reason to encourage the use of a global shared one via getSocketFactory().  If people want to use a particular socket factory, they should just create a new one.


-----Original Message-----
From: Oleg Kalnichevski [mailto:olegk@apache.org] 
Sent: Thursday, February 17, 2011 3:37 PM
To: HttpClient User Discussion
Subject: Re: Webstart problems with SSL and the DEFAULT SSLSocketFactory

     A. On Thu, 2011-02-17 at 14:48 -0500, Mark Claassen wrote:
> I have been using HttpClient for a while now with success.  However, I have recently encountering some problems which I think have
> an easy solution, although it is not accessible to me through the current API.
> 
> Situation (my test enviroment):
> 
> ServerA:
> * Runs Tomcat 6
> * Contains jar files that are downloaded via webstart
> * Only accepts non-SSL connections
> 
> ServerB:
> * Runs Tomcat 6
> * Contains jar files that are downloaded via webstart
> * Contains a servlet
> * Only accepts SSL connections
> 
> If I connect to serverB (via webstart) and download the jars, my app connects to the servlet on ServerB and everything is fine.
> However, if I connect to ServerA (via webstart), download the jars, and then the app tries to connect to ServerB, the SSL connection
> cannot be established.
> 
> I need to use the default socket factory since it is managed by webstart and automatically prompts for certificate issues and allows
> for automatic use of client certificates.
> 
> Theory
> ------
> Terminology:
> javax.SSLSocketFactory = javax.net.ssl.SSLSocketFactory apache.SSLSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory
> 
> I am confused about exactly why this is happening, but I have a theory.  In my theory, the crux of the problem is that the DEFAULT
> apache.SSLSocketFactory is set in the static initializer of the apache.SSLSocketFactory class.  In the first scenario, webstart
> creates a new javax.SSLSocketFactory for the jar download, and makes this the default.  This happens way before the
> apache.SSLSocketFactory is loaded.  In the second scenario, this happens in the other order and the javax.SSLSocketFactory wrapped
> by the apache.SSLSocketFactory is not the correct one.
> 
> If I could ensure that the javax.SSLSocketFactory is initialized first, and then create an apache.SSLSocketFactory to wrap this, I
> think I would be in good shape.  The apache.SSLSocketFactory does have a wrapping construtor, but it is the private no-argument
> constructor.  If this were public in some manner, I could ensure my apache.SSLSocketFactory wraps the correct one.
> 
> I don't really see a down-side to making this public.  However, if this needed to be private to prevent certain types of
> subclassing, a static factory method could be added to create an apache.SSLSocketFactory that wraps a javax.SSLSocketFactory.
> 
> Theory Corroborated
> --------------------
> I downloaded the httpclient 4.01 source (the version we are currently using), changed the no-arg constructor to be public, and used
> it to create a new apache.SSLSocketFactory after I initialized the HttpsURLConnection.  This did, indeed, solve the problem.
> Perhaps there is more going on here than I realize, but it was easy and it worked.
> 
> Formal Request:
> ---------------
> I would like to request that the API of apache.SSLSocketFactory be adjusted to handle this scenario.
> 
> My test Details:
> ----------------
> This is how I initialized the default socket factory:
> 
> HttpsURLConnection conn = (HttpsURLConnection)new URL(urlString).openConnection(); conn.setDoOutput(true); OutputStream os =
> conn.getOutputStream(); os.close(); conn.disconnect();
> 
> apache.SSLSocketFactory fact = new SSLSocketFactory();			
> schemeRegistry.register(new Scheme(scheme, fact, port));
> 

Mark

What kind of changes would you like us to do? Remove static
javax.SSLSocketFactory variable? Something else?

Probably the best course of actions would be to open a change request in
JIRA and attach a patch with changes you would like committed to the
project code repository.

Oleg


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: Webstart problems with SSL and the DEFAULT SSLSocketFactory

Posted by Oleg Kalnichevski <ol...@apache.org>.
     A. On Thu, 2011-02-17 at 14:48 -0500, Mark Claassen wrote:
> I have been using HttpClient for a while now with success.  However, I have recently encountering some problems which I think have
> an easy solution, although it is not accessible to me through the current API.
> 
> Situation (my test enviroment):
> 
> ServerA:
> * Runs Tomcat 6
> * Contains jar files that are downloaded via webstart
> * Only accepts non-SSL connections
> 
> ServerB:
> * Runs Tomcat 6
> * Contains jar files that are downloaded via webstart
> * Contains a servlet
> * Only accepts SSL connections
> 
> If I connect to serverB (via webstart) and download the jars, my app connects to the servlet on ServerB and everything is fine.
> However, if I connect to ServerA (via webstart), download the jars, and then the app tries to connect to ServerB, the SSL connection
> cannot be established.
> 
> I need to use the default socket factory since it is managed by webstart and automatically prompts for certificate issues and allows
> for automatic use of client certificates.
> 
> Theory
> ------
> Terminology:
> javax.SSLSocketFactory = javax.net.ssl.SSLSocketFactory apache.SSLSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory
> 
> I am confused about exactly why this is happening, but I have a theory.  In my theory, the crux of the problem is that the DEFAULT
> apache.SSLSocketFactory is set in the static initializer of the apache.SSLSocketFactory class.  In the first scenario, webstart
> creates a new javax.SSLSocketFactory for the jar download, and makes this the default.  This happens way before the
> apache.SSLSocketFactory is loaded.  In the second scenario, this happens in the other order and the javax.SSLSocketFactory wrapped
> by the apache.SSLSocketFactory is not the correct one.
> 
> If I could ensure that the javax.SSLSocketFactory is initialized first, and then create an apache.SSLSocketFactory to wrap this, I
> think I would be in good shape.  The apache.SSLSocketFactory does have a wrapping construtor, but it is the private no-argument
> constructor.  If this were public in some manner, I could ensure my apache.SSLSocketFactory wraps the correct one.
> 
> I don't really see a down-side to making this public.  However, if this needed to be private to prevent certain types of
> subclassing, a static factory method could be added to create an apache.SSLSocketFactory that wraps a javax.SSLSocketFactory.
> 
> Theory Corroborated
> --------------------
> I downloaded the httpclient 4.01 source (the version we are currently using), changed the no-arg constructor to be public, and used
> it to create a new apache.SSLSocketFactory after I initialized the HttpsURLConnection.  This did, indeed, solve the problem.
> Perhaps there is more going on here than I realize, but it was easy and it worked.
> 
> Formal Request:
> ---------------
> I would like to request that the API of apache.SSLSocketFactory be adjusted to handle this scenario.
> 
> My test Details:
> ----------------
> This is how I initialized the default socket factory:
> 
> HttpsURLConnection conn = (HttpsURLConnection)new URL(urlString).openConnection(); conn.setDoOutput(true); OutputStream os =
> conn.getOutputStream(); os.close(); conn.disconnect();
> 
> apache.SSLSocketFactory fact = new SSLSocketFactory();			
> schemeRegistry.register(new Scheme(scheme, fact, port));
> 

Mark

What kind of changes would you like us to do? Remove static
javax.SSLSocketFactory variable? Something else?

Probably the best course of actions would be to open a change request in
JIRA and attach a patch with changes you would like committed to the
project code repository.

Oleg


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org