Navigating Spring Security from thick Client to REST Webservice

When a Web Service is protected by Spring security, and we try to access that Web Service, we are presented with a login page to enter our credentials. After we provide our credentials, this information is stored as part of the session and sent back and forth between the browser and the server in a cookie.

However this is not the way it works with a non-browser, standalone client (like a mobile app) – for obvious reasons.

This note describes a thick client. User requires to login into the thick client. On successful authentication the user’s credentials are stored with the client. When the client accesses the Web Service, the web server responds to the client with the login page. Then the client presents the credentials, and submits it back to the web server.

Thus accessing a Web Service secured by Spring Security is a two-step process.

This note primarily describes the client. Some server-side config files are shown for information.

Follows are relevant code snippets for this scenario.

Comments are provided in bold.

On the Server side

Follows are some standard code snippets to secure a URL pattern with Spring Security with a username and password. Please refer to Spring Security documentation for detailed instructions and samples.

In web.xml

<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/mvc-dispatcher-servlet.xml, /WEB-INF/spring-security.xml </param-value> </context-param> …….. …….. <!-- Spring Security --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Code language: HTML, XML (xml)

In spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd"> <!--Web Services with the pattern “/rest/vp/” will be secured --> <http auto-config="true"> <intercept-url pattern="/rest/vp/**" access="ROLE_USER" /> </http> <!—The username and password to be provided isvpUserandvp123--> <authentication-manager> <authentication-provider> <user-service> <user name="vpUser" password="vp123" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
Code language: HTML, XML (xml)

In mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <context:component-scan base-package="com.devices.middleware.webservice" /> <mvc:annotation-driven /> </beans>
Code language: HTML, XML (xml)

On the Mobile Client side

// This is the object that we will populate from the JSON object //returned by the Web Service List<AlarmBean> alarmBeanList = new ArrayList<AlarmBean>(); // The username and password authenticated to the client, and required for //the Web Service //String urlParameters= // "j_username="+userBean.getUsername()+"&j_password="+userBean.getPassword(); String urlParameters="j_username="+”vpUser” +"&j_password="+”vp123”; // When Spring Security presents the login page, that page gets submitted to this link. // i.e. - /j_spring_security_check String strSpringAuthURL = "http://hostname/j_spring_security_check"; //This is the REST Web Service to be invoked String strWebSvc = "http://hostname/rest/vp/alarm/11"; try { // Create the URL object with the Web Service url URL url = new URL(strWebSvc); System.out.println("strWebSvc "+strWebSvc); // Invoke the URL HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); // ************* IMP ************* conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); conn.setUseCaches (false); //HTTP Response codes are // 200 is OK // 302 is Redirect // When the secured Web Service is requested, the web server directs // to the login page and sends a 302 Response code if (conn.getResponseCode() == 302) { System.out.println(" Response code is " + conn.getResponseCode()); String newUrl = conn.getHeaderField("Location"); // Get the cookie. It has the value of the original Web Service URL. //In a browser scenario, after successful authentication, it would’ve //automatically re-directed to the WS URL String cookies = conn.getHeaderField("Set-Cookie"); //conn = (HttpURLConnection) new URL(strSpringAuthURL + // ";jsessionid=" + J_SESSION_ID).openConnection(); conn = (HttpURLConnection) new URL(strSpringAuthURL).openConnection(); //Pass on the cookie conn.setRequestProperty("Cookie", cookies); conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); conn.setRequestMethod("POST"); DataOutputStream wr1 = new DataOutputStream(conn.getOutputStream ()); //Pass on the credentials wr1.writeBytes(urlParameters); wr1.flush(); wr1.close(); //System.out.println("Redirect to URL : " + strSpringAuthURL // + ";jsessionid=" + J_SESSION_ID); System.out.println("Redirected to URL : " + strSpringAuthURL ); System.out.println("Response code from Spring Auth URL is " + conn.getResponseCode()); //Get the Web Service URL from the http header String strOrigWSUrl = conn.getHeaderField("Location"); String cookies1 = conn.getHeaderField("Set-Cookie"); //conn = (HttpURLConnection) new URL(strOrigWSUrl + // ";jsessionid=" + J_SESSION_ID).openConnection(); // Connection is made to the original Web Service URL that we want conn = (HttpURLConnection) new URL(strOrigWSUrl).openConnection(); // ************* IMP ************* // The cookies that we received after authentication is passed here again. conn.setRequestProperty("Cookie", cookies1); conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); conn.setUseCaches (false); System.out.println("Redirect to URL strOrigWSUrl : " + strOrigWSUrl); // We get a 200 Response code now System.out.println(" Response code 555 is " + conn.getResponseCode()); } //end-if for the condition where we checked if the Response code was 302 //if the response code was not 302 above at the “if” check for the response code, //and was 200 (assumed, not checked here), //code would’ve continued here-forward // Reading the JSON output returned by the Web Service // And populating the AlarmBean object BufferedReader br = new BufferedReader( new InputStreamReader((conn.getInputStream()))); String line; while ((line = br.readLine()) != null) { JSONArray jsa = new JSONArray(line); for (int i = 0; i < jsa.length(); i++) { JSONObject jo = (JSONObject) jsa.get(i); AlarmBean alarmBean = new AlarmBean(jo .getInt("alarmId"), jo.getString("timestamp"), jo.getString("duration"), jo .getString("meterName"), jo .getString("alarmType"), jo .getString("status"), jo .getInt("dcId"), jo .getInt("count"), jo .getString("deviceId"), jo .getInt("buildingId"), jo .getBoolean("disabled"), jo .getString("location"), jo .getString("dc"), jo .getString("buildingName"), jo .getInt("acknowledgedBy"), jo .getString("ackUserName"), jo .getString("acknowledgedOn"), jo .getString("thresholdValue"), jo .getString("actualValue")); alarmBeanList.add(alarmBean); }
Code language: Java (java)

View Comments

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

5 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

5 years ago