Spring MVC Security REST Digest Authentication

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringSecurityRESTDigestAuthentication

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0.

STEP 3:- copy below jars to WEB-INF/lib folder.
  • aopalliance-1.0.jar
  • aspectjrt-1.8.4.jar
  • commons-io-2.4.jar
  • commons-logging-1.2.jar
  • jackson-annotations-2.6.0.jar
  • jackson-core-2.6.0.jar
  • jackson-databind-2.6.0.jar
  • jtds.jar
  • log4j-1.2.17.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-dao-2.0.8.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-jdbc-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-oauth2-2.0.8.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 4:- Create Spring Configuration Bean file. /WebContent/WEB-INF/dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 
 xmlns:context="http://www.springframework.org/schema/context"
 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.xsd
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
 <context:component-scan base-package="com.tutorialsdesk.controllers" />
 <context:component-scan base-package="com.tutorialsdesk.services" />

 <mvc:annotation-driven />
 
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.UrlBasedViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />
 </bean>
 
 <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
STEP 5:- Create Spring security configuration file. /WebContent/WEB-INF/spring-security.xml
First thing to understand about the configuration is that, while Spring Security does have full out of the box support for the Digest authentication mechanism, this support is not as well integrated into the namespace as Basic Authentication was.
In this case, we need to manually define the raw beans that are going to make up the security configuration – the DigestAuthenticationFilter and the DigestAuthenticationEntryPoint:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
 xmlns:security="http://www.springframework.org/schema/security"
 xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 
 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/security
 http://www.springframework.org/schema/security/spring-security.xsd">
 
 
<security:global-method-security pre-post-annotations="enabled"/>

 <security:http use-expressions="true" entry-point-ref="digestEntryPoint">
 <security:intercept-url access="hasRole('ROLE_VERIFIED')" pattern="/api/**"/>
 <security:intercept-url pattern='/*' access='permitAll'/>

 <security:logout logout-success-url="/"/>

 <security:session-management session-fixation-protection="newSession">
 <security:concurrency-control max-sessions="1"/>
 </security:session-management>
 
 <security:custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
 </security:http>
 <security:authentication-manager>
 <security:authentication-provider>
 <security:user-service id="userService">
 <security:user name="test" password="test" authorities="ROLE_VERIFIED"/>
 </security:user-service>

 </security:authentication-provider>
 </security:authentication-manager>
 
 
 <bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
 <property name="userDetailsService" ref="userService" />
 <property name="authenticationEntryPoint" ref="digestEntryPoint" />
 </bean>
 
 <bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
 <property name="realmName" value="Contacts Realm via Digest Authentication" />
 <property name="key" value="PrivateKeyValue" />
 <property name="nonceValiditySeconds" value="10"/>
 </bean>
 
</beans>
Next, we need to integrate these beans into the overall security configuration – and in this case, the namespace is still flexible enough to allow us to do that. The first part of this is pointing to the custom entry point bean, via the entry-point-ref attribute of the main <http> element. The second part is adding the newly defined digest filter into the security filter chain. Since this filter is functionally equivalent to the BasicAuthenticationFilter, we are using the same relative position in the chain – this is specified by the BASIC_AUTH_FILTER alias in the overall Spring Security Standard Filters. Finally, notice that the Digest Filter is configured to point to the user service bean – and here, the namespace is again very useful as it allows us to specify a bean name for the default user service created by the <user-service> element:
<user-service id="userService">
STEP 6 :- Map Spring configuration files in /WebContent/WEB-INF/web.xml file as below :-
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
 <display-name>SpringSecurityRESTDigestAuthentication</display-name>
 <servlet>
 <servlet-name>dispatcher</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
 <servlet-name>dispatcher</servlet-name>
 <url-pattern>/</url-pattern>
 </servlet-mapping>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value> 
 /WEB-INF/spring-security.xml
 </param-value>
 </context-param>
 <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>

STEP 7 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: RestController.java
package com.tutorialsdesk.controllers;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.tutorialsdesk.models.Employee;
import com.tutorialsdesk.services.EmployeeService;

@Controller
@RequestMapping()
public class RestController {

 @Autowired
 EmployeeService employeeService;

 @RequestMapping(value = "api/users", method = RequestMethod.GET)
 @ResponseBody
 public List<Employee> list() {
 System.out.println("RestController.list()");
 
 return employeeService.getEmployeesList();
 }
 
}

STEP 9 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: Employee.java
package com.tutorialsdesk.models;

import java.io.Serializable;

public class Employee implements Serializable{

 private static final long serialVersionUID = 5088863992478607917L;

 private Integer id;
 
 private String firstName;

 private String lastName;
 
 private String email;

 public Employee(Integer id, String firstName, String lastName, String email) {
 super();
 this.id = id;
 this.firstName = firstName;
 this.lastName = lastName;
 this.email = email;
 }

 public Employee() {
 super();
 }

 public Integer getId() {
 return id;
 }

 public void setId(Integer id) {
 this.id = id;
 }

 public String getFirstName() {
 return firstName;
 }

 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

 public String getLastName() {
 return lastName;
 }

 public void setLastName(String lastName) {
 this.lastName = lastName;
 }

 public String getEmail() {
 return email;
 }

 public void setEmail(String email) {
 this.email = email;
 }

 public static long getSerialversionuid() {
 return serialVersionUID;
 }

 @Override
 public String toString() {
 return "Employee [id=" + id + ", firstName=" + firstName
 + ", lastName=" + lastName + ", email=" + email + "]";
 }
 
}

STEP 10 :- Create Service Interface and Class.
  • Package: com.tutorialsdesk.services
  • Filename: EmployeeService.java
package com.tutorialsdesk.services;

import java.util.List;

import com.tutorialsdesk.models.Employee;

public interface EmployeeService {
 public List<Employee> getEmployeesList();
}

  • Package: com.tutorialsdesk.services
  • Filename: EmployeeServiceImpl.java
package com.tutorialsdesk.services;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.tutorialsdesk.models.Employee;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Override
 public List<Employee> getEmployeesList() {
 List<Employee> employeeList = new ArrayList<Employee>();
 employeeList.add(new Employee(1, "Prince", "Sethi", "prince@gmail.com"));
 employeeList.add(new Employee(2, "Rambir", "Singh", "rambir@gmail.com"));
 employeeList.add(new Employee(3, "Vishnu", "Jangid", "vishnu@gmail.com"));
 return employeeList;
 }

}

STEP 11 :- Create jsp file in /WebContent/WEB-INF folder
  • Filename: index.jsp
<html>
<body>
<h2>Spring REST Security Digest Authentication</h2> 
<a href="http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users">Get Users List</a>
<br/>
<br/>
Or use CURL command <br/>
<br/>
curl -i --digest --user test:test http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

</body>
</html>

STEP 12 :- Run your project enter below URL in your browser http://localhost:8080/SpringSecurityRESTDigestAuthentication/ STEP 13 :- Consuming The Secured Application The curl command is our go to tool for consuming the secured application.
First, let’s try to request the /api/users without providing any security credentials:
curl -i http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

We get back the expected 401 Unauthorized and the Authentication Challenge:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=B8B4177EE54D239C35B4A4EE36EAD2C2; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="
auth", nonce="MTQ2Njc1MTMyMTM0NDo2NDQ3Zjc2ODc1MWQ0MThmMzM5ZWNiMGZlZGNkMDYzNQ=="
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1061
Date: Fri, 24 Jun 2016 06:55:11 GMT

<html><head><title>Apache Tomcat/7.0.55 - Error report</title><style><!--H1 {fon
t-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:
22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525
D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;backgro
und-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;col
or:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:w
hite;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;backgroun
d:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR
{color : #525D76;}--></style> </head><body><h1>HTTP Status 401 - Full authentica
tion is required to access this resource</h1><HR size="1" noshade="noshade"><p><
b>type</b> Status report</p><p><b>message</b> <u>Full authentication is required
 to access this resource</u></p><p><b>description</b> <u>This request requires H
TTP authentication.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.
55</h3></body></html>

The browser would interpret this challenge and prompt us for credentials with a simple dialog, but since we’re using curl, this isn’t the case.

Let’s now provide the correct credentials and send the request again:
curl -i --digest --user test:test http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

Notice that we are enabling Digest Authentication for the curl command via the –digest flag. The first response from the server will be the same – the 401 Unauthorized – but the challenge will now be interpreted and acted upon by a second request – which will succeed with a 200 OK:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=4A34FF7C29FC9702D5A7F986D5815429; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="
auth", nonce="MTQ2Njc1MTM3NDgwMzoxYTJmZTNiMWRjZDAyNTUxY2EyYjM0MWQ3NzE4M2E4ZA=="
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1061
Date: Fri, 24 Jun 2016 06:56:04 GMT

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=5CD390094F262230FBB6EA59E1253846; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 24 Jun 2016 06:56:04 GMT

[{"id":1,"firstName":"Prince","lastName":"Sethi","email":"prince@gmail.com"},{"i
d":2,"firstName":"Rambir","lastName":"Singh","email":"rambir@gmail.com"},{"id":3
,"firstName":"Vishnu","lastName":"Jangid","email":"vishnu@gmail.com"}]
From the browser, the application can be consumed normally – the only difference is that a login page is no longer a hard requirement since all browsers support Basic Authentication and use a dialog to prompt the user for credentials.

A final note on this interaction is that a client can preemptively send the correct Authorization header with the first request, and thus entirely avoid the server security challenge and the second request.

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC Security REST Digest Authentication Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.