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 Sachin Nikumbh <sa...@gmail.com> on 2013/04/29 17:27:04 UTC
HTTP async client and accessing server certificate (SSL)
Hi,
I am currently using the HTTP async client in my application to communicate
with a proprietary server. Now, I need to extend the functionality to
include HTTPS support. We need to provide client authentication and I have
the following picture of how I can provide client credentials.
My first question is, is this the correct approach? Am I missing anything
here?
************************************************
SSLContext context = ..... ; // Create with user provided
keystore/truststore
AsyncScheme scheme = new AsyncScheme( "https", 9910, new
SSLLayeringStrategy(context) );
HttpAsyncClient httpClientAsync = new DefaultHttpAsyncClient();
PoolingClientAsyncConnectionManager connectionMgr =
(PoolingClientAsyncConnectionManager)httpClientAsync.getConnectionManager();
AsyncSchemeRegistry asyncReg = connectionMgr.getSchemeRegistry();
asyncReg.register(scheme);
************************************************
My second question is about server authorization for which I need access to
the server certificate. I need to get the CN value from the certificate
which I am later going to use internally. I am basically looking for
something similar to java.net.HttpsUrlConnection.getPeerPrincipal or
java.net.HttpsUrlConnection.getServerCertificates.
Any help will be greatly appreciated.
Thanks
Sachin
Re: HTTP async client and accessing server certificate (SSL)
Posted by Sachin Nikumbh <sa...@gmail.com>.
Throwing an SSLException was the right thing to do. Now, everything is
working as expected.
Thanks a lot
Sachin
On Fri, May 31, 2013 at 4:59 AM, Oleg Kalnichevski <ol...@apache.org> wrote:
> On Thu, 2013-05-30 at 15:07 -0400, Sachin Nikumbh wrote:
> > Hi Oleg,
> >
> > Thanks for your reply. I started digging through the Apache async client
> > code and have come with a way to access the server certificate
> immediately
> > after the SSL handshake in the verify method of SSLSetupHandler, To
> achieve
> > this, I created my own MySSLLayeringStrategy class that
> > extends SSLLayeringStrategy as shows below :
> >
> > ********************************************************
> > class MySSLLayeringStrategy extends SSLLayeringStrategy{
> >
> > private SSLContext sslContext;
> >
> > public MySSLLayeringStrategy(SSLContext context){
> > super(context);
> > this.sslContext = context;
> > }
> >
> > protected void initializeEngine(final SSLEngine engine) {
> > super.initializeEngine(engine);
> > }
> >
> > protected void verifySession(final IOSession iosession,
> > final SSLSession sslsession) throws
> SSLException {
> > super.verifySession(iosession, sslsession);
> > }
> >
> > public SSLIOSession layer(final IOSession iosession) {
> > SSLIOSession ssliosession = new SSLIOSession(iosession,
> > SSLMode.CLIENT, this.sslContext,
> > new MySSLSetupHandler());
> > iosession.setAttribute(SSLIOSession.SESSION_KEY,
> ssliosession);
> > return ssliosession;
> > }
> >
> > class MySSLSetupHandler implements SSLSetupHandler {
> >
> > public void initalize(
> > final SSLEngine sslengine) throws SSLException {
> > initializeEngine(sslengine);
> > }
> >
> > public void verify(
> > final IOSession iosession,
> > final SSLSession sslsession) throws SSLException {
> >
> > verifySession(iosession, sslsession);
> >
> > // Now that basic hostname verification is done, perform
> > extra authorization based on peer DN
> > String peerDN = sslsession.getPeerPrincipal().getName();
> > if ( !authorizedPeer(peerDN) ){
> > throw new RuntimeException("Authorization failed");
> > }
> > }
> > }
> > }
> > ********************************************************
> >
> > Now, I am using MySSLLayeringStrategy to create AsyncScheme
> >
> > ********************************************************
> > AsyncScheme scheme = new AsyncScheme( "https", 443, new
> > MySSLLayeringStrategy(sslContext) );
> > ********************************************************
> >
> > This seems to be doing the job but the exception thrown in the verify
> > method causes the DefaultHttpAsyncClient instance to close abnormally as
> I
> > can see from the exception thrown:
> >
>
> Why are throwing a RuntimeException exception for what is clearly an SSL
> issue?
>
> Oleg
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> For additional commands, e-mail: httpclient-users-help@hc.apache.org
>
>
Re: HTTP async client and accessing server certificate (SSL)
Posted by Oleg Kalnichevski <ol...@apache.org>.
On Thu, 2013-05-30 at 15:07 -0400, Sachin Nikumbh wrote:
> Hi Oleg,
>
> Thanks for your reply. I started digging through the Apache async client
> code and have come with a way to access the server certificate immediately
> after the SSL handshake in the verify method of SSLSetupHandler, To achieve
> this, I created my own MySSLLayeringStrategy class that
> extends SSLLayeringStrategy as shows below :
>
> ********************************************************
> class MySSLLayeringStrategy extends SSLLayeringStrategy{
>
> private SSLContext sslContext;
>
> public MySSLLayeringStrategy(SSLContext context){
> super(context);
> this.sslContext = context;
> }
>
> protected void initializeEngine(final SSLEngine engine) {
> super.initializeEngine(engine);
> }
>
> protected void verifySession(final IOSession iosession,
> final SSLSession sslsession) throws SSLException {
> super.verifySession(iosession, sslsession);
> }
>
> public SSLIOSession layer(final IOSession iosession) {
> SSLIOSession ssliosession = new SSLIOSession(iosession,
> SSLMode.CLIENT, this.sslContext,
> new MySSLSetupHandler());
> iosession.setAttribute(SSLIOSession.SESSION_KEY, ssliosession);
> return ssliosession;
> }
>
> class MySSLSetupHandler implements SSLSetupHandler {
>
> public void initalize(
> final SSLEngine sslengine) throws SSLException {
> initializeEngine(sslengine);
> }
>
> public void verify(
> final IOSession iosession,
> final SSLSession sslsession) throws SSLException {
>
> verifySession(iosession, sslsession);
>
> // Now that basic hostname verification is done, perform
> extra authorization based on peer DN
> String peerDN = sslsession.getPeerPrincipal().getName();
> if ( !authorizedPeer(peerDN) ){
> throw new RuntimeException("Authorization failed");
> }
> }
> }
> }
> ********************************************************
>
> Now, I am using MySSLLayeringStrategy to create AsyncScheme
>
> ********************************************************
> AsyncScheme scheme = new AsyncScheme( "https", 443, new
> MySSLLayeringStrategy(sslContext) );
> ********************************************************
>
> This seems to be doing the job but the exception thrown in the verify
> method causes the DefaultHttpAsyncClient instance to close abnormally as I
> can see from the exception thrown:
>
Why are throwing a RuntimeException exception for what is clearly an SSL
issue?
Oleg
---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org
Re: HTTP async client and accessing server certificate (SSL)
Posted by Sachin Nikumbh <sa...@gmail.com>.
Hi Oleg,
Thanks for your reply. I started digging through the Apache async client
code and have come with a way to access the server certificate immediately
after the SSL handshake in the verify method of SSLSetupHandler, To achieve
this, I created my own MySSLLayeringStrategy class that
extends SSLLayeringStrategy as shows below :
********************************************************
class MySSLLayeringStrategy extends SSLLayeringStrategy{
private SSLContext sslContext;
public MySSLLayeringStrategy(SSLContext context){
super(context);
this.sslContext = context;
}
protected void initializeEngine(final SSLEngine engine) {
super.initializeEngine(engine);
}
protected void verifySession(final IOSession iosession,
final SSLSession sslsession) throws SSLException {
super.verifySession(iosession, sslsession);
}
public SSLIOSession layer(final IOSession iosession) {
SSLIOSession ssliosession = new SSLIOSession(iosession,
SSLMode.CLIENT, this.sslContext,
new MySSLSetupHandler());
iosession.setAttribute(SSLIOSession.SESSION_KEY, ssliosession);
return ssliosession;
}
class MySSLSetupHandler implements SSLSetupHandler {
public void initalize(
final SSLEngine sslengine) throws SSLException {
initializeEngine(sslengine);
}
public void verify(
final IOSession iosession,
final SSLSession sslsession) throws SSLException {
verifySession(iosession, sslsession);
// Now that basic hostname verification is done, perform
extra authorization based on peer DN
String peerDN = sslsession.getPeerPrincipal().getName();
if ( !authorizedPeer(peerDN) ){
throw new RuntimeException("Authorization failed");
}
}
}
}
********************************************************
Now, I am using MySSLLayeringStrategy to create AsyncScheme
********************************************************
AsyncScheme scheme = new AsyncScheme( "https", 443, new
MySSLLayeringStrategy(sslContext) );
********************************************************
This seems to be doing the job but the exception thrown in the verify
method causes the DefaultHttpAsyncClient instance to close abnormally as I
can see from the exception thrown:
********************************************************
.May 30, 2013 2:30:18 PM
org.apache.http.impl.nio.client.InternalIOReactorExceptionHandler handle
SEVERE: Fatal runtime error
java.lang.RuntimeException: Authorization failed
....
....
May 30, 2013 2:30:18 PM
org.apache.http.impl.nio.client.AbstractHttpAsyncClient doExecute
SEVERE: I/O reactor terminated abnormally
org.apache.http.nio.reactor.IOReactorException: I/O dispatch worker
terminated abnormally
at
org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:382)
at
org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager.execute(PoolingClientAsyncConnectionManager.java:108)
....
....
Caused by: java.lang.RuntimeException: Authorization failed
....
....
********************************************************
Is my approach for accessing server certificate safe? If so, what is the
safe way of throwing exception from the verify method?
Thanks
Sachin
On Wed, May 15, 2013 at 9:21 AM, Oleg Kalnichevski <ol...@apache.org> wrote:
> On Mon, 2013-05-13 at 22:10 -0400, Sachin Nikumbh wrote:
> > Hi Oleg,
> >
> > Thanks a lot for the response. I have one more question.
> >
> > In my client application, I need to provide extra authorization based on
> > the common name in the server certificate. I want to allow the
> > request-response exchange (I am sending a POST request) only after the
> > server passes this extra authorization step.
> >
> > Is using BasicAsyncResponseConsumer going be too late for me to access
> the
> > server certificate?
> >
> > I want the behavior similar to following sample code based
> > on HttpsURLConnection :
> >
> >
> ************************************************************************************************************
> > HttpsURLConnection urlConnection =
> > (HttpsURLConnection)madsUrl.openConnection();
> > urlConnection.setRequestMethod("POST");
> > ...
> > ...
> > urlConnection.connect(); //Establish connection for initial SSL handshake
> > String peerDN = urlConnection.getPeerPrincipal().getName();
> > if( isAuthorizedPeer(peerDN) ){
> > // Now it's safe to write request data
> > OutputStream oStream = urlConnection.getOutputStream();
> > ...
> > ...
> > }
> >
> ************************************************************************************************************
> >
> > Thanks once again
> > Sachin
> >
> >
>
> Hi Sachin
>
> There is currently no easy way of obtaining the SSL session details
> prior to issuing a request. Feel free to raise an improvement request in
> JIRA for this problem.
>
> Oleg
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> For additional commands, e-mail: httpclient-users-help@hc.apache.org
>
>
Re: HTTP async client and accessing server certificate (SSL)
Posted by Oleg Kalnichevski <ol...@apache.org>.
On Mon, 2013-05-13 at 22:10 -0400, Sachin Nikumbh wrote:
> Hi Oleg,
>
> Thanks a lot for the response. I have one more question.
>
> In my client application, I need to provide extra authorization based on
> the common name in the server certificate. I want to allow the
> request-response exchange (I am sending a POST request) only after the
> server passes this extra authorization step.
>
> Is using BasicAsyncResponseConsumer going be too late for me to access the
> server certificate?
>
> I want the behavior similar to following sample code based
> on HttpsURLConnection :
>
> ************************************************************************************************************
> HttpsURLConnection urlConnection =
> (HttpsURLConnection)madsUrl.openConnection();
> urlConnection.setRequestMethod("POST");
> ...
> ...
> urlConnection.connect(); //Establish connection for initial SSL handshake
> String peerDN = urlConnection.getPeerPrincipal().getName();
> if( isAuthorizedPeer(peerDN) ){
> // Now it's safe to write request data
> OutputStream oStream = urlConnection.getOutputStream();
> ...
> ...
> }
> ************************************************************************************************************
>
> Thanks once again
> Sachin
>
>
Hi Sachin
There is currently no easy way of obtaining the SSL session details
prior to issuing a request. Feel free to raise an improvement request in
JIRA for this problem.
Oleg
---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org
Re: HTTP async client and accessing server certificate (SSL)
Posted by Sachin Nikumbh <sa...@gmail.com>.
Hi Oleg,
Thanks a lot for the response. I have one more question.
In my client application, I need to provide extra authorization based on
the common name in the server certificate. I want to allow the
request-response exchange (I am sending a POST request) only after the
server passes this extra authorization step.
Is using BasicAsyncResponseConsumer going be too late for me to access the
server certificate?
I want the behavior similar to following sample code based
on HttpsURLConnection :
************************************************************************************************************
HttpsURLConnection urlConnection =
(HttpsURLConnection)madsUrl.openConnection();
urlConnection.setRequestMethod("POST");
...
...
urlConnection.connect(); //Establish connection for initial SSL handshake
String peerDN = urlConnection.getPeerPrincipal().getName();
if( isAuthorizedPeer(peerDN) ){
// Now it's safe to write request data
OutputStream oStream = urlConnection.getOutputStream();
...
...
}
************************************************************************************************************
Thanks once again
Sachin
On Tue, Apr 30, 2013 at 6:46 AM, Oleg Kalnichevski <ol...@apache.org> wrote:
> On Mon, 2013-04-29 at 11:27 -0400, Sachin Nikumbh wrote:
> > Hi,
> >
> > I am currently using the HTTP async client in my application to
> communicate
> > with a proprietary server. Now, I need to extend the functionality to
> > include HTTPS support. We need to provide client authentication and I
> have
> > the following picture of how I can provide client credentials.
> >
> > My first question is, is this the correct approach? Am I missing anything
> > here?
> >
> > ************************************************
> >
> > SSLContext context = ..... ; // Create with user provided
> > keystore/truststore
> >
> > AsyncScheme scheme = new AsyncScheme( "https", 9910, new
> > SSLLayeringStrategy(context) );
> >
> > HttpAsyncClient httpClientAsync = new DefaultHttpAsyncClient();
> >
> > PoolingClientAsyncConnectionManager connectionMgr =
> >
> (PoolingClientAsyncConnectionManager)httpClientAsync.getConnectionManager();
> >
> > AsyncSchemeRegistry asyncReg = connectionMgr.getSchemeRegistry();
> >
> > asyncReg.register(scheme);
> > ************************************************
> >
> > My second question is about server authorization for which I need access
> to
> > the server certificate. I need to get the CN value from the certificate
> > which I am later going to use internally. I am basically looking for
> > something similar to java.net.HttpsUrlConnection.getPeerPrincipal or
> > java.net.HttpsUrlConnection.getServerCertificates.
> >
> > Any help will be greatly appreciated.
> >
> > Thanks
> > Sachin
>
> You can get full access to the SSL session details from the local
> execution context:
>
> ---
> final HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
> httpclient.start();
> try {
> final HttpHost host = new HttpHost("www.verisign.com", -1, "https");
> final HttpGet request = new HttpGet("/");
> final BasicAsyncRequestProducer requestProducer = new
> BasicAsyncRequestProducer(host, request);
> final BasicAsyncResponseConsumer responseConsumer = new
> BasicAsyncResponseConsumer() {
>
> @Override
> protected HttpResponse buildResult(final HttpContext context) {
> final ManagedClientAsyncConnection conn =
> (ManagedClientAsyncConnection) context.getAttribute(
> ExecutionContext.HTTP_CONNECTION);
> final SSLSession sslsession = conn.getSSLSession();
> if (sslsession != null) {
> try {
> System.out.println(sslsession.getPeerPrincipal());
> } catch (final SSLPeerUnverifiedException e) {
> }
> }
> return super.buildResult(context);
> }
>
> };
> final Future<HttpResponse> future =
> httpclient.execute(requestProducer, responseConsumer, null);
> final HttpResponse response = future.get();
> System.out.println("Response: " + response.getStatusLine());
> System.out.println("Shutting down");
> } finally {
> httpclient.shutdown();
> }
> ---
>
> Hope this helps
>
> Oleg
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> For additional commands, e-mail: httpclient-users-help@hc.apache.org
>
>
Re: HTTP async client and accessing server certificate (SSL)
Posted by Oleg Kalnichevski <ol...@apache.org>.
On Mon, 2013-04-29 at 11:27 -0400, Sachin Nikumbh wrote:
> Hi,
>
> I am currently using the HTTP async client in my application to communicate
> with a proprietary server. Now, I need to extend the functionality to
> include HTTPS support. We need to provide client authentication and I have
> the following picture of how I can provide client credentials.
>
> My first question is, is this the correct approach? Am I missing anything
> here?
>
> ************************************************
>
> SSLContext context = ..... ; // Create with user provided
> keystore/truststore
>
> AsyncScheme scheme = new AsyncScheme( "https", 9910, new
> SSLLayeringStrategy(context) );
>
> HttpAsyncClient httpClientAsync = new DefaultHttpAsyncClient();
>
> PoolingClientAsyncConnectionManager connectionMgr =
> (PoolingClientAsyncConnectionManager)httpClientAsync.getConnectionManager();
>
> AsyncSchemeRegistry asyncReg = connectionMgr.getSchemeRegistry();
>
> asyncReg.register(scheme);
> ************************************************
>
> My second question is about server authorization for which I need access to
> the server certificate. I need to get the CN value from the certificate
> which I am later going to use internally. I am basically looking for
> something similar to java.net.HttpsUrlConnection.getPeerPrincipal or
> java.net.HttpsUrlConnection.getServerCertificates.
>
> Any help will be greatly appreciated.
>
> Thanks
> Sachin
You can get full access to the SSL session details from the local
execution context:
---
final HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
httpclient.start();
try {
final HttpHost host = new HttpHost("www.verisign.com", -1, "https");
final HttpGet request = new HttpGet("/");
final BasicAsyncRequestProducer requestProducer = new
BasicAsyncRequestProducer(host, request);
final BasicAsyncResponseConsumer responseConsumer = new
BasicAsyncResponseConsumer() {
@Override
protected HttpResponse buildResult(final HttpContext context) {
final ManagedClientAsyncConnection conn =
(ManagedClientAsyncConnection) context.getAttribute(
ExecutionContext.HTTP_CONNECTION);
final SSLSession sslsession = conn.getSSLSession();
if (sslsession != null) {
try {
System.out.println(sslsession.getPeerPrincipal());
} catch (final SSLPeerUnverifiedException e) {
}
}
return super.buildResult(context);
}
};
final Future<HttpResponse> future =
httpclient.execute(requestProducer, responseConsumer, null);
final HttpResponse response = future.get();
System.out.println("Response: " + response.getStatusLine());
System.out.println("Shutting down");
} finally {
httpclient.shutdown();
}
---
Hope this helps
Oleg
---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org