Unlike my previous post here, sometimes we do need to access JAX-RS resource which is secured by the “traditional” approach of using FORM-based authentication (i.e. jsecuritycheck
).
I thought it would be good to share how I do it from within Java client.
Please note that this post is based on (Bien 2013).
Firstly, the thing about ‘jsecurity’-check in Tomcat…
After much reading, I found some help from the following entry at a href=”www.stackoverflow.com” target=”_blank”>stackoverflow.com:
that to get some resource on the tomcat server with j_security_check auth it is necessary to implement three steps:
- Send GET request to the needed private resource, in response you get a cookie (Header “Set cookie”)
- Send request with cookie (from step 1) to the j_security_check. On response you should get code 302 – “Moved Temporarily”
- Now you can repeat request to the private resource with same cookie, on responce you get needed resource data.
Let’s look at some code
I have put comments in the code to explain what is going on in relation to the three points above. But basically what is happening is that we intercept (Kops 2013) the request in order to first make another request authenticating against jsecuritycheck
.
– Register the ‘Authenticator’ when making the call
final Client client = ClientBuilder.newClient().register(new Authenticator("http://myapplication.com/myweb", "username", "password")); final WebTarget target = client.target("http://myapplication.com/myweb/resources/person"); final JsonObject response = target.request(MediaType.APPLICATION_JSON_TYPE).get(JsonObject.class); // do something with the response
– Our ‘Authenticator’, which is a ‘javax.ws.rs.client.ClientRequestFilter’
package id.co.lucyana.hr.util; // imports omitted @Provider public final class Authenticator implements ClientRequestFilter { private static final String COOKIE = "Cookie"; // security params private static final String J_SECURITY_CHECK = "j_security_check"; private static final String J_USERNAME = "j_username"; private static final String J_PASSWORD = "j_password"; private final String username; private final String password; private final String baseUri; // requires by @Provider public Authenticator() { this.username = null; this.password = null; this.baseUri = null; } public Authenticator(final String baseUri, final String username, final String password) { this.username = username; this.password = password; this.baseUri = baseUri; } @Override public void filter(final ClientRequestContext requestContext) throws IOException { final List<Object> cookies = new ArrayList<>(); /* * This is hitting the URL as requested by the ClientBuilder. * (Refer to the line: "1. Send GET request to the needed private resource, * in response you get a cookie (Header “Set cookie”)" */ final Client initialClient = ClientBuilder.newClient(); final Response responseInitial = initialClient .target(requestContext.getUri()) .request(requestContext.getAcceptableMediaTypes().get(0)) .method(requestContext.getMethod()); initialClient.close(); /* * This section is getting the cookie above and use it to make the call against jsecuritycheck * (Refer to the line: 2. Send request with cookie (from step 1) to the j_security_check. * On response you should get code 302 – “Moved Temporarily”) */ responseInitial.getCookies().values().stream().forEach((cookie) -> { cookies.add(cookie.toCookie()); }); final Client loginClient = ClientBuilder.newClient(); final Form form = new Form(); form.param(J_USERNAME, this.username); form.param(J_PASSWORD, this.password); final Response loginResponse = loginClient.target(this.baseUri).path(J_SECURITY_CHECK) .request(MediaType.APPLICATION_FORM_URLENCODED) .header(COOKIE, cookies) .post(Entity.form(form)); loginClient.close(); loginResponse.getCookies().values().stream().forEach((cookie) -> { cookies.add(cookie.toCookie()); }); /* * This is right before making the actual call. So we add the cookie (which the server will be * able to tell that this call has been authenticated). * (Refer to the line: 3. Now you can repeat request to the private resource with same cookie, * on responce you get needed resource data.) */ requestContext.getHeaders().put(COOKIE, cookies); } }
For more information on Java EE, check out this article.
References
Alexander, 2011, ‘Request to j_security_check return 408 error only with right paramters’, stackoverflow.com, accessed on 28 November 2016
Bien, A, 2013, ‘Client-side HTTP Basic Authentication With JAX-RS 2.0’, Adam Bien’s weblog, accessed on 28 November 2016
Kops, M, 2013, ‘JAX-RS 2.0 REST Client Features by Example’, hasCode.com, accessed on 28 November 2016