Further debugged the issue and investigated httpclient code. For Basic Auth , DefaultUserTokenHandler.getAuthPrincipal(..) retrurns null .
Should i change this implementation and return userName instead? On Wed, Sep 17, 2014 at 6:05 PM, Sukhdev Singh <[email protected]> wrote: > One more observation on it. > > I don't see this issue when I lock httpclient.execute (...) and let it run > by 1 thread at a time. > Looks like in httpclient 4.1.2, httpclient.execute(...) is not thread safe > as credentials are being overwritten by another thread. > > How to fix this issue. Any setting in httpclient? > > Regards > Sukhdev > > On Wed, Sep 17, 2014 at 12:45 AM, Sukhdev Singh <[email protected]> > wrote: > >> I am using httpclient 4.1.3 in my project. >> >> I am creating single httpclient instance with ThreadSafeClientConnManager. >> I don't see alternative to ThreadSafeClientConnManager in httpclient >> 4.1.3. >> >> Intermittently I am experiencing that http request being made for >> another user which is not the intended user. I am setting credentials in >> AuthState and using localHttpClient. >> >> My test includes - >> - Six threads running in parallel each calling REST API 10 time >> - Endpoint URL is same for all request so HttpHost is same. >> - There are six authenticating users. Each thread correspond to 1 thread. >> >> Pasting code below. Please let me know if i am missing anything in main >> code. I am not printing my test code here. >> >> import java.io.IOException; >> >> import java.security.cert.CertificateException; >> >> import java.security.cert.X509Certificate; >> >> >> import org.apache.http.HttpException; >> >> import org.apache.http.HttpHost; >> >> import org.apache.http.HttpRequest; >> >> import org.apache.http.HttpRequestInterceptor; >> >> import org.apache.http.auth.AuthScope; >> >> import org.apache.http.auth.AuthState; >> >> import org.apache.http.client.CredentialsProvider; >> >> import org.apache.http.client.params.HttpClientParams; >> >> import org.apache.http.client.protocol.ClientContext; >> >> import org.apache.http.conn.ClientConnectionManager; >> >> import org.apache.http.conn.scheme.Scheme; >> >> import org.apache.http.conn.scheme.SchemeRegistry; >> >> import org.apache.http.conn.ssl.SSLSocketFactory; >> >> import org.apache.http.conn.ssl.TrustStrategy; >> >> import org.apache.http.impl.auth.BasicScheme; >> >> import org.apache.http.impl.client.DefaultHttpClient; >> >> import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; >> >> import org.apache.http.params.HttpConnectionParams; >> >> import org.apache.http.protocol.ExecutionContext; >> >> import org.apache.http.protocol.HttpContext; >> >> import org.apache.log4j.Logger; >> >> >> public class BasicAuthRestClient extends AbstractRestClient{ >> >> private static int HTTP_CONN_TIMEOUT = 30*1000; //30 second >> >> private static int HTTP_SOCKET_TIMEOUT = 5*60*1000; //5 minute >> >> private static int HTTP_MAX_CONN = 1000; >> >> private static int HTTP_MAX_PER_ROUTE = 100; >> >> >> public BasicAuthRestClient(String baseUrl){ >> >> >> this.baseUrl = baseUrl; >> >> SchemeRegistry registry = new SchemeRegistry(); >> >> SSLSocketFactory socketFactory; >> >> try { >> >> socketFactory = new SSLSocketFactory(new TrustStrategy() { >> >> @Override >> >> public boolean isTrusted(X509Certificate[] arg0, String arg1) >> >> throws CertificateException { >> >> return true; >> >> } >> >> }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER >> ); >> >> registry.register(new Scheme("https", HTTP_SSL_PORT, >> socketFactory)); >> >> } catch (Exception e) { >> >> logger.error("exception in creating SSLSocketFactory", e); >> >> } >> >> >> ClientConnectionManager connMgr = new >> ThreadSafeClientConnManager(registry); >> >> ((ThreadSafeClientConnManager)connMgr).setMaxTotal(HTTP_MAX_CONN >> ); >> >> ((ThreadSafeClientConnManager)connMgr).setDefaultMaxPerRoute( >> HTTP_MAX_PER_ROUTE); >> >> >> >> httpClient = new DefaultHttpClient(connMgr); >> >> //setting request interceptor >> >> ((DefaultHttpClient)httpClient).addRequestInterceptor(new >> HttpBasicAuthInterceptor(), 0); >> >> >> HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), >> HTTP_CONN_TIMEOUT); >> >> HttpConnectionParams.setSoTimeout(httpClient.getParams(), >> HTTP_SOCKET_TIMEOUT); >> >> HttpConnectionParams.setStaleCheckingEnabled(httpClient.getParams(), >> true); >> >> HttpConnectionParams.setTcpNoDelay(httpClient.getParams(), true); >> >> >> HttpClientParams.setAuthenticating(httpClient.getParams(), true); >> >> HttpClientParams.setRedirecting(httpClient.getParams(), false); >> >> } >> >> >> static class HttpBasicAuthInterceptor implements >> HttpRequestInterceptor { >> >> public void process( >> >> final HttpRequest request, >> >> final HttpContext context) throws HttpException, >> IOException { >> >> AuthState authState = (AuthState) >> context.getAttribute(ClientContext.TARGET_AUTH_STATE); >> >> CredentialsProvider credProvider = >> (CredentialsProvider)context.getAttribute( >> >> ClientContext.CREDS_PROVIDER); >> >> >> >> HttpHost targetHost = (HttpHost)context.getAttribute( >> >> ExecutionContext.HTTP_TARGET_HOST); >> >> >> >> authState.setCredentials(credProvider.getCredentials( >> >> new AuthScope(targetHost.getHostName(), >> targetHost.getPort()))); >> >> >> >> authState.setAuthScheme((BasicScheme)context.getAttribute( >> "preemptive-auth")); >> >> } >> >> } >> >> >> private HttpContext createHttpContext(String userName, String >> password){ >> >> String host = Utils.getHostName(baseUrl); >> >> >> BasicHttpContext localcontext = new BasicHttpContext(); >> >> BasicScheme basicAuth = new BasicScheme(); >> >> localcontext.setAttribute("preemptive-auth", basicAuth); >> >> CredentialsProvider credProvider = new BasicCredentialsProvider(); >> >> credProvider.setCredentials( >> >> new AuthScope(host, HTTP_SSL_PORT), >> >> new UsernamePasswordCredentials(userName, password)); >> >> localcontext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider); >> >> localcontext.setAttribute( >> >> ClientContext.TARGET_AUTH_STATE, new AuthState()); >> >> HttpHost targetHost = new HttpHost(host, HTTP_SSL_PORT, "https"); >> >> localcontext.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost); >> >> return localcontext; >> >> } >> >> >> >> public String doGet(final String url, >> >> final String userName, final String password) throws >> RestClientException { >> >> HttpGet httpget = new HttpGet(this.baseUrl + url); >> >> HttpResponse response = null; >> >> try { >> >> HttpContext localcontext = createHttpContext(userName, password); >> >> >> response = httpClient.execute(httpget, localcontext); >> >> return handleHttpResponse(response); >> >> } catch (ClientProtocolException e) { >> >> throw new RestClientException(e); >> >> } catch (IllegalStateException e) { >> >> throw new RestClientException(e); >> >> } catch (IOException e) { >> >> throw new RestClientException(e); >> >> } catch (Exception e){ >> >> throw new RestClientException(e); >> >> }finally{ >> >> try { >> >> EntityUtils.consume(response.getEntity()); >> >> } catch (Exception e) { >> >> logger.warn("Exception in EntityUtils.consume - ", e); >> >> } >> >> httpClient.getConnectionManager().closeIdleConnections(60000, >> >> TimeUnit.MILLISECONDS); >> >> httpClient.getConnectionManager().closeExpiredConnections(); >> >> } >> >> } >> >> } >> >> >> Regards >> Sukhdev >> > >
