Re: [rest-assured] Form Authentication

1,219 views
Skip to first unread message

Johan Haleby

unread,
Jan 11, 2013, 1:52:49 AM1/11/13
to rest-a...@googlegroups.com
Hi, 

What does your login page look like? (especially your html form that have the login and password fields). 

Regards,
/Johan

On Thu, Jan 10, 2013 at 4:06 PM, Rich Aquino <aquin...@gmail.com> wrote:
Hi Everyone, 

I've been having trouble with form authentication in rest-assured. In a browser, I am able to login and use the site.  In rest-assured, my get will not authorize me to let me past the login screen.

This is my bare-bones authentication test...

RestAssured.authentication = form("theuser", "thepassword", new FormAuthConfig("/j_security_check", "j_username", "j_password"));
expect().body(not(containsString("j_security_check"))).body(containsString("the event")).get("/s/events/today/");

When the second line is executed, the get returns my login form, failing my "not" constraint.

I thought I got a bit farther when I did something like this (and variations of it)…

String sessionId = given().auth().form("theuser", "thepassword", new FormAuthConfig("/j_security_check", "j_username", "j_password")).get("/s/events/today/").sessionId();
given().sessionId(sessionId).expect().body(not(containsString("j_security_check"))).body(containsString("the event")).get("/s/events/today/"); 

And that works when I hard-code the sessionID in the second line to one I pull from a cookie in chrome, but for the life of me I can't get this working when I programmatically login.

Thinking it might be an issue with JAX-RS or something, I've disabled everything in web.xml that I thought could cause this, and it now boils down to this…

<security-constraint>
  <web-resource-collection> 
    <web-resource-name>Restricted</web-resource-name> 
    <url-pattern>/s/*</url-pattern> 
    <http-method>DELETE</http-method> 
    <http-method>PUT</http-method> 
    <http-method>HEAD</http-method> 
    <http-method>OPTIONS</http-method> 
    <http-method>TRACE</http-method> 
    <http-method>GET</http-method> 
    <http-method>POST</http-method> 
  </web-resource-collection> 
  <auth-constraint> 
    <role-name>admin</role-name> 
    <role-name>sales</role-name> 
    <role-name>manager</role-name> 
    <role-name>chair</role-name> 
    <role-name>employee</role-name> 
    <role-name>attendee</role-name> 
  </auth-constraint> 
  <user-data-constraint> 
    <transport-guarantee>NONE</transport-guarantee> 
  </user-data-constraint> 
</security-constraint> 
<login-config> 
  <auth-method>FORM</auth-method> 
  <form-login-config> 
    <form-login-page>/login/login.jsp</form-login-page> 
    <form-error-page>/login/login_err.jsp</form-error-page> 
  </form-login-config> 
</login-config> 
<security-role> 
  <role-name>admin</role-name> 
</security-role> 
<security-role> 
  <role-name>sales</role-name> 
</security-role> 
<security-role> 
  <role-name>manager</role-name> 
</security-role> 
<security-role> 
  <role-name>chair</role-name> 
</security-role> 
<security-role> 
  <role-name>employee</role-name> 
</security-role> 
<security-role> 
  <role-name>attendee</role-name> 
</security-role> 

I can still login to a browser, but now my page 404s because I've disabled my servlet.  However, in my tests, the get still returns the login form.

Thanks in advance for your help.

Rich
P.S. I installed 1.7.2 yesterday to no avail.

P.P.S. I'm not sure it matters, but here is my context.xml…

<Resource name="jdbc/testdb" auth="Container" type="javax.sql.DataSource" 
username="root" password="" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/testdb"
maxActive="100" maxIdle="30" maxWait="10000" 
testConnectionOnCheckout="true" testOnBorrow="true" validationQuery="select 1" 
/> 

<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="com.mysql.jdbc.Driver" 
connectionURL="jdbc:mysql://localhost:3306/testdb" 
connectionName="root" connectionPassword="" 
userTable="tc_realm_users" userNameCol="username" userCredCol="passwordhash" 
userRoleTable="tc_realm_groups" roleNameCol="groupname" digest="sha-256" />


Rich Aquino

unread,
Jan 11, 2013, 1:48:15 PM1/11/13
to rest-a...@googlegroups.com
Hi Johan,

Here it is...
<form action="/j_security_check"> 

  <label for="j_username">User Name:</label> 
  <div class="clear"> 
  <input type="text" name="j_username" id="j_username" autocapitalize="off" autocomplete="off" autocorrect="off" /> 
  <div class="clear"> 
  <label for="j_password">Password:</label> 
  <div class="clear"> 
  <input type="password" name="j_password" id="j_password" /> 
  <div class="clear"> 
  <input class="btn" type="submit" name="submit" id="submit" value="Go" data-theme="b" /> 
</form>

Rich

Johan Haleby

unread,
Jan 12, 2013, 5:25:28 AM1/12/13
to rest-a...@googlegroups.com
Hm it looks right to me, do you get a message on the login page hinting about a potential error when RA has tried to perform the form auth? You could also try removing the FormAuthConfig entirely (i.e. keep only form("theuser", "thepassword"))  and RA will try to parse the login page and send a request automatically (this approach, if it works for you, is not a fast though and require an extract round-trip to the server for each request).

Regards,
/Johan

Rich Aquino

unread,
Jan 12, 2013, 7:19:34 PM1/12/13
to rest-a...@googlegroups.com
Hi Johan,

I removed FormAuthConfig and that didn't help.  I actually tried only form("theuser", "thepassword") initially, and only found out about FormAuthConfig after that failed.

I tried to get more info by using the error object on my login_err.jsp file (not a best practice, but for testing I'm cool with it), but couldn't figure it out.  However, I know that RA is receiving my login.jsp (non error) page, not the error page, because my error page does have a generic message on it that I'm not seing returned to RA.

Rich

Johan Haleby

unread,
Jan 13, 2013, 9:47:33 AM1/13/13
to rest-a...@googlegroups.com
ok it seems like either the requests that RA is sending is not correct (do the wrong endpoint or something?) or an error occurred on the server due to an incomplete or invalid request. I don't really know what else I can do :/ One thing you could try is to compare what's happening if you do a manual login and a RA form auth in Wireshark. If you do that and find out what the differences are then perhaps we can find a way to get it to work.

Regards,
/Johan

Rich Aquino

unread,
Jan 13, 2013, 10:58:19 PM1/13/13
to rest-a...@googlegroups.com
Hi Johan,

Great suggestion.  I did that and found a couple of differences.

1. RA is posting to /j_security_check, while Chrome is doing a get.  

I changed the method of the form to POST, and now Chrome does a get, though it still works while RA does not.

2. RA is getting a 408 error:  "The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser".

I realized that Chrome had a few differences.  
a. It added this header
Cache-Control: max-age=0
b. And these headers
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.101 Safari/537.11
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
c. And to the j_username and j_password params, it included this one: 
submit=Go
d. It included the JSESSIONID cookie that it received from the 

For a-c, I couldn't figure out how to include those headers/parameters in the auth request.
For a, I tried adding the following to my login page but it didn't help:

<meta http-equiv="Cache-Control" content="no-store,no-cache,must-revalidate"><meta http-equiv="Pragma" content="no-cache"><meta http-equiv="Expires" content="-1">

For c, I tried changing the form's submit to have a value of "Login", but that did nothing.

For d, I couldn't figure out how to include the JSESSIONID cookie in the post to /j_security_check

I also tried setting my server's RequestTimeout to 60000, to no avail.

Rich

Johan Haleby

unread,
Jan 14, 2013, 2:18:27 AM1/14/13
to rest-a...@googlegroups.com
1) Yes RA only support POST for form authentication. I must admit that I've never thought about using something else, I think using a GET for form submission is "violating" the HTTP spec (correct me if I'm wrong).
2) You can also add custom headers with RA but it seems like your form auth may be a bit more complicated than what RA can handle (the form auth provided by RA has worked in all projects I've tried it so far). What I would suggest you to do is to write a custom filter that customizes that form auth for your application. You can have a look at the FormAuthFilter class in RA to get some ideas.

Regards,
/Johan

Rich Aquino

unread,
Jan 17, 2013, 3:49:04 PM1/17/13
to rest-a...@googlegroups.com
Hi Johan,

1. Agree.  I changed it to post.
2. I'm not intentionally doing anything special.  I haven't gotten around to creating my own filter yet, but I can try that next.  

I'm not sure if it helps you understand the problem, but I was able to get this to work:

String sessionId = get("/s/events/Today/").sessionId(); 
RestAssured.sessionId = sessionId; 


RestAssured.authentication = form("theuser", "thepassword", new FormAuthConfig("/j_security_check", "j_username", "j_password")); 

given().expect().body(not(containsString("j_security_check"))).body(containsString("RMH")).get("/s/events/Today/");

However, if I follow that up with this line, it again prompts me for the login.

given().expect().body(not(containsString("j_security_check"))).body(containsString("RMH")).get("/s/events/Yesterday/");

I have to do this to get yesterday to work:

String sessionId = get("/s/events/Yesterday/").sessionId(); 
RestAssured.sessionId = sessionId; 


RestAssured.authentication = form("theuser", "thepassword", new FormAuthConfig("/j_security_check", "j_username", "j_password")); 

given().expect().body(not(containsString("j_security_check"))).body(containsString("RMH")).get("/s/events/Yesterday/");

If the highlighted parts do not match, the last line fails because I receive the login screen.

I think it has something to do with the sessionID changing with each get.  i.e. this test fails:
String sessionId = get("/s/events/Today/").sessionId();
String sessionId2 = get("/s/events/Future/").sessionId(); 
assertEquals(sessionId, sessionId2);

Rich

Johan Haleby

unread,
Jan 18, 2013, 2:16:13 AM1/18/13
to rest-a...@googlegroups.com
It could be that you get a new session id after a successful login and that your app/server require that a session id is always sent along with the request. Try to use the session id from the second request for subsequent requests. 

If this doesn't work I would probably (again) check how RA behaves compared to how the browser behaves using Wireshark. I would then create my own filter (that perhaps uses the original FormAuthFilter if applicable) and just adds the missing headers etc that RA is not providing in your scenario.

Regards,
/Johan 
Reply all
Reply to author
Forward
0 new messages