Security in Spring Rest API


Use JAR files which are listed below:

antlr-2.7.7.jar
avro-1.7.5.jar
cglib-2.2.jar
classmate-1.0.0.jar
com.springsource.org.aopalliance-1.0.0.jar
commons-codec-1.6.jar
commons-compress-1.5.jar
commons-dbcp-1.4.jar
commons-io-2.4.jar
commons-lang-2.6.jar
commons-logging.jar
commons-pool-1.6.jar
dom4j-1.6.1.jar
hibernate-commons-annotations-4.0.4.Final.jar
hibernate-core-4.3.1.Final.jar
hibernate-entitymanager-4.3.1.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hibernate-search-analyzers-4.5.0.CR1.jar
hibernate-validator-5.1.1.Final.jar
hibernate-validator-annotation-processor-5.1.1.Final.jar
hibernate-validator-cdi-5.1.1.Final.jar
jackson-core-asl-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jandex-1.1.0.Final.jar
javassist-3.18.1-GA.jar
javax.servlet.jsp.jstl-1.2.2.jar
javax.servlet.jsp.jstl-api-1.2.1.jar
jboss-logging-3.1.3.GA.jar
jboss-logging-annotations-1.2.0.Beta1.jar
jms-1.1.jar
jsr250-api-1.0.jar
jta-1.1.jar
lucene-analyzers-3.6.2.jar
lucene-core-3.6.2.jar
lucene-grouping-3.6.2.jar
lucene-highlighter-3.6.2.jar
lucene-kuromoji-3.6.2.jar
lucene-memory-3.6.2.jar
lucene-misc-3.6.2.jar
lucene-phonetic-3.6.2.jar
lucene-smartcn-3.6.2.jar
lucene-spatial-3.6.2.jar
lucene-spellchecker-3.6.2.jar
lucene-stempel-3.6.2.jar
mysql-connector-java-5.0.8.jar
paranamer-2.3.jar
persistence-api-1.0.2.jar
slf4j-api-1.7.7.jar
solr-analysis-extras-3.6.2.jar
solr-core-3.6.2.jar
solr-solrj-3.6.2.jar
spring-aop-3.2.3.RELEASE.jar
spring-beans-4.0.6.RELEASE.jar
spring-context-4.0.6.RELEASE.jar
spring-context-support-4.0.6.RELEASE.jar
spring-core-4.3.3.RELEASE.jar
spring-expression-4.0.6.RELEASE.jar
spring-jdbc-4.0.6.RELEASE.jar
spring-orm-4.0.6.RELEASE.jar
spring-oxm-4.0.6.RELEASE.jar
spring-security-config-4.1.3.RELEASE.jar
spring-security-core-4.1.3.RELEASE.jar
spring-security-web-4.1.3.RELEASE.jar
spring-tx-4.0.6.RELEASE.jar
spring-web-4.0.6.RELEASE.jar
spring-webmvc-4.0.6.RELEASE.jar
validation-api-1.1.0.Final.jar
xml-apis-1.0.b2.jar

Create Dynamic Web Project in Eclipse and add the below configuration to the web.xml file

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">

	<session-config>
		<session-timeout>1</session-timeout>
	</session-config>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-security.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Spring Security -->

	<servlet>
		<servlet-name>api</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>api</servlet-name>
		<url-pattern>/api/*</url-pattern>
	</servlet-mapping>

	<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>

</web-app>




Spring Restful Web Services Confiagurtion File

Create api-servlet.xml file contains configuration for Spring Restful Web Services

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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-4.0.xsd" >

</beans>

Security Configuration File

Create spring-security.xml file contains configuration for security

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-4.1.xsd
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context-4.0.xsd
	 http://www.springframework.org/schema/mvc
	 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

 	<context:component-scan base-package="demo.*" />

	<mvc:annotation-driven />

    <!-- Rest authentication entry point configuration -->
    <http auto-config="true"
    	use-expressions="true"
    	entry-point-ref="restAuthenticationEntryPoint">
        <intercept-url pattern="/api/**" />
        <sec:form-login authentication-success-handler-ref="mySuccessHandler"
            authentication-failure-handler-ref="myFailureHandler" />
        <logout />
    </http>

    <!-- Connect the custom authentication success handler -->
    <beans:bean id="mySuccessHandler"
        class="demo.security.RestAuthenticationSuccessHandler" />

    <!-- Using default failure handler -->
    <beans:bean id="myFailureHandler"
        class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" />

    <!-- Authentication manager -->
    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="acc1" password="123" authorities="ROLE_SUPER_ADMIN,ROLE_ADMIN,ROLE_USER" />
                <user name="acc2" password="123" authorities="ROLE_ADMIN,ROLE_USER" />
                <user name="acc3" password="123" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

    <!-- Enable the annotations for defining the secure role -->
    <global-method-security secured-annotations="enabled" />

</beans:beans>




Create demo.security package in server project. This package contain classes need for security in Spring Restful Web Services. Create classes: RestAuthenticationEntryPoint.java and RestAuthenticationSuccessHandler.java as below

RestAuthenticationEntryPoint.java

package demo.security;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

	@Override
	public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			AuthenticationException authenticationException) throws IOException, ServletException {
		httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
	}

}

RestAuthenticationSuccessHandler.java

package demo.security;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.StringUtils;

public class RestAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

	private RequestCache requestCache = new HttpSessionRequestCache();

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws ServletException, IOException {
		SavedRequest savedRequest = requestCache.getRequest(request, response);

		if (savedRequest == null) {
			clearAuthenticationAttributes(request);
			return;
		}

		String targetUrlParam = getTargetUrlParameter();
		if (isAlwaysUseDefaultTargetUrl() || (targetUrlParam != null && StringUtils.hasText(request.getParameter(targetUrlParam)))) {
			requestCache.removeRequest(request, response);
			clearAuthenticationAttributes(request);
			return;
		}

		clearAuthenticationAttributes(request);
	}

	public void setRequestCache(RequestCache requestCache) {
		this.requestCache = requestCache;
	}
}




Create Rest API Controller provides text/plain data for the client

package demo.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.*;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("demo")
public class DemoController {

	@RequestMapping(
		value = "work1",
		method = RequestMethod.GET,
		produces = { MimeTypeUtils.TEXT_PLAIN_VALUE }
	)
	public ResponseEntity<String> work1() {
		try {
			String content = "Work 1";
			return new ResponseEntity<String>(content, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

	@Secured({ "ROLE_SUPER_ADMIN" })
	@RequestMapping(
		value = "work2",
		method = RequestMethod.GET,
		produces = { MimeTypeUtils.TEXT_PLAIN_VALUE }
	)
	public ResponseEntity<String> work2() {
		try {
			String content = "Work 2";
			return new ResponseEntity<String>(content, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

	@Secured({ "ROLE_SUPER_ADMIN", "ROLE_ADMIN" })
	@RequestMapping(
		value = "work3",
		method = RequestMethod.GET,
		produces = { MimeTypeUtils.TEXT_PLAIN_VALUE }
	)
	public ResponseEntity<String> work3() {
		try {
			String content = "Work 3";
			return new ResponseEntity<String>(content, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

	@Secured({ "ROLE_SUPER_ADMIN", "ROLE_ADMIN", "ROLE_USER" })
	@RequestMapping(
		value = "work4",
		method = RequestMethod.GET,
		produces = { MimeTypeUtils.TEXT_PLAIN_VALUE }
	)
	public ResponseEntity<String> work4() {
		try {
			String content = "Work 4";
			return new ResponseEntity<String>(content, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

}

Access Web API use the following url: http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work1

Output

Work 1

Access restful web services use the following url: http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work2

Output

Access restful web services use the following url: http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work3

Output

Access restful web services use the following url: http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work4

Output

Create Java Project in Eclipse




DemoRestClientModel class contain methods call Web API

package models;

import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import org.apache.commons.codec.binary.Base64;

public class DemoRestClientModel {

	private String BASE_URL = "http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/";
	private RestTemplate restTemplate = new RestTemplate();
	private String username = "acc2";
	private String pasword = "123";

	private HttpHeaders getHeaders() {
		String plainCredentials = this.username + ":" + this.pasword;
		String base64Credentials = new String(Base64.encodeBase64(plainCredentials.getBytes()));
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "Basic " + base64Credentials);
		return headers;
	}

	public ResponseEntity<String> work1() {
		return restTemplate.exchange(BASE_URL + "work1", HttpMethod.GET, null, String.class);
	}

	public ResponseEntity<String> work2() {
		return restTemplate.exchange(BASE_URL + "work2", HttpMethod.GET, null, String.class);
	}

	public ResponseEntity<String> work3() {
		HttpEntity<String> request = new HttpEntity<String>(getHeaders());
		return restTemplate.exchange(BASE_URL + "work2", HttpMethod.GET, request, String.class);
	}

	public ResponseEntity<String> work4() {
		HttpEntity<String> request = new HttpEntity<String>(getHeaders());
		return restTemplate.exchange(BASE_URL + "work3", HttpMethod.GET, request, String.class);
	}

	public ResponseEntity<String> work5() {
		HttpEntity<String> request = new HttpEntity<String>(getHeaders());
		return restTemplate.exchange(BASE_URL + "work4", HttpMethod.GET, request, String.class);
	}

}
package main;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import models.DemoRestClientModel;

public class Main {

	public static void main(String[] args) {

		DemoRestClientModel demoRestClientModel = new DemoRestClientModel();

		try {
			System.out.println("Test with work1 web method");
			ResponseEntity<String> responseEntity1 = demoRestClientModel.work1();
	        HttpStatus HttpStatus1 = responseEntity1.getStatusCode();
	        System.out.println("\tStatus Code: " + HttpStatus1);
	        String result1 = responseEntity1.getBody();
	        System.out.println("\tResult: " + result1);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

        try {
        	System.out.println("Test with work2 web method without account");
            ResponseEntity<String> responseEntity2 = demoRestClientModel.work2();
            HttpStatus HttpStatus2 = responseEntity2.getStatusCode();
            System.out.println("\tStatus Code: " + HttpStatus2);
            String result2 = responseEntity2.getBody();
            System.out.println("\tResult: " + result2);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

        try {
	        System.out.println("Test with acc2 have roles: admin and user access work2 web method");
	        ResponseEntity<String> responseEntity3 = demoRestClientModel.work3();
	        HttpStatus HttpStatus3 = responseEntity3.getStatusCode();
	        System.out.println("\tStatus Code: " + HttpStatus3);
	        String result3 = responseEntity3.getBody();
	        System.out.println("\tResult: " + result3);
        } catch (Exception e) {
			System.out.println(e.getMessage());
		}

        try {
	        System.out.println("Test with acc2 have roles: admin and user access work3 web method");
	        ResponseEntity<String> responseEntity4 = demoRestClientModel.work4();
	        HttpStatus HttpStatus4 = responseEntity4.getStatusCode();
	        System.out.println("\tStatus Code: " + HttpStatus4);
	        String result4 = responseEntity4.getBody();
	        System.out.println("\tResult: " + result4);
        } catch (Exception e) {
			System.out.println(e.getMessage());
		}

        try {
	        System.out.println("Test with acc2 have roles: admin and user access work4 web method");
	        ResponseEntity<String> responseEntity5 = demoRestClientModel.work5();
	        HttpStatus HttpStatus5 = responseEntity5.getStatusCode();
	        System.out.println("\tStatus Code: " + HttpStatus5);
	        String result5 = responseEntity5.getBody();
	        System.out.println("\tResult: " + result5);
        } catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

}




Test with work1 web method
	Status Code: 200
	Result: Work 1

Test with work2 web method without account
GET request for "http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work2" resulted in 401 (Unauthorized); invoking error handler
401 Unauthorized

Test with acc2 have roles: admin and user access work2 web method
WARNING: GET request for "http://localhost:8086/SecurityInWebServiceSpringFramework/api/demo/work2" resulted in 403 (Forbidden); invoking error handler
403 Forbidden

Test with acc2 have roles: admin and user access work3 web method
	Status Code: 200
	Result: Work 3

Test with acc2 have roles: admin and user access work4 web method
	Status Code: 200
	Result: Work 4