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