I am having trouble getting Apache HttpClient 4 to follow SiteMinder AD FS 2.0 authentication through a RADIUS server (securID). I've gotten it to work without the AD FS, but AD FS sends back an autopost with a SAML assertion. I try to pull the parameters myself and post again, but it sends back a message saying something is wrong. The error message is very generic.
The only thing I can see obviously different between how HttpClient works and a browser is the referer is not set during redirects by HttpClient. When watching a browser follow redirects (using Fiddler), the referer header parameter is always set as the previous location. With HttpClient, the referer is not.
Has anyone used Apache HttpClient 4 to authenticate to a SAML / AD FS 2.0 server? Sample code? thanks
Related
I am getting FileNotFoundException when making GET call to REST API. Here HTTP status code I get is 403.
For POST call I get IOException : No authentication challenges found, whereas I pass Authorization header. Here I get HTTP status code 401.
Look at my already asked question to see the code and logcat screen shot for POST call.
Below I am attaching logcat screen shot for GET call :
Note :
1) I have tried using Authenticator.
2) Tried different base64 flags such as NO_WRAP, URL_SAFE, DEFAULT.
3) My simple call to www.google.com works.
4) When I log urlConnection.getErrorStream(), last line in image is printed. I don't understand what is that and what does it mean. I have specified Content-type to application/json in header.
UPDATE : I tried using Burp and found that headers "Accept", "Content-type" were different. I used the same as in iOS app. But still it does not work.
Things to note :
1) It always throws an Exception on the line in = urlConnection.getInputStream();.
2) I logged few things and according to it, content-length is 114, which is not null. content-type is application/json; charser=utf-8.
There's a difference between your HTTP traffic for iOS and for Android. This is guaranteed, otherwise you'd get identical behaviour from the server. The difference is probably in HTTP header(s) &/or parameter(s).
This is very difficult to debug remotely via SO Q&A - E.g. we don't know what headers & parameters your iOS client is successfully using nor how your server is configured & programmed.
How to diagnose the problem & correct yourself:
Trace your working HTTP traffic: iOS client <-> server
Trace your non-working HTTP traffic: Android client <-> server
Compare (2) and (3). For the most thorough comparison, save each HTTP request and response message as a separate file for (2) and (3), then diff the corresponding files.
Recommended HTTP tracing tools:
Fiddler2 (windows only) See also Documentation
Burp (JVM-based: windows, linux, OSX, etc) See also Getting Started
WebScarab (JVM-based: windows, linux, OSX, etc) See also Getting Started
UPDATE
Seems you have the same problem for both GET and POST: the server is configured for BASIC authentication, but the client is not following the authentication protocol correctly. I think it just shows as a slightly different sympton in the two cases: for GET it says 'resource not found' (because you're not authenticated) and for POST the resource is given by you, but the server says you're not authorized to change the resource on the server. I suggest you've done enough (good!) debugging of request contents and now you should stop and focus on getting authentication working.
Send you GET/POST request to the server without Authorization header
Allow the server to prompt you for authentication with a 401 response with an WWW-Authenticate header containing a challenge string (e.g. WWW-Authenticate: Basic realm="Protected" see RFC 2617 HTTP Basic Authentication and Digest Authentication)
Now send an additional GET request to server that (either without/with the original request contents), but includes the Authentication header, with Base 64 encoded username:password (Authorization: Basic ZnJhbms6ZmllZGxlcg==)
I solved my problem and it is something I never tried to focus on while solving the problem.
I need not pass Authorization header. The thing is that there are 2 credentials come into the picture. one is server's authorization and second is credentials for login API. In my app, user creates an account and login to it. To authenticate the user I pass credentials to server and server authenticate it.
So when user enters correct credentials then response received is correct. And, in case of wrong credentials, my server passes a error message You are not authorized person, which I want to display to user(as in my iOS app). So the problem is here that HTTP status code (in case of wrong credentals) is 401 and that is why I don't receive the message sent by the server (and receive No authentication challenges found message).
The reason why I don't receive server message is that HttpUrlConnection don't give server response when HTTP status code is >= 400.
The only option to get error details in case status code 400 and above is to use getErrorStream() method and using that I was receiving No authentication challenges found message.
Finally, either I had to handle each status code, that is equal and above 400, at client side or I can use HttpClient, instead of HttpUrlConnection. And now I am moving to HttpClient.
I had a similar problem, and solved by passing the authenticated session cookie. Not sure if that is possible in your situation.
AuthUser="foobar"
AuthPass="password"
URL targetUrl = new URL("http://www.google.com/");
HttpURLConnection connection = (HttpURLConnection) targetUrl.openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
String authStr = Base64Variants.MIME_NO_LINEFEEDS.encode((AuthUser+":"+AuthPass).getBytes());
connection.addRequestProperty("Authorization", "Basic "+authStr);
InputStream inputStream= connection.getInputStream();
I just run something like this and it worked perfectly for me. Just make sure you use Base64Variants.MIME_NO_LINEFEEDS and you should be able to create a proper authentication header. If that doesn't work, then you might have some problem on the server side.
I'm simulating an HTTPS process with Google App Engine's URL fetch API. The process has 2 steps: first, a GET request will return an URL with URL-encoded session information and a cookie; and second, a POST with some payload to the returned URL.
I have used Firebug to capture the headers of the 2 requests, e.g User-agent, Keep-alive, Connection, Cookie. I used these same headers in my code (the cookie value is updated according to the response). Testing on my computer is successful but the code always fails at the POST step on Google's server. On my development box, the remote .NET app website replies to the POST request with a 200-OK with the information that I want, but on Google side, the remote .NET app website also give a 200-OK response but with a "Session timeout" message (which I don't want). So what have I missed?
Are you connectiong to the GAE applictation through appspot.com domain or a custom domain? SSL is supported only on appspot.com, so maybe this the reason?
I want to create a small java application to copy some wiki content from one server to another. The API is based on the XML-RPC.
Basically I have three methods, login, getPage and putPage. I use Apache HttpClient 3.x and managed to use login to login successfully and getPage to get a page from the old wiki correctly.
Authentication is handled with cookies: I log into the new wiki and some cookies are set on the corresponding httpclient. The doku tells me that one of those cookies is used for authentification.
Then I execute putPage with another POST method on the same httpclient and the server responds with a authentication failure message.
The code sequence goes like this (very reduced):
HttpClient client = new HttpClient();
PostMethod postLogin = createNewPostMethod("login", "user", "pw");
client.executeMethod(postLogin);
// Now I'm logged in and the client definitly has stored the cookies
PostMethod postPutPage = createNewPostMethod("putPage", getPage());
client.executeMethod(postPutPage); // the server won't let me put the page
Should it work like that or do I have to add the cookies manually to the second post method and, if yes, how?
Edit / Solution
With the help of the answers to this question I was able to identify and solve the problem, which was outside of the usage of httpclient. At the end it was a configuration issue on the target wiki side. The answers here helped me to ask the right questions in another forum.
Cookies are handled by HTTPClient by default. You shouldn't have to do anything to have cookies work properly.
Source:
http://www.innovation.ch/java/HTTPClient/getting_started.html#cookies
Edit for Apache HTTP Client:
Apache HTTP Client behaves the same :-)
Here is the source:
http://hc.apache.org/httpclient-3.x/cookies.html
You can set manually cookies with HTTP Client but it will handle correctly cookies created during your connection.
HttpClient supports automatic management of cookies, including allowing the server to set cookies and automatically return them to the server when required. It is also possible to manually set cookies to be sent to the server.
Resources :
Apache HttpClient - cookies
I have historically used this when I wanted to accept cookies with HttpClient
postPutPage.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
I'm trying to consume a restful webservice in java using the Apache Wink framework through my school web proxy requiring authentification
ClientConfig clientConfig = new ClientConfig();
clientConfig.proxyHost("proxy.school.com");
clientConfig.proxyPort(3128);
//nothing to set username and password :(
RestClient client = new RestClient(clientConfig);
Resource resource = client.resource("http://vimeo.com/api/v2/artist/videos.xml");
String response = resource.accept("text/plain").get(String.class);
I've also tried to use the BasicAuthSecurityHandler but it seems to be used to authenticate directly to a web server, not the web proxy
BasicAuthSecurityHandler basicAuthHandler = new BasicAuthSecurityHandler();
basicAuthHandler.setUserName("username");
basicAuthHandler.setPassword("password");
config.handlers(basicAuthHandler);
It still fail with a HTTP 407 error code : Proxy Authentication Required.
I've googled the best I could, nothing came up better to consume a webservice from a Java client through a web proxy, if someone has another idea, feel free to respond
Ok that was pretty hard but I found it ! I logged the HTTP requests that were being made from my browser with Fiddler and found out that the Proxy-Connection and Proxy-Authorization were what I was looking for after reading extensive documentation like RFC 2616 about HTTP/1.1
So I copy-pasted the values that were being sent into my java code :
resource.header("Proxy-Connection", "Keep-Alive");
resource.header("Proxy-Authorization", "Basic encodedString");
where encodedString is what is being sent by my browser : username:password base64 encoded
And it now works perfectly :)
This issue was raised as [1] and has since been resolved with the addition of a ProxyAuthSecurityHandler available to Apache Wink client developers.
[1]: https://issues.apache.org/jira/browse/WINK-292 Apache Wink JIRA issue WINK-292
I do the below steps to get the security token from browser for Single Sign on authentication.
I am able to find the Token from http header. My question is:
a) How do I verify this token with active directory?
b) How do I find username from this token?
While googling it seems Java API has Kerberos5 login module to do what I was expecting. But almost all pages lacks simple examples.
The Web client accesses a AS Java resource with a GET request.
The AS Java sends back a 401 response code (unauthorized) with a request to initiate SPNego authentication by setting the HTTP header “WWW-Authenticate” to “Negotiate”.
The Web client recognizes that the AS Java host is a member of the Kerberos Realm and procures a Kerberos Client/Server Session Ticket for the AS Java from the KDC.
The Web client then sends the Kerberos Client/Server Session Ticket to the AS Java wrapped as a SPNego token in the HTTP authorization header.
The SPNegoLoginModule reads the token from the HTTP request and feeds the Kerberos implementation of the JDK with it.
The result is either successful client authentication or failure when the client request is rejected or another roundtrip to the KDC is necessary. In the case of failure, the Kerberos JDK implementation of the AS Java generates and sends back to the Web client an output token. The output token is wrapped as a SPNego token and sent in the HTTP authorization header.
Any help would be appreciated.
There is no response for long time. Found answer myself from various site on the internet.
Documented my experience in below link:
http://webmoli.com/2009/08/29/single-sign-on-in-java-platform/
Here's an open source library, http://spnego.sourceforge.net, that has some examples of what you want to do.