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.
Related
i want to send a SAML request to my IDP (Azure AD) but ia m not sure how to send the request at all.
First i used OpenSAML to build an AuthRequest. Which i encoded as a String.
Now i wanted to use ApacheHttpClient to send the request and read the response and i am not sure if OpenSAML provides http sending methods at all so my idea was to use Apaches HttpClient for this for now.
String encodedAuthRequest = generateAuthRequest();
String url = "http://myidp/samlendpoint";
CloseableHttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
// add request header
request.addHeader("User-Agent", USER_AGENT);
// what is to add else?
HttpResponse response = client.execute(request);
I am stuck now since i am not sure how to setup the request, does it need to be a query parameter like ?saml=.... in GET or do i have to put the encoded saml response in the body as POST..
Can someone help or clarify these issue?
Update from Guillaumes answer:
I have this from the IDPs MetaData:
<IDPSSODescriptor>
<SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://myidp/saml2" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://myidp/saml2" />
Depends on which binding you are supposed to use. The IdP documentation or metadata should mention that. There are several:
Redirect Binding (using a GET), by far the most common for Requests
POST Binding
Artifact Binding (more complex, but I have never seen it used for Requests)
...
I suppose that Redirect Binding will be used in your case (EDIT: you added the metadata from your IdP, it mentions that you can use both Redirect and POST bindings). It is described here: https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf page 15.
Short version: your must first use the DEFLATE algorithm to compress your XML Request, encode it using base64, encode it using URL encoding, then pass it as a query parameter named SAMLRequest
?SAMLRequest=<your url-encoded base64-encoded deflated authnrequest>
https://en.wikipedia.org/wiki/SAML_2.0#SP_Redirect_Request.3B_IdP_POST_Response
I am migrating my httpclient 3.x to httpclient 4.3.x.
With httpClient 3.x I used setDoAuthentication(false) which ensured that the method would not try to handle the authentication challenges automatically. How can I set the same functionality with httpClient 4.3.x?
I already went through the javadocs of httpmethods and httpclient and there is no way to do it. The closest I have been is the use of disableAuthCaching() in httpClientBuilder, but not sure whether it would serve the purpose.
Can anyone please provide some pointers?
I have read somewhere that there is a parameter through which we can achieve this behavior but I am not able to find it anywhere. Sorry if it looks like a pretty basic question.
I think I got it. I guess it can be done by setting the setDoAuthentication() method to false in the requestConfig for httpClient.
#spock8190 thanks for your post this gave me the correct hint.
But the new method name is setAuthenticationEnabled (at least for 4.5)
Determines whether authentication should be handled automatically.
Example:
HttpGet httpGet = new HttpGet("test.de");
RequestConfig requestConfig = RequestConfig.custom().setAuthenticationEnabled(true).build();
httpGet.setConfig(requestConfig);
This might be a trivial question but I'm trying to send web request to USPS to get a http post response (or email response depending on my request) containing the tracking information based on the tracking number that I send in. The documentation says the xml needs to appended as part of the url like below
http://secure.shippingapis.com/ShippingAPITest.dll?API=TrackV2&XML=<PTSEmailRequest USERID="xxxxx"><TrackId>xxxxx</TrackId><RequestType>EN</RequestType></PTSEmailRequest>
I saw there were 2 ways to make an xml request, one using HttpPost and the other URLConnection. I'm a bit thrown by how I go about this and I'm failing to appreciate what's the difference between appending xml in the url and a normal http request. Can someone please clear things up for me?
USPS documentation for tracking =>
https://www.usps.com/business/web-tools-apis/track-and-confirm.pdf
I read these related Stackoverflow posts
Java: How to send a XML request?
posting XML request in java
HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost("http://secure.shippingapis.com/ShippingAPITest.dll");
List<String> params = new ArrayList<String>(2);
params.add(new BasicNameValuePair("API", "TrackV2"));
params.add(new BasicNameValuePair("XML", FuncTOGenerateXML()));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
//.....
// .....
instream.close();
}
An HTTP request can use one of several methods, like POST, GET, DELETE, PUT... Here we talk about POST and GET
Technical differences
With GET, the data is retrieved from the parameters in the URL.
With POST, the data is retrieved from the data transmitted inside the HTTP message.
Intended use differences
GET is intended to be used when the request does not cause a change (v.g., searching in Google). Since you can repeat the request without side effects, the data is in the URL and can be stored in the browser history, favorites, etc.
POST is intended to use when you are performing a change (v.g. sending an e-mail, doing a on-line purchase). The data related is not stored with the URL (it is then that, if you go back to a page that was obtained using POST, the browser many times will show you a pop-up asking for permission to send the data again.
In real usage, the distinction is not so clear cut, in particular POST is sometimes used when the data is too large (URLs have limited length). Also, sometimes GET is used with the meaning of POST so the data can be presented as an HTML link.
Finally, URLConnection is the basic API for opening a connection (which you can use as a POST or GET request, based in how you pass the data, or something else) and HttpPost is just a higher level API for creating a POST request. If you go the basic way, use HttpURLConnection better.
I'm implementing an android app and I'm having trouble understanding how I can implement a login feature (very simple, no encryption needed) and how it works after the user logs in
So, the first thing to do is make a Request, I send the login, and password,with an http POST method probably?
and the server replies with a token of some sort, correct?
Then I save that token, and what happens next? I have a bunch of pages I need to make GET requests on, but I also need to send the token someway, right?
How exactly can I make that?
thank you
You pretty much have it summed up I guess. Let the app send the credentials with a POST, the server checks if they are okay, then sends back a token (some random String maybe). When you make the GET requests after login, send the token with a custom HTTP header and let the server check it. The server has a list of valid tokens and checks if the received token is valid. If not, it responds with an error message, else it does what it's supposed to do.
That's all very basic and not at all secure of course.
Edit: The GET request could be done like this:
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("someUrl.com/rest");
get.setHeader("Authorization", "someTokenYouCreated");
HttpResponse response = client.execute(get);
You'll find lot's of examples about calling a REST method. You'll have to look up how to handle that header on the server side, but that can't be too difficult either.
I'm trying to write a Java client (with Apache HttpClient) for the Gengo API which makes use of HTTP GET, POST, PUT and DELETE. However for every RESTful API "method" that they expose, you must pass your API key and signature as "parameters".
Would this mean query string parameters, POST variables, key-value pair headers, or something else?
I guess I'm just confused by what is meant by the word "parameters" in the context of all these different HTTP request methods. In other words, how would I pass the API key as a "parameter" to their API when I could be using GET, POST, PUT or DELETE? My understanding was that only HTTP GET can handle query string params, and that HTTP POST can only handle POST variables. And I have never used PUT or DELETE before so I'm not sure what they require.
So I ask: what mechanism can I use to send the API key/signature via all 4 types of request methods, or do they all support the processing of query string parameters? Thanks in advance.
You can try this. It works for my HttpClient application with POST request.
DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(name, value);
......
For Example, I set the connection timeout:
httpClient.getParams().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, httpTimeout);
Then later, to send(execute) the request:
HttpResponse response = httpClient.execute([My HttpPost instance was here, but I think you can use HttpGet, HttpPut, and HttpDelete here as well]);
All verbs can use request parameters (also known as query parameters) and they will be available to the server in the same way regardless of if you also send a body.
In your example (Gengo) there is a good example on there page about authentication.