Base64 Encoding Basic Authentication Header Apache HTTP Client - java

Two related questions, I'm using Apache HTTP Client 4.x API. myHttpPost is an instance of HttpPost and myHttpClient is an instance of HttpClient. I'm trying to send a request using basic authentication. So I have a HttpClient and create a HttpPost.
The 'brute force' way of setting a basic authentication header seems to be to set it in the HttpPost header.
String encoding = Base64Encoder.encode("username" + ":" + "password");
myHttpPost.setHeader("Authorization", "Basic " + encoding);
The example above came from another stack overflow question (can't find link to it now). In relation to the Base64Encoder class - which package would I find it in or where would I download it from?
Main question - I was hoping to do basic authentication in a more aesthetic manner using the code below:
myHttpClient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthPolicy.BASIC),
new UsernamePasswordCredentials("username", "password")
);
But this doesn't seem to work. So is the first example above the right way to do basic authentication with Apache HTTP Client 4.0? Or is there a cleaner/simpler way.

In relation to the Base64Encoder class - which package would I find it
in or where would I download it from?
Base64Encoder can come from various places, I couldn't find something that matches with your static encode method.
As for Credentials, you need to set scheme to Basic on your AuthScope, like so:
myHttpClient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "basic"),
new UsernamePasswordCredentials("username", "password")
);
or
myHttpClient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthPolicy.BASIC),
new UsernamePasswordCredentials("username", "password")
);

I know this is a really old post. But, just wanted to answer so that others will benefit in future:
If you are using a username which is to be represented using Variable width encoding (http://en.wikipedia.org/wiki/Variable-width_encoding), then make sure that you change the encoding used to form the bytes for (username:password) as follows:
HttpParams params = new BasicHttpParams();
params.setParameter(AuthPNames.CREDENTIAL_CHARSET, HTTP.UTF_8);
By default, the encoding used is HttpProtocolParams.HTTP_ELEMENT_CHARSET.

HttpClient does not attempt to authenticate with the origin or proxy server unless explicitly challenged. I suspect you would like HttpClient to authenticate preemptively. While the preemptive authentication is disabled per default (and I personally would discourage its application outside secure or internal networks) one can force the preemptive authentication using example below
http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java

I tried out the solution suggested in http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java and it works for Base64 Encoding Basic Authentication.
I guess the
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local
// auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(target, basicAuth);
// Add AuthCache to the execution context
HttpClientContext localContext = HttpClientContext.create();
localContext.setAuthCache(authCache);
makes the miracle :)
as without this i always receive "401 Unauthorized" HTTP response

Related

Can JCIFS be used with Jersey?

I have trouble adding NTLM authentication to my existing application that uses Jersey and Apache HttpClient. I was only able to authenticate using JCIFS, the default NTLM authentication from HttpClient does not work (I get 401).
The example from Apache HttpClient page shows how to use CloseableHttpClient:
https://hc.apache.org/httpcomponents-client-4.5.x/ntlm.html
Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.NTLM, new JCIFSNTLMSchemeFactory())
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.build();
But with CloseableHttpClient I cannot use methods like target:
WebTarget target = client.target(this.my Address).path(elementPath)
.resolveTemplate(P_ID, myId);
There is only execute.
I'm not sure if I should rewrite my whole application and use only basic HttpClient calls like:
HttpGet httpGet = new HttpGet(repositoryAddress + "/" + "element/70032_1498404600000(,,arm)");
CloseableHttpResponse response = httpClient.execute(httpGet);
or there is some other way to set AuthSchemes in javax.ws.rs.client.Client, which can be used in Jersey?
I faced similar issues and my approach was below :
1) If you are using ApacheConnectorProvider as Connector you can Override ApacheConnector code (found here https://github.com/jersey/jersey/tree/master/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector). In my case I had to create custom ConnectorProvider and Connector.
2) Create a custom property or use HttpClientContext.AUTHSCHEME_REGISTRY and put it in the ClientConfig ( This is how we set properties for client in Jersey Client).
3) The Custom connector gets called when you call builder.get( or post or any other method). In the custom connector you can check for the property set in the above step. If it is set, you can set the DefaultAuthSchemeRegistry just like it is specified for ClosableHttpClient(ApacheConnector uses ClosableHttpClient in its implementation).
This may be kind of a hack but works fine for me. Hope this helps :)

apache commons httpclient 4.23 form login problems different session cookies used in different requests

I have a protected resource which requires me to login. Im using the commons client with the following code block.
HttpClient httpClient = new HttpClient();
httpClient.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY);
httpClient.getParams().setParameter("http.protocol.single-cookie-header", Boolean.TRUE);
PostMethod postMethod = new PostMethod("/admin/adminlogon.do");
postMethod.setRequestEntity(new StringRequestEntity("action=logon&adminUser=admin&adminPassword=password",
"application/x-www-form-urlencoded",
"UTF-8"));
postMethod.addParameter("action","logon");
postMethod.addParameter("adminUser","admin");
postMethod.addParameter("adminPassword","password");
httpClient.executeMethod(postMethod);
String response2 = postMethod.getResponseBodyAsString();
Above is where I basically login. This works fine im getting a nice little JSESSIONID cookie back.
GetMethod get = new GetMethod("/admin/api.do?action=getSomeJson");
httpClient.executeMethod(get);
When I check the logic on the sever the for the 2nd request I notice that we are using a different JSESSIONID. Therefore the get seems to fail to log in. I was under the impression the httpClient managed the cookies and sent the same cookie back. When I log into my app normally through the UI I see the same cookie in each request just not in the this test code.
String s = get.getResponseBodyAsString();
get.releaseConnection();
Do I need to do something with the httpClient to ensure it uses the same cookies from the first post request when it does its get request??
Thanks in advance.
Your assumption regarding HTTP client cookie behavior is correct.
In your case your not use the same httpClient instance. To fix it you need to allocate the httpClient only once (in PostConstructor):
httpClient = new DefaultHttpClient(); // or new HttpClient();
Then, you perform your calls using the same instance of the client. The client will take a cookie from a response, will store it in the cookieStore and will send it with the next request.
[Added after the comment]
The following code works for me:
httpClient = new DefaultHttpClient();
// Create a local instance of cookie store
cookieStore = new BasicCookieStore();
// Set the store
httpClient.setCookieStore(cookieStore);

Can't authenticate with DefaultHttpClient

I want to add authentication header to my request. I'm using DefaultHttpClient from Apache httpclient 4.0.
I found that's done this way:
URI uri = new URI("http://www.bla.bla/folder/");
String host = uri.getHost();
int port = uri.getPort();
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(host, port, AuthScope.ANY_SCHEME),
new UsernamePasswordCredentials("myuser", "mypassword")
);
This is executed and even with the debugger I see some credentials variable of the httpClient are set at the moment of doing the request. But I inspect web traffic with Charles and there's no authentication header.
Content of vars:
host: www.bla.bla
port: -1
Btw. I enabled Charles as a proxy to see the headers of the request, with:
HttpHost proxy = new HttpHost("127.0.0.1", 8888, "http");
httpParameters.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
I think that should not be altering my headers, would make no sense for webproxy... anyways if I disable the proxy stuff it also doesn't work (although I can't see the content of the header but I suppose it's the same reason).
Also tried using a request interceptor like described in Softhinker.com's post here: How can I send HTTP Basic Authentication headers in Android?
And I get exactly the same request, without authentification header.
What am I doing wrong?
Thanks in advance.
I got it working setting the header "manually" in the request.
request.setHeader(new BasicHeader("Authorization", authstring));

HTTPClient sends out two requests when using Basic Auth?

I have been using HTTPClient version 4.1.2 to try to access a REST over HTTP API that requires Basic Authentication. Here is client code:
DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager());
// Enable HTTP Basic Auth
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(this.username, this.password));
HttpHost proxy = new HttpHost(this.proxyURI.getHost(), this.proxyURI.getPort());
httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, proxy);
When I construct a POST request, like this:
HttpPost request = new HttpPost("http://my/url");
request.addHeader(new BasicHeader("Content-type", "application/atom+xml; type=entry")); // required by vendor
request.setEntity(new StringEntity("My content"));
HttpResponse response = client.execute(request);
I see in Charles Proxy that there are two requests being sent. One without the Authorization: Basic ... header and one with it. The first one fails with a 401, as you would expect, but the second goes through just fine with a 201.
Does anyone know why this happens? Thanks!
EDIT:
I should make clear that I have already looked at this question, but as you can see I set the AuthScope the same way and it didn't solve my problem. Also, I am creating a new HttpClient every time I made a request (though I use the same ConnectionManager), but even if I use the same HttpClient for multiple requests, the problem still persists.
EDIT 2:
So it looks like what #LastCoder was suggesting is the way to do. See this answer to another question. The problem stems from my lack of knowledge around the HTTP spec. What I'm looking to do is called "preemptive authentication" and the HttpClient docs mention it here. Thankfully, the answer linked to above is a much shorter and cleaner way to do it.
Rather than using .setCredentials() why don't you just encode USERNAME:PASSWORD and add the authentication header with .addHeader()
This means that your server/target endpoint is creating a new session for every client request. This forces every request of yours to go through a hand-shake, which means the clients first makes the call and realizes that it needs authorization, then it follows with the authorization. What you need to do is send the authorization preemptively as follows:
httpClient.getParams().setAuthenticationPreemptive(true);
Just to understand the process you may log your client request headers, to give you an idea of what your client is sending and receiving:
See if this works.

How to get last sent HTTP request android

I am trying to send a GET request to the web server from the android device, the server is having digest authentication enabled, I am able to authenticate using following sort of code,
HttpHost host = new HttpHost(urlObj.getHost(), -1, null);
CredentialsProvider cp = new BasicCredentialsProvider();
cp.setCredentials(scope, creds);
HttpContext credContext = new BasicHttpContext();
credContext.setAttribute(ClientContext.CREDS_PROVIDER, cp);
Now my problem is every time when I call httpClient.execute() function it first send request without authentication header and then second time with proper headers. So is there any way I can instruct HttpClient to send authentication details by default?
One way is to store the last sent request but, I am also not able to get the last sent request. Any suggestion on this?
Thanks in advance.
You may use HttpURLConnection to save all the params you need. I use it and display my source code here.
url_connection is defined like that
private HttpURLConnection url_connection; // WebService Connection
url_connection= (HttpURLConnection) new URL(your_url_server).openConnection();
url_connection.setRequestMethod("POST");
url_connection.setDoInput(true);
url_connection.setDoOutput(true);
....

Categories

Resources