Proactive Basic Authentication with Apache HttpClient 4

Is there an easier way to configure the http client for proactive basic authentication than described here ?
In the previous version (3.x), this was a simple method call (e.g. httpClient.getParams().setAuthenticationPreemptive(true) ).
The main thing I want to avoid is to add a BasicHttpContext for every method that I execute.

+47
java basic-authentication
Jan 06 '10 at 17:05
source share
9 answers

This is difficult to do without passing the context through each time, but you can probably do this using a request interceptor. Here is some code we use (found from their JIRA, iirc):

 // Pre-emptive authentication to speed things up BasicHttpContext localContext = new BasicHttpContext(); BasicScheme basicAuth = new BasicScheme(); localContext.setAttribute("preemptive-auth", basicAuth); httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0); (...) static class PreemptiveAuthInterceptor implements HttpRequestInterceptor { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); // If no auth scheme avaialble yet, try to initialize it // preemptively if (authState.getAuthScheme() == null) { AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth"); CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authScheme != null) { Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort())); if (creds == null) { throw new HttpException("No credentials for preemptive authentication"); } authState.setAuthScheme(authScheme); authState.setCredentials(creds); } } } } 
+23
Aug 16 '10 at 13:49
source

If you want HttpClient 4 to authenticate with a single request, the following will work:

 String username = ... String password = ... UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password); HttpRequest request = ... request.addHeader(new BasicScheme().authenticate(creds, request)); 
+84
Dec 01 '10 at 20:20
source

This is the same solution as Mat Mannion, but you do not need to put localContext in every request. This is simpler, but adds authentication for ALL requests. Useful if you do not have control over individual requests, as in my case when using Apache Solr, which internally uses HttpClient.

 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.auth.Credentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.protocol.ClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0); (...) static class PreemptiveAuthInterceptor implements HttpRequestInterceptor { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); // If no auth scheme available yet, try to initialize it // preemptively if (authState.getAuthScheme() == null) { CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort())); if (creds == null) { throw new HttpException("No credentials for preemptive authentication"); } authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } } } 

Of course you must install the credential provider:

 httpClient.getCredentialsProvider().setCredentials( new AuthScope(url.getHost(), url.getPort()), new UsernamePasswordCredentials(username, password)) 

AuthScope should not contain an area, since it is not known in advance.

+16
Aug 08 2018-12-12T00:
source

The answers above use outdated code. I am using Apache SOLRJ version 5.0.0. My code consists of

 private HttpSolrClient solrClient; private void initialiseSOLRClient() { URL solrURL = null; try { solrURL = new URL(urlString); } catch (MalformedURLException e) { LOG.error("Cannot parse the SOLR URL!!" + urlString); throw new SystemException("Cannot parse the SOLR URL!! " + urlString, e); } String host = solrURL.getHost(); int port = solrURL.getPort(); AuthScope authScope = new AuthScope(host, port); BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); textEncryptor.setPassword("red bananas in the spring"); String decryptPass = textEncryptor.decrypt(pass); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, decryptPass); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( authScope, creds); HttpClientBuilder builder = HttpClientBuilder.create(); builder.addInterceptorFirst(new PreemptiveAuthInterceptor()); builder.setDefaultCredentialsProvider(credsProvider); CloseableHttpClient httpClient = builder.build(); solrClient = new HttpSolrClient(urlString, httpClient); } 

Now PreemptiveAuthInterceptor looks like this: -

 static class PreemptiveAuthInterceptor implements HttpRequestInterceptor { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE); // If no auth scheme available yet, try to initialize it // preemptively if (authState.getAuthScheme() == null) { CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); if(creds == null){ } authState.update(new BasicScheme(), creds); } } } 
+7
Mar 12 '15 at 14:27
source

A little late for the party, but I went through the stream trying to solve this problem for pre-authorization of the mail request. To add to Adam's answer, I found that this worked for me:

 HttpPost httppost = new HttpPost(url); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password); Header bs = new BasicScheme().authenticate(creds, httppost); httppost.addHeader("Proxy-Authorization", bs.getValue()); 

A thought that can be useful to anyone who comes across this.

+6
Jul 07 2018-11-17T00:
source

I think the best way is to just do it manually. I added the following function

Classic Java:

 import javax.xml.bind.DatatypeConverter; 

...

 private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException { String encoded = DatatypeConverter.printBase64Binary((username + ":" + password).getBytes("UTF-8")); http.addHeader("AUTHORIZATION", "Basic " + encoded); } 

HTTPRequestBase can be an instance of HttpGet or HttpPost

Android:

 import android.util.Base64; 

...

 private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException { String encoded = Base64.encodeToString((username + ":" + password).getBytes("UTF-8"), Base64.NO_WRAP); http.addHeader("AUTHORIZATION", "Basic " + encoded); } 
+6
Jan 19 '14 at 22:46
source

I use this code based on reading the HTTPClient 4.5 documentation :

 HttpClientContext ctx = HttpClientContext.create() ctx.setCredentialsProvider(new BasicCredentialsProvider()) ctx.setAuthCache(new BasicAuthCache()) UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user, pass) AuthScope authScope = new AuthScope(host, port) ctx.getCredentialsProvider.setCredentials(authScope, credentials) // This part makes authentication preemptive: HttpHost targetHost = new HttpHost(host, port, scheme) ctx.getAuthCache.put(targetHost, new BasicScheme()) 

... and make sure you always pass this context to HTTPClient.execute() .

+1
Mar 16 '17 at 19:12
source

I do not quite understand your final comment. This is an HttpClient that has all this equipment to run proactive auth, and you only need to do this once (when you create and configure your HttpClient). Once you do this, you instantiate the method in the same way as always. You are not adding the BasicHttpContext method to the method.

Best of all, I think, is to have your own object, which installs all the junk files needed for preemptive auth, and has a simple method or methods to execute requests on the specified HTTPMethod objects.

0
Jan 06 '10 at 17:11
source

in android, Mat Mannion's answer cannot allow https, still send two requests, you can do this as shown below, the trick adds authHeader with user-agent:

  public static DefaultHttpClient createProxyHttpClient() { try { final DefaultHttpClient client = createPlaintHttpClient(); client.setRoutePlanner(new HttpRoutePlanner() { @Override public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException { boolean isSecure = "https".equalsIgnoreCase(target.getSchemeName()); if (needProxy) { Header header = isSecure ? ProxyUtils.createHttpsAuthHeader() : ProxyUtils.createAuthHeader(); if (isSecure) { client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT + "\r\n" + header.getName() + ":" + header.getValue()); } else { client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT); if (request instanceof RequestWrapper) { request = ((RequestWrapper) request).getOriginal(); } request.setHeader(header); } String host = isSecure ? ProxyUtils.SECURE_HOST : ProxyUtils.HOST; int port = isSecure ? ProxyUtils.SECURE_PORT : ProxyUtils.PORT; return new HttpRoute(target, null, new HttpHost(host, port), isSecure); } else { client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT); return new HttpRoute(target, null, isSecure); } } }); return client; } catch (Exception e) { e.printStackTrace(); return new DefaultHttpClient(); } } public static DefaultHttpClient createPlaintHttpClient() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); PlainSSLSocketFactory socketFactory = new PlainSSLSocketFactory(trustStore); socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); BasicHttpParams params = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(params, 30000); HttpConnectionParams.setSoTimeout(params, 30000); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", socketFactory, 443)); ThreadSafeClientConnManager ccm = new ThreadSafeClientConnManager(params, registry); HttpClientParams.setCookiePolicy(params, CookiePolicy.BROWSER_COMPATIBILITY); final DefaultHttpClient client = new DefaultHttpClient(ccm, params); client.setRoutePlanner(new HttpRoutePlanner() { @Override public HttpRoute determineRoute(HttpHost target, HttpRequest arg1, HttpContext arg2) throws HttpException { client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT); return new HttpRoute(target, null, "https".equalsIgnoreCase(target.getSchemeName())); } }); return client; } catch (Exception e) { e.printStackTrace(); return new DefaultHttpClient(); } } 
0
Jan 29 '14 at 2:20
source



All Articles