Oleg, While reusing http context I encountered on thread-safety issue though. A *HttpRequest *is processed by *DefaultRequestDirector *which, among others, sets up currently used connection on the context object (a line from v4.2.5):
*515: context.setAttribute(ExecutionContext.HTTP_CONNECTION, managedConn);* This value is extracted later on by *DefaultUserTokenHandler* and used to retrieve user principal from SSL session associated with the connection. The multithreaded case lead to situation when the session is replaced between storing and retrieving, which, causes *DefaultUserTokenHandler*cannot find the user principal. Regards, Mateusz 2013/9/5 Oleg Kalnichevski <[email protected]> > On Thu, 2013-09-05 at 12:55 +0200, Mateusz P wrote: > > Oleg, > > What in case sacrificing performance is not possible? > > The system I work on is a ESB gateway with high volume traffic and > > processing requests one by one is not an option at all. > > However, all requests go to the same service and use exactly the same > > client-side certificate in mutual SSL handshake, so they could reuse the > > connections. > > The problem would be easier to solve if there would be separation between > > client context (holding all information specific for all connections like > > security context, cookie store etc) and execution context (holding > > information specific for a particular connection). > > My temporary solution is to save the first request's context and I create > > my own BasicContext for every subsequent request and provide USER_TOKEN > to > > it from the initially saved http context. > > If separation is not an option, I would appreciate utils class to > > extract/store client/execution context's attributes in one call. Having > > that I could improve my solution > > Please let me know what are your thoughts on that > > Regards, > > Mateusz > > > > Mateusz > > There is absolutely nothing that prevents you from using the same > HttpContext per worker thread. Those contexts could share the same > cookie store, credentials provider or any other thread safe object. > > If the same connection pool is not used anywhere else you might as well > disable connection state tracking. > > Oleg > > > > > On Mon, 2013-08-12 at 12:54 -0700, Erik Pilz wrote: > > > > > > Hi Oleg, > > > > > > > > Thanks for the clear and thoughtful reply explaining the design. For > my > > > own > > > > edification I was hoping you could elaborate on the scenario where > > > another > > > > consumer with a different security context would introduce a risk or > > > > problem. Are you referring to clients using a SSLContext other than > the > > > > system default? > > > > > > > > Thanks, > > > > Erik > > > > > > > > > > Hi Erik > > > > > > Consider the following scenario. Multiple threads consume the same > > > service (the same route) but using a different SSLContext with the > > > client auth set to required. The service handles requests differently > > > based on the security principal of the client certificate (user role). > > > You would not want HttpClient to carelessly hand out a persistent > > > connection to that service to the very first consumer that happens to > > > request it, would you? > > > > > > It is a fairly uncommon scenario, but when it comes to security, one > > > better be safe than sorry. Security considerations override those of > > > performance. > > > > > > Hope this helps > > > > > > Oleg > > > > > > > > > > > On Sun, Aug 11, 2013 at 3:34 AM, Oleg Kalnichevski <[email protected] > > > > > wrote: > > > > > > > > > On Fri, 2013-08-09 at 15:16 -0700, Erik Pilz wrote: > > > > > > We're migrating an old application from Java's > HttpsUrlConnection to > > > > > > HttpClient. After running a performance test we found a high cost > > > around > > > > > > connection acquisition. A bit of debugging later led me to find > that > > > > > we're > > > > > > not getting the full benefit of pooled connections. What I > eventually > > > > > found > > > > > > is that I have to create a HttpClientContext and populate the > > > userToken > > > > > > with some object and use HttpClient#execute(method, context). > This > > > wasn't > > > > > > obvious to me; is this intentional or did I just find a > workaround > > > to a > > > > > bug? > > > > > > > > > > ... > > > > > > > > > > > Calling HttpClient#execute(method) will create a context whose > > > userToken > > > > > is > > > > > > null. To work around the behavior it's instead necessary to > create an > > > > > > HttpClientContext and populate it with a userToken of your own > (it > > > can be > > > > > > any object); this will then be used as the state in the available > > > > > > connections instead of the principal from the SSLSession; you > then > > > use > > > > > > HttpClient#execute(method, context) in place of > > > > > HttpClient#execute(method). > > > > > > > > > > > > Thanks, > > > > > > Erik > > > > > > > > > > Hi Erik > > > > > > > > > > This is by design and not a defect. > > > > > > > > > > Mutually authenticated SSL connections are considered state-full > and > > > > > special measures are taken to make sure they cannot be leased to a > > > > > consumer with a different security context. Their state is > represented > > > > > by a user token, which is by default the security principal of the > > > > > client certificate. > > > > > > > > > > There are two ways you could resolve the issue > > > > > > > > > > (1) Disable connection state management if your application does > not > > > > > need to maintain a different security context per worker thread > > > > > > > > > > --- > > > > > CloseableHttpClient client = HttpClients.custom() > > > > > .disableConnectionState() > > > > > .build(); > > > > > --- > > > > > > > > > > (2) Simply make related requests share the same context > (recommended). > > > > > In this case SSL security principal of the initial request will be > > > added > > > > > to the execution context as a user token and propagated to all > > > > > subsequent requests. When leasing a persistent connection from the > > > > > connection pool HttpClient will use the user token to request a > > > > > connection with a specific state / security context. > > > > > > > > > > --- > > > > > CloseableHttpClient client = HttpClients.custom() > > > > > .build(); > > > > > HttpClientContext context = HttpClientContext.create(); > > > > > HttpGet get1 = new HttpGet("https://myhost/this"); > > > > > CloseableHttpResponse response1 = client.execute(get1, context); > > > > > try { > > > > > > > > > > } finally { > > > > > response1.close(); > > > > > } > > > > > HttpGet get2 = new HttpGet("https://myhost/that"); > > > > > CloseableHttpResponse response2 = client.execute(get2, context); > > > > > try { > > > > > > > > > > } finally { > > > > > response1.close(); > > > > > } > > > > > --- > > > > > > > > > > Oleg > > > > > > > > > > > > > > > > --------------------------------------------------------------------- > > > > > To unsubscribe, e-mail: [email protected] > > > > > For additional commands, e-mail: > [email protected] > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > >
