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 is “vpUser” and “vp123” -->
<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)
very nice tutorial.
thanx for sharing.
Very helpful artical…works great…Thanx for the artical.
Do I need to call j_spring_security_check for every webservice request for single user? please give me brief description. Thanx for the help… :)
very nice post ..thanks for this
Thanx For Writing This Article
It really helped me alot
Thank You