Embracing the Messiness in Search of Epic Solutions

Java: Invoking Secured Web Service with JSESSIONID

Posted

in

PROBLEM

I wrote a JSP custom tag that invokes a secured web service within the same application to perform some evaluation. This custom tag is only used in the secured views where the user has successfully authenticated against Spring Security, and they have access to these views. The secured web service is also guarded by Spring Security.

My custom tag implementation looks something like this:-

public int doStartTag() throws JspException {

	...

	HttpClient httpclient = HttpClientBuilder.create().build();

	HttpGet httpGet = new HttpGet(url);

	log.debug("Before executing HTTP Get...");

	HttpResponse response = httpclient.execute(httpGet);

	int statusCode = response.getStatusLine().getStatusCode();

	log.debug("Status Code: " + statusCode);

	return statusCode == HttpStatus.SC_OK ? EVAL_BODY_INCLUDE : SKIP_BODY;
}

The goal here is… if the response code from the secured web service is a 200 OK, then the custom tag will evaluate its body and include the content. Otherwise, it will hide it.

My first attempt is to test the custom tag with an invalid value so that the secured web service will throw a 400 Bad Request. The hope is the custom tag’s body will not get rendered in the view.

After getting authenticated successfully by Spring Security, the view containing this custom tag gets rendered. However, the response code always return a 200 OK even though I should get a 400 Bad Request from the secured web service.

After poking around, I decided to debug the console log… and this is what I see:-

[DEBUG] [CheckEditAccess] [hasAccess:72] - Before executing HTTP Get...
127.0.0.1 -  -  [29/Dec/2013:10:18:14 -0600] "GET /epic-app/api/request/invalid-key
HTTP/1.1" 302 0
127.0.0.1 -  -  [29/Dec/2013:10:18:14 -0600] "GET /epic-app/;jsessionid=1vlnl6eloabfh12r9x465kvuq
HTTP/1.1" 200 6311
[DEBUG] [CheckEditAccess] [hasAccess:75] - Status Code: 200

As you can see, there are two calls made even though my custom tag only makes one call. The first call is made by the custom tag but the response code is a 302 Found. Then, it gets directed to the next URL that returns a 200 OK.

Why is this happening?

SOLUTION

The problem here is because when the custom tag invokes the secured web service call, it is not done within the same session where the user is already authenticated by Spring Security. Thus, Spring Security prevents the actual call to go through. Instead, Spring Security redirects the request to the login page first (which is located at /epic-app in this case). As a result, the custom tag will receive a 200 OK from the login page instead of the response code from the secured web service.

To fix this, we need to send the session ID with the HTTP Get before executing it:-

public int doStartTag() throws JspException {

	...

	CookieStore cookieStore = new BasicCookieStore();
    BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", pageContext.getSession().getId());
    cookieStore.addCookie(cookie);

	// very important to set the domain, otherwise this will not work!
    cookie.setDomain(request.getServerName());

    cookieStore.addCookie(cookie);

    HttpClient httpclient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();

	HttpGet httpGet = new HttpGet(url);

	log.debug("Before executing HTTP Get...");

	HttpResponse response = httpclient.execute(httpGet);

	int statusCode = response.getStatusLine().getStatusCode();

	log.debug("Status Code: " + statusCode);

	return statusCode == HttpStatus.SC_OK ? EVAL_BODY_INCLUDE : SKIP_BODY;
}

When I try it again, now I’m getting the intended 400 Bad Request from the secured web service due to input validation error.

[DEBUG] [CheckEditAccess] [hasAccess:72] - Before executing HTTP Get...
127.0.0.1 -  -  [29/Dec/2013:10:45:19 -0600] "GET /epic-app/api/request/invalid-key
HTTP/1.1" 400 0
[DEBUG] [CheckEditAccess] [hasAccess:73] - Status Code: 400

Comments

Leave a Reply