Sunday, April 8, 2007

HttpClient for Form Based Authentication

There are 3 HTTP requests: 1st one to visit the protected pages defined by security-constraint in web.xml and obtain JSESSIONID, this is becasue we cannot access to j_security_check directly; 2nd one to post j_security_check for authentication; 3rd one resubmit the original request. The subsequent requests in the same session will be authenticated automatically. The Key point is that the 3rd one must resubmit the exact same original request. This is because the state is kept in server and the following request (a redirect request) will be checked against it. The redirect is always a GET based on the LOCATION header value in the response (response code 302). So if you send POST request to a different URL in 3rd request, you maybe mysterously taken to a doGet() method instead although you issue a POST request, as what I observed in JBOSS environment. In Tomcat, the behaviour is different, it is treated as non-authenticated and taken to login page again. Also, keep in mind that redirect might result in previous POST data lost.

HttpClient client = new HttpClient();
GetMethod method = new GetMethod("http://localhost:8000/webTest/protected/securityTest.html");
int status = client.executeMethod(method); // 200, response with login page

PostMethod authPost = new PostMethod("http://localhost:8000/webTest/j_security_check");
// authPost.setFollowRedirects(false);
NameValuePair[] data = {
new NameValuePair("j_username", "tomcat"),
new NameValuePair("j_password", "tomcat")
status = client.executeMethod(authPost); // 302, redirect to original requested page

method = new GetMethod("http://localhost:8000/webTest/protected/securityTest.html");
String response = method.getResponseBodyAsString();


SAM said...

My application consist of resource which is protected by Form Authentication, Ive tried above mentioned steps to get the protected resource,
i was unable to login through Login Form, the response which i am getting after third step is the source Form login itself instead of actual resource.
Below is the snippet of my code , can any body tell me where i am going wrong.

GetMethod method = new GetMethod("http://host:port/test.html");
int statuscode = client.executeMethod(method);

PostMethod authPost = new PostMethod("http://host:port/login.html");
// authPost.setFollowRedirects(false);
NameValuePair[] data = {
new NameValuePair("login", "user"), new NameValuePair("password", "welcome") }; authPost.setRequestBody(data); status = client.executeMethod(authPost); authPost.releaseConnection();

method = new GetMethod("http://host:port/test.html");
String response = method.getResponseBodyAsString(); method.releaseConnection(); System.out.println(response);

Chris said...

After your code executes the line:
status = client.executeMethod(authPost);

What is the value of status? Is the value 200 or 302?

Ginger said...

The 2nd post should send to j_security_check logical name rather than login.html