I've been trying to get XSRF working on a webapp to no avail. I am looking at a typical login implementation.
I am following Google's code. I changed my web.xml to include:
<servlet>
<servlet-name>xsrf</servlet-name>
<servlet-class>com.google.gwt.user.server.rpc.XsrfTokenServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xsrf</servlet-name>
<url-pattern>/gwt/xsrf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>gwt.xsrf.session_cookie_name</param-name>
<param-value>JSESSIONID</param-value>
</context-param>
and extended XsrfProtectedServiceServlet
on the server Impl file of my login service. It is my understanding that no other change is needed on the server. Do I need to add anything else, such as a method that returns an RpcToken
here (as well as in the interface I am implementing)?
On the client side, I use annotations.
@XsrfProtect
@RemoteServiceRelativePath("login")
public interface LoginService extends RemoteService {
String check(String user, String pass) throws IllegalArgumentExceptionhere;
}
This is probably where I am missing something. Google says on the tip: Tip: To specify which RpcToken implementation GWT should generate serializers for use @RpcTokenImplementation annotation.
Not sure what that means or if I need another method here to return an RpcToken.
My async interface is like this:
public interface LoginServiceAsync {
//Returns the Session ID
void check(String user, String pass, AsyncCallback<String> callback);
}
Then for my actual RPC call, I wrap my code around the xsrf token request. I use code identical to google's:
XsrfTokenServiceAsync xsrf = (XsrfTokenServiceAsync)GWT.create(XsrfTokenService.class);
((ServiceDefTarget)xsrf).setServiceEntryPoint(GWT.getModuleBaseURL() + "xsrf");
xsrf.getNewXsrfToken(new AsyncCallback<XsrfToken>() {
public void onSuccess(XsrfToken token) {
LoginServiceAsync rpc = (LoginServiceAsync)GWT.create(LoginService.class);
((HasRpcToken) rpc).setRpcToken(token);
// make XSRF protected RPC call
rpc.check(user, pass, new AsyncCallback<String>() {
// ...
});
}
public void onFailure(Throwable caught) {
try {
throw caught;
} catch (RpcTokenException e) {
// Can be thrown for several reasons:
// - duplicate session cookie, which may be a sign of a cookie
// overwrite attack
// - XSRF token cannot be generated because session cookie isn't
// present
} catch (Throwable e) {
// unexpected
}
});
The complain is I that the call to getNewXsrfToken fails as it doesn't know that xsrf location from the call here: GWT.getModuleBaseURL() + "xsrf"
. I get the feeling there is a token handshake missing which causes this error, but I am not sure.
Lastly, I also tried implementing Nick Siderakis' code but his example uses a JSP page which asks the server: XsrfTokenUtil.getToken(request.getSession().getId())
. I do not want to use JSP pages and I have not figured out how to perform this without a jsp page. His code also diverges from the Google code example (i.e. he doesn't call getNewXsrfToken) which I do not know if it's the "prefered" google way of dealing with XSRF.
Any ideas as to what I am missing? Thanks.
EDIT
Solution below...
Ok I figured out the problem. I had to change GWT.getModuleBaseURL() + "xsrf" to "gwt/xsrf" in my code above as it wasn't pointing to the the right place, as I suspected. In addition, the server could not find a JSESSIONID cookie, so I followed this and added Cookies.setCookie("JSESSIONID", "JSESSIONID", null, null, "/", false); inside my onModuleLoad(). That did it. Cheers.