JavaBlog.fr / Java.lu DEVELOPMENT,Java,Spring Java/Spring3: Spring Security, authentication provider, override authentication token

Java/Spring3: Spring Security, authentication provider, override authentication token

Hi,

I would write an article concerning the overridden of the token of Spring 3 Security. In this post, we will follow several points: creation of a simple Spring MVC Web application (controller, JSP pages,…), securization with Spring security via custom login form, override the authentication components (provider, token,…).

Creation of Spring MVC Web application

  • Create a simple Dynamic Web Module in Eclipse named Spring3Security;
  • Final structure of Eclipse project named Spring3Security;

  • Add the following jars in the folder Spring3Security\war\WEB-INF\lib:
    • activation-1.1.jar
    • antlr-2.7.7.jar
    • aopalliance-1.0.jar
    • asm-3.3.1.jar
    • cglib-2.2.jar
    • commons-logging-1.1.1.jar
    • javassist-3.8.1.GA.jar
    • jstl-1.2.jar
    • org.springframework.aop-3.0.5.RELEASE.jar
    • org.springframework.asm-3.0.5.RELEASE.jar
    • org.springframework.beans-3.0.5.RELEASE.jar
    • org.springframework.context.support-3.0.5.RELEASE.jar
    • org.springframework.context-3.0.5.RELEASE.jar
    • org.springframework.core-3.0.5.RELEASE.jar
    • org.springframework.expression-3.0.5.RELEASE.jar
    • org.springframework.jdbc-3.0.5.RELEASE.jar
    • org.springframework.jms-3.0.5.RELEASE.jar
    • org.springframework.orm-3.0.5.RELEASE.jar
    • org.springframework.oxm-3.0.5.RELEASE.jar
    • org.springframework.web-3.0.5.RELEASE.jar
    • servlet-api-2.5.jar
    • spring-oxm-tiger-1.5.9.jar
    • spring-security-acl-3.1.2.RELEASE.jar
    • spring-security-config-3.1.2.RELEASE.jar
    • spring-security-core-3.1.2.RELEASE.jar
    • spring-security-core-tiger-2.0.7.RELEASE.jar
    • spring-security-taglibs-3.1.2.RELEASE.jar
    • spring-security-web-3.1.2.RELEASE.jar
    • spring-support-2.0.8.jar
    • spring-webmvc-3.0.5.RELEASE.jar

  • Edit the web descriptor file web.xml, in order to add a section concerning the Spring context and Spring security configuration (http filter):
    001<?xml version="1.0" encoding="UTF-8"?>
    004    xmlns:javaee="http://java.sun.com/xml/ns/javaee"
    007    version="2.5">
    008 
    009    <display-name>SPRING3SECURITY</display-name>
    010 
    011    <welcome-file-list>
    012        <welcome-file>index.jsp</welcome-file>
    013    </welcome-file-list>
    014 
    015    <error-page>
    016        <error-code>403</error-code>
    017        <location>/unauthorizedAccess.jsp</location>
    018    </error-page>
    019    <error-page>
    020        <error-code>404</error-code>
    021        <location>/unauthorizedAccess.jsp</location>
    022    </error-page>
    023 
    024    <!-- ##################################### -->
    025    <!-- SPRING SECURITY -->
    026    <!-- ##################################### -->   
    027    <filter>
    028        <filter-name>springSecurityFilterChain</filter-name>
    029        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    030    </filter>
    031    <filter-mapping>
    032        <filter-name>springSecurityFilterChain</filter-name>
    033        <url-pattern>/*</url-pattern>
    034    </filter-mapping>
    035 
    036 
    037    <listener>
    038        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    039    </listener>
    040     
    041 
    042    <!-- Login failed error --> 
    043 
    044    <!-- MUST be first context param -->
    045    <context-param>
    046        <param-name>webAppRootKey</param-name>
    047        <param-value>spring3security.root</param-value>
    048    </context-param>
    049 
    050    <!-- MUST be second context param -->
    051    <context-param>
    052        <param-name>log4jConfigLocation</param-name>
    053<!--         <param-value>../../etc/spring3security-log4j.properties</param-value> -->
    054        <param-value>classpath:log4j.properties</param-value>
    055    </context-param>
    056 
    057    <!--  MUST be first listener -->
    058    <listener>
    059        <listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
    060    </listener>
    061 
    062    <!--  MUST be second listener -->
    063    <listener>
    064        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    065    </listener>
    066 
    067    <listener>
    068        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    069    </listener>
    070 
    071 
    072 
    073    <!-- ##################################### -->
    074    <!-- SPRING MVC & SPRING CONTEXT-->
    075    <!-- ##################################### -->       
    076    <context-param>
    077        <param-name>webAppRootKey</param-name>
    078        <param-value>Spring3Security.root</param-value>
    079    </context-param>
    080 
    081    <listener>
    082        <listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
    083    </listener>
    084    <listener>
    085        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    086    </listener>
    087 
    088    <context-param>
    089        <param-name>contextConfigLocation</param-name>
    090        <param-value>/WEB-INF/applicationContext.xml</param-value>
    091    </context-param>
    092     
    093    <servlet>
    094        <servlet-name>Spring3Security</servlet-name>
    095        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    096        <load-on-startup>1</load-on-startup>
    097    </servlet>
    098    <servlet-mapping>
    099        <servlet-name>Spring3Security</servlet-name>
    100        <url-pattern>*.do</url-pattern>
    101    </servlet-mapping>
    102 
    103</web-app>



Spring MVC configuration

  • First, we need to configure the Spring MVC controllers. For this, edit the file Spring3Security-servlet.xml in order to define the “web beans” here such as the Controllers and the URL mapping configurations. The Web beans defined in this file may reference “application beans” in the “root” web application context:
    01<?xml version="1.0" encoding="UTF-8"?>
    05    xsi:schemaLocation="http://www.springframework.org/schema/beans
    07 
    08 
    09    <!-- ####################### SPRING MVC ################################################### -->
    10    <!--
    11        Define the "web beans" here such as the Controllers and the URL mapping configurations
    12        Web beans here may reference "application beans" in the "root" web application context
    13    -->
    14 
    15 
    16    <!-- ################### SPRING MVC VIEW RESOLVER  ################### -->
    17    <!--
    18        IF the Controller returns a logical view name="rewardList" THEN
    19            the ViewResolver will return the file "/WEB-INF/jsp/rewardList.jsp"
    20        END IF
    21     -->
    22    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    23        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
    24        <property name="prefix" value="/WEB-INF/jsp/"></property>
    25        <property name="suffix" value=".jsp"></property>
    26        <property name="order"><value>2</value></property>
    27    </bean>
    28     
    29 
    30    <!-- ################### SPRING MVC CONTROLLER XML  ################### -->
    31    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    32        <property name="mappings">
    33            <value>
    34                /loginSecure.do=loginSecureController
    35                /myOwnController.do=myOwnController
    36            </value>
    37        </property>
    38    </bean>
    39     
    40     
    41    <bean name="loginSecureController" class="com.ho.spring3.security.test1.controller.LoginSecureController">
    42        <property name="methodNameResolver" ><ref bean="paramResolver"/></property>
    43    </bean>
    44 
    45    <bean name="myOwnController" class="com.ho.spring3.security.test1.controller.MyOwnController" >
    46        <property name="methodNameResolver" ><ref bean="paramResolver"/></property>
    47    </bean>
    48 
    49    <bean id="paramResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
    50        <property name="paramName"><value>action</value></property>
    51    </bean>
    52 
    53 
    54    <!-- ################### SPRING JSON RESOLVER ################### -->
    55    <bean id="jsonResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
    56        <property name="order"><value>1</value></property>
    57    </bean>
    58 
    59 
    60</beans>

  • Then, we need a Spring MVC controller MyOwnController to handle the web requests for the pages navigation (handlePage0, handlePage1, handlePage2 methods):
    01package com.ho.spring3.security.test1.controller;
    02 
    03import java.io.IOException;
    04 
    05import javax.servlet.ServletException;
    06import javax.servlet.http.HttpServletRequest;
    07import javax.servlet.http.HttpServletResponse;
    08 
    09import org.apache.commons.logging.Log;
    10import org.apache.commons.logging.LogFactory;
    11import org.springframework.web.servlet.ModelAndView;
    12import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
    13 
    14public class MyOwnController extends MultiActionController {
    15    // ------------------------------------------------------------------ LOG4J
    16    protected final Log logger = LogFactory.getLog(this.getClass());
    17     
    18    // --------------------------------------------------------- PUBLIC METHODS
    19    public ModelAndView handlePage0(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    20        logActionName("handlePage0");
    21 
    22        return new ModelAndView("page0");
    23    }
    24 
    25    public ModelAndView handlePage1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    26        logActionName("handlePage1");
    27 
    28        return new ModelAndView("page1");
    29    }
    30 
    31    public ModelAndView handlePage2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    32        logActionName("handlePage2");
    33 
    34        return new ModelAndView("page2");
    35    }
    36 
    37     
    38    // -------------------------------------------------------- PRIVATE METHODS
    39    private void logActionName(String actionName) {
    40        if (logger.isDebugEnabled()) {
    41            logger.debug(this.getClass().getSimpleName() + actionName + "()");
    42        } // end-if
    43    }
    44}

  • So, we need also a Spring MVC controller LoginSecureController to handle the security requests after that the authentication is successful (handleLogin method) or for the logout request (handleLogout method),
    01package com.ho.spring3.security.test1.controller;
    02 
    03import java.io.IOException;
    04 
    05import javax.servlet.ServletException;
    06import javax.servlet.http.HttpServletRequest;
    07import javax.servlet.http.HttpServletResponse;
    08 
    09import org.springframework.web.servlet.ModelAndView;
    10import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
    11import com.ho.spring3.security.test1.util.MyRoleUtil;
    12 
    13 
    14 
    15public class LoginSecureController extends MultiActionController {
    16 
    17    // -------------------------------------------------------------- PUBLIC FUNCTIONS
    18    public LoginSecureController() { }
    19 
    20    public ModelAndView handleLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    21        if (logger.isInfoEnabled()) {
    22            logger.info("LoginSecureController : user " + (new MyRoleUtil()).getLoggedUserName() + " logged in.");
    23            MyRoleUtil roleUtil = new MyRoleUtil();
    24            logger.info("User roles = " + roleUtil.getLoggedUserRolesNames());
    25        } // end-if
    26 
    27        return new ModelAndView("redirect:/myOwnController.do?action=handlePage0");
    28    }
    29     
    30    public ModelAndView handleLogout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    31        // Invaliadtion manuelle de la session utilisateur
    32        if(null!=request.getSession()){
    33            request.getSession().invalidate();
    34        }
    35 
    36        if (logger.isInfoEnabled()) {
    37            logger.info("LoginSecureController : user " + (new MyRoleUtil()).getLoggedUserName() + " logged out.");
    38        } // end-if
    39     
    40        return new ModelAndView("redirect:/index.jsp");
    41    }
    42}

Spring Security components (provider, token)
We will securize the application with Spring security via a custom login form.

  • Add the security access configuration file name applicationContext.xml in the folder Spring3Security\war\WEB-INF:
    01<?xml version="1.0" encoding="UTF-8"?>
    07    xsi:schemaLocation="
    16    ">
    17     
    18    <!-- ################### SPRING SECURITY ################### -->
    19    <global-method-security jsr250-annotations="enabled" secured-annotations="enabled" />
    20 
    21    <http pattern="/*.jsp" security="none" />
    22    <http pattern="/*.jsp.*" security="none" />
    23    <http pattern="/jsp/**" security="none" />
    24    <http pattern="/css/**" security="none" />
    25    <http pattern="/images/**" security="none" />
    26    <http pattern="/img/**" security="none" />
    27    <http pattern="/js/**" security="none" />
    28 
    29    <http auto-config="true">
    30 
    31        <!-- Limitation of simultaneous connections  -->
    32        <session-management session-fixation-protection="none">
    33            <!-- <concurrency-control error-if-maximum-exceeded="true" max-sessions="1"/> -->
    34            <concurrency-control max-sessions="1"/>
    35        </session-management>
    36 
    37        <!-- Access rule: every user should have the role ROLE_BASIC to view any URLs. The syntax, / ** is called "Ant syntax." -->
    38        <!-- The role ROLE_BASIC will be affected after authentication -->
    39        <intercept-url pattern="/*.do.*" access="ROLE_BASIC" />
    40        <intercept-url pattern="/.*" access="ROLE_BASIC" />
    41        <intercept-url pattern="/**" access="ROLE_BASIC" />
    42 
    43 
    44        <!-- Authentication form in Spring Security -->
    45        <form-login login-page="/login.jsp"
    46            authentication-failure-url="/login.jsp?error=true"
    47            default-target-url="/loginSecure.do?action=handleLogin" />
    48 
    49         
    50        <!-- Disconnect: By default, the disconnection URL is j_spring_security_logout. -->
    51        <logout invalidate-session="true"
    52            logout-success-url="/index.jsp"
    53            logout-url="/loginSecure.do?action=handleLogout" />
    54 
    55    </http>
    56 
    57 
    58    <!-- Components AuthenticationProvider -->
    59    <authentication-manager>
    60        <!-- Spring Security password hashing see http://md5.gromweb.com/ -->
    61<!--         <authentication-provider>  -->
    62<!--             <password-encoder hash="md5" />   -->
    63<!--             <user-service id="userDetailsService"> -->
    64<!--                 <user name="admin" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_BASIC,ROLE_FULLACCESS_XML" /> -->
    65<!--                 <user name="user1" password="24c9e15e52afc47c225b757e7bee1f9d" authorities="ROLE_BASIC,ROLE_FULLACCESS_XML" /> -->
    66<!--                 <user name="user2" password="7e58d63b60197ceb55a1c487989a3720" authorities="ROLE_BASIC,ROLE_FULLACCESS_XML" /> -->
    67<!--             </user-service> -->
    68<!--         </authentication-provider> -->
    69 
    70 
    71        <authentication-provider ref="myAuthenticationProvider" />
    72    </authentication-manager>
    73 
    74 
    75    <beans:bean id="myAuthenticationProvider" class="com.ho.spring3.security.test1.util.MyAuthenticationProvider">
    76    </beans:bean>
    77 
    78</beans:beans>

    Some explanations:

    • We have used a customized HTTP authentication form via the form-login tag: a cutomized form page named login.jsp to which all users will be redirected;
    • If the authentication fails, the user will redirect to the URL /login.jsp?error=true; but if the authentication is successful, the user will redirect to the URL /loginSecure.do?action=handleLogin:
      1<form-login login-page="/login.jsp"
      2    authentication-failure-url="/login.jsp?error=true"
      3    default-target-url="/loginSecure.do?action=handleLogin" />
    • The syntax used in the acess rules /** is named/called “Ant syntax”;
    • All JSP pages, css, images, javascript resources will not be securized:
      1<http pattern="/*.jsp" security="none" />
      2<http pattern="/*.jsp.*" security="none" />
      3<http pattern="/jsp/**" security="none" />
      4<http pattern="/css/**" security="none" />
      5<http pattern="/images/**" security="none" />
      6<http pattern="/img/**" security="none" />
      7<http pattern="/js/**" security="none" />
    • We have defined 1 access rule: every user should have the role ROLE_BASIC to view the URLs *.do. The role ROLE_BASIC will be affected after authentication:
      1<intercept-url pattern="/*.do.*" access="ROLE_BASIC" />
      2<intercept-url pattern="/.*" access="ROLE_BASIC" />
      3<intercept-url pattern="/**" access="ROLE_BASIC" />
    • We have set a limitation of simultaneous connections.
      1<session-management session-fixation-protection="none">
      2    <concurrency-control max-sessions="1"/>
      3</session-management>

      .. it requires the presence of the listener “org.springframework.security.web.session.HttpSessionEventPublisher” in web.xml. The max-sessions attribute specifies the maximum number of simultaneous connections to the same identifier;

    • We have specified a logout URL /loginSecure.do?action=handleLogout which will invalide the user’s session;
      1<logout invalidate-session="true"
      2    logout-success-url="/index.jsp"
      3    logout-url="/loginSecure.do?action=handleLogout" />
    • Finally, we have defined a custom AuthenticationProvider named myAuthenticationProvider. The components AuthenticationProvider of Spring Security, perform the authentication, that is to say it manages the verification of the identity of the user:
      1<authentication-manager>
      2    <authentication-provider ref="myAuthenticationProvider" />
      3</authentication-manager>
      4 
      5<beans:bean id="myAuthenticationProvider" class="com.ho.spring3.security.test1.util.MyAuthenticationProvider"></beans:bean>

  • The index page index.jsp will redirect the user to a securized URL /loginSecure.do?action=handleLogin for which the login form will be displayed by the Spring security:
    1<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
    2<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    3<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
    4<c:redirect url="/loginSecure.do?action=handleLogin"/>

  • The login form login.jsp will be display an authentication form, and error message if the authentication has failed:
    01<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
    02<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    03<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    04<html>
    05<head>
    06<title>Login Page</title>
    07</head>
    08<body onload='document.f.j_username.focus();'>
    09<h3>Login with Username and Password  - JavaBlog.fr - Custom Page</h3>
    10<c:if test="${param.error == true}">
    11    <font color="red">
    12    Authentication was not successful, try again.<br />
    13    Cause:
    14    <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/><br/>
    15    <%-- ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}<br/> --%>
    16    <%-- ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}<br/> --%>
    17    </font>
    18    <br/>
    19</c:if>
    20<form name='f' action="/Spring3Security/j_spring_security_check" method='POST'>
    21<table>
    22<tr>
    23<td>User:</td>
    24<td><input type='text' name='j_username' value=''>
    25</td>
    26</tr>
    27<tr>
    28<td>Password:</td>
    29<td><input type='password' name='j_password' />
    30</td>
    31</tr>
    32<tr>
    33<td colspan='2'><input name="submit" type="submit" value="submit" />
    34</td>
    35</tr>
    36<tr>
    37<td colspan='2'><input name="reset" type="reset" />
    38</td>
    39</tr>
    40</table>
    41</form>
    42</body>
    43</html>

  • After a successful authentication, the main page page0.jsp will display the user’s informations:
    – fullname, email stored in the custom token
    – username, roles from the Spring security,

    01<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    02<%@ taglib prefix="sec"  uri="http://www.springframework.org/security/tags"%>
    03<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    04<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
    05<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
    06<%@ page import="com.ho.spring3.security.test1.util.MyRoleUtil" %>
    07 
    08 
    09<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    11<head>
    12<META http-equiv="Cache-Control" content="no-cache">
    13<META http-equiv="Pragma" content="no-cache">
    14<META http-equiv="Expires" content="0">
    15<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    16<title>Page 0</title>
    17</head>
    18<body>
    19 
    20<%-- <h2>Bienvenue <sec:authentication property="principal.username" />:  --%>
    21<h2>Bienvenue <%= new MyRoleUtil().getLoggedUserName()%>:</h2>
    22* <%= new MyRoleUtil().getCurrentMyUser().getFullName()%><br/>
    23* <%= new MyRoleUtil().getCurrentMyUser().getEmail()%><br/>
    24<br/>
    25 
    26<table>
    27<tr><td><a href="/Spring3Security/loginSecure.do?action=handleLogout">Logout</a></td></tr>
    28<tr>
    29    <td><a href="myOwnController.do?action=handlePage0">page0</a></td>
    30    <td>&nbsp;|&nbsp;</td>
    31    <td><a href="myOwnController.do?action=handlePage1">page1</a></td>
    32    <td>&nbsp;|&nbsp;</td>
    33    <td><a href="myOwnController.do?action=handlePage2">page2</a></td>
    34</tr>
    35</table>
    36 
    37 
    38<br/>
    39Yours roles:
    40<sec:authentication property="authorities" var="authorities" />
    41<ul>
    42<c:forEach items="${authorities}" var="authority">
    43    <li>${authority}</li>
    44</c:forEach>
    45</ul>
    46 
    47<sec:authorize ifAnyGranted ="ROLE_BASIC,ROLE_FULLACCESS_XML,ROLE_FULLACCESS_CUSTOM">
    48    <br/>Code visible for users who have the roles ROLE_FULLACCESS_XML <u>or</u> ROLE_FULLACCESS_CUSTOM
    49</sec:authorize>
    50 
    51<sec:authorize ifAllGranted ="ROLE_FULLACCESS_XML,ROLE_FULLACCESS_CUSTOM">
    52    <br/>Code visible for users who have the roles ROLE_FULLACCESS_XML <u>and</u> ROLE_FULLACCESS_CUSTOM
    53</sec:authorize>
    54         
    55<sec:authorize ifNotGranted ="ROLE_FULLACCESS_XML,ROLE_FULLACCESS_CUSTOM">
    56    <br/>Code visible for users who don't have the role ROLE_FULLACCESS_XML, <u>and neither</u> ROLE_FULLACCESS_CUSTOM
    57</sec:authorize>
    58 
    59<sec:authorize ifAnyGranted ="ROLE_FULLACCESS_XML">
    60    <br/>Code visible for the users who have the role ROLE_FULLACCESS_XML
    61</sec:authorize>
    62 
    63<sec:authorize ifAnyGranted ="ROLE_FULLACCESS_CUSTOM">
    64    <br/>Code visible for the users who have the role ROLE_FULLACCESS_CUSTOM
    65</sec:authorize>
    66     
    67<br/>
    68</div>
    69</body>
    70</html>

  • Several pages page1.jsp and page2.jsp will contain the mock application pages like:
    01<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
    02<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    03 
    04<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    05<html>
    06<head>
    07<title>Page 1</title>
    08</head>
    09<body>
    10 
    11<table>
    12<tr><td><a href="/Spring3Security/loginSecure.do?action=handleLogout">Logout</a></td></tr>
    13<tr>
    14    <td><a href="myOwnController.do?action=handlePage0">page0</a></td>
    15    <td>&nbsp;|&nbsp;</td>
    16    <td><a href="myOwnController.do?action=handlePage1">page1</a></td>
    17    <td>&nbsp;|&nbsp;</td>
    18    <td><a href="myOwnController.do?action=handlePage2">page2</a></td>
    19</tr>
    20</table>
    21<hr/>
    22<h3>PAGE 1 </h3>
    23</body>
    24</html>

  • The main class is MyAuthenticationProvider which performs the authentication, i.e., it manages the checking of user’s identity via the authenticate method which gets the filled login and password to check with others systems (LDAP, WS, …). In our case, we check only if
    the login == password???. Then, we add the technical role ROLE_BASIC for the AUTHENTICATION ONLY, and the applicative ROLE_FULLACCESS_CUSTOM role. And finally, we have set the specific user’s informations (fullname and email) in an simple POJO MyUser
    used in the security and representing the User informations stored in the authentication mechanism:

    01package com.ho.spring3.security.test1.util;
    02 
    03import java.util.ArrayList;
    04import java.util.List;
    05 
    06import org.springframework.security.authentication.AuthenticationProvider;
    07import org.springframework.security.authentication.AuthenticationServiceException;
    08import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    09import org.springframework.security.core.Authentication;
    10import org.springframework.security.core.AuthenticationException;
    11import org.springframework.security.core.GrantedAuthority;
    12import org.springframework.security.core.authority.GrantedAuthorityImpl;
    13 
    14 
    15/**
    16 * The "AuthenticationProvider" components perform the authentication, i.e., they manage the checking of user's identity.
    17 *
    18 * @author Huseyin OZVEREN
    19 *
    20 */
    21public class MyAuthenticationProvider implements AuthenticationProvider {
    22     
    23     
    24    // ---------------------------------- PUBLIC METHODS
    25    @Override
    26    public Authentication authenticate(Authentication authentication) throws AuthenticationException{
    27        // Login
    28        //String login= authentication.getName();
    29        String login = (String) authentication.getPrincipal();
    30 
    31        // Password
    32        String password = (String) authentication.getCredentials();
    33 
    34         
    35        // Additional details of current (not yet authenticated) user
    36        MyUser myUser = null;
    37         
    38        if(password == null || login == null || login.trim().length()==0 || password.trim().length()==0){
    39            throw new AuthenticationServiceException("Your login/password are empty!!!");
    40        }
    41         
    42        boolean isAuth= false;
    43        try{
    44             
    45            // .... Call remote service like LDAP or WS
    46            // login == password???
    47            isAuth = (login.equals(password));
    48             
    49            List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
    50            if(isAuth){
    51                // Technical role : FOR AUTHENTICATION ONLY
    52                AUTHORITIES.add(new GrantedAuthorityImpl("ROLE_BASIC"));
    53                 
    54                // .... Get Applicative Roles from remote services LDAP of WS
    55                AUTHORITIES.add(new GrantedAuthorityImpl("ROLE_FULLACCESS_CUSTOM"));
    56                 
    57                // .... Get User Details from remote services LDAP of WS
    58                {
    59                    // ---- FullName
    60                    String fullName = "Huseyin OZVEREN";
    61                    // ---- Email
    62                    String email = "contact@javablog.fr";
    63                    //
    64                    myUser = new MyUser(fullName, email);
    65                }
    66             
    67            }else{
    68                throw new AuthenticationServiceException("Your login attempt was not successful.");
    69            }
    70             
    71             
    72            //return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), AUTHORITIES);
    73            return new MyAuthenticationToken(authentication.getName(), authentication.getCredentials(), AUTHORITIES, myUser);
    74             
    75        }catch(AuthenticationServiceException e){
    76            throw e;
    77        }catch(Throwable e){
    78            throw new AuthenticationServiceException("An error/exception occurs during the authentication. Please, try again.", e);
    79            //Exception ex = new DisabledException(msg);
    80            //Exception ex = new CredentialException(msg);
    81            //Exception ex = new CredentialExpiredException(msg);
    82            //Exception ex = new BadCredentialsException(msg);
    83            //Exception ex = new BadCredentialsException(msg);
    84             
    85        }
    86    }
    87     
    88     
    89    @Override
    90    public boolean supports(Class<? extends Object> authentication){
    91        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)
    92                && authentication.equals(UsernamePasswordAuthenticationToken.class);
    93    }
    94}

  • Simple code for the MyUser class:
    01package com.ho.spring3.security.test1.util;
    02 
    03import java.io.Serializable;
    04 
    05/**
    06 * This class is used in the security and represents the User informations stored in the authentication mechanism.
    07 *
    08 * @author Huseyin OZVEREN
    09 *
    10 */
    11public class MyUser implements Serializable{
    12 
    13    // ------------------------ PRIVATE ATTRIBUTES
    14    private String fullName = null;
    15    private String email = null;
    16     
    17     
    18    // ------------------------ CONSTRUCTOR
    19    public MyUser(String fullName, String email){
    20        this.fullName = fullName;
    21        this.email = email;
    22    }
    23 
    24    // ------------------------ GET/SET TERS
    25    public String getFullName() {
    26        return fullName;
    27    }
    28 
    29 
    30    public void setFullName(String fullName) {
    31        this.fullName = fullName;
    32    }
    33 
    34    public String getEmail() {
    35        return email;
    36    }
    37 
    38    public void setEmail(String email) {
    39        this.email = email;
    40    }  
    41}

  • Last, we have override the Spring token UsernamePasswordAuthenticationToken by our token MyAuthenticationToken used in the “AuthenticationProvider” component MyAuthenticationProvider:
    1return new MyAuthenticationToken(authentication.getName(), authentication.getCredentials(), AUTHORITIES, myUser);

    … so, here, the source of our new token MyAuthenticationToken which extends the standard Spring class “UsernamePasswordAuthenticationToken” to allow the storing of additional data/details attached to authenticated user (for example, fullName, email..):

    01package com.ho.spring3.security.test1.util;
    02 
    03import java.util.Collection;
    04 
    05import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    06import org.springframework.security.core.GrantedAuthority;
    07 
    08/**
    09 * This component extends the standard Spring class "UsernamePasswordAuthenticationToken" to allow the storing of additional data/details
    10 * attached to authenticated user (for example, fullName, email..).
    11 *
    12 * @author Huseyin OZVEREN
    13 */
    14public class MyAuthenticationToken extends UsernamePasswordAuthenticationToken{
    15 
    16    // ----------------------------------- PRIVATE ATTRIBUTES
    17    private MyUser myUser = null;
    18     
    19    // ----------------------------------- CONSTRUCTOR
    20    public MyAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities, MyUser myUser){
    21        super(principal, credentials, authorities);
    22        this.myUser = myUser;
    23    }
    24 
    25    // ----------------------------------- GET/SET TERS
    26    public MyUser getMyUser() {
    27        return myUser;
    28    }
    29 
    30    public void setMyUser(MyUser myUser) {
    31        this.myUser = myUser;
    32    }
    33             
    34}

  • We have created a utility class MyRoleUtil using SPRING to retrieve the properties and roles of a authenticated user from the Spring Security Context:
    01package com.ho.spring3.security.test1.util;
    02 
    03import java.util.ArrayList;
    04import java.util.Collection;
    05 
    06import org.springframework.security.core.Authentication;
    07import org.springframework.security.core.GrantedAuthority;
    08import org.springframework.security.core.context.SecurityContext;
    09import org.springframework.security.core.context.SecurityContextHolder;
    10 
    11/**
    12 * <p>
    13 *      Utility class using SPRING to retrieve the properties and roles of a authenticated user.
    14 * </p>
    15 *
    16 * @author Huseyin OZVEREN
    17 *
    18 */
    19public class MyRoleUtil {
    20 
    21    // --------------------------------------------------------------------------------------------------- FONCTIONS PUBLIQUES
    22 
    23    /**
    24     * return true if at least one role match
    25     */
    26    public boolean loggedUserHasRole(String ... roles) {
    27        SecurityContext context = SecurityContextHolder.getContext();
    28        //GrantedAuthority[] authorities = context.getAuthentication().getAuthorities();
    29        Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) context.getAuthentication().getAuthorities();
    30        if (authorities != null && authorities.size()>0) {
    31            for (GrantedAuthority authority : authorities) {
    32                for (String role : roles) {
    33                    if (authority.getAuthority().matches(role)) {
    34                        return true;
    35                    }
    36                }
    37            }
    38        }
    39        return false;
    40    }
    41 
    42     
    43    /**
    44     * Return the username/login of the user
    45     */
    46    public String getLoggedUserName() {
    47        SecurityContext context = SecurityContextHolder.getContext();
    48        Authentication authentication = context.getAuthentication();
    49         
    50        String userName = null;
    51        if(authentication.getPrincipal() instanceof org.springframework.security.core.userdetails.User){
    52            org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
    53            userName = user.getUsername();
    54        }else{
    55            userName = (String) authentication.getPrincipal();
    56            authentication.getName();
    57            authentication.getPrincipal();
    58            authentication.getCredentials();
    59            authentication.isAuthenticated();
    60            authentication.getDetails();
    61        }
    62        return userName;
    63    }
    64 
    65    /**
    66     * Return the list of user roles
    67     */
    68    public Collection<String> getLoggedUserRolesNames() {
    69        SecurityContext context = SecurityContextHolder.getContext();
    70        //GrantedAuthority[] authorities = context.getAuthentication().getAuthorities();
    71        Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) context.getAuthentication().getAuthorities();
    72        Collection<String> roles = new ArrayList<String>();
    73        if (authorities != null && authorities.size()>0) {
    74            for (GrantedAuthority authority : authorities) {
    75                roles.add(authority.getAuthority());
    76            }
    77        }
    78        return roles;
    79    }
    80 
    81 
    82    /**
    83     * Return the informations/details relatives to the authenticated user
    84     * @return
    85     */
    86    public MyUser getCurrentMyUser(){
    87        SecurityContext context = SecurityContextHolder.getContext();
    88        Authentication authentication = context.getAuthentication();
    89        MyUser user = null;
    90        if(authentication instanceof MyAuthenticationToken){
    91            user = ((MyAuthenticationToken)authentication).getMyUser();
    92        }
    93         
    94        return user;
    95    }
    96}



Demo and Tests
1. Access URL “http://localhost:8080/Spring3Security/index.jsp“, the index page will redirect to the securized page “/loginSecure.do?action=handleLogin”. So Spring will redirect your request to the custom login form:

URL : http://localhost:8080/Spring3Security/login.jsp

2. If username/password is wrong (login != password), authentication failed, display custom error messages:

URL : http://localhost:8080/Spring3Security/login.jsp?error=true

3. If username/password is correct (login == password), authentication success, display requested page. The welcome page contains several informations concerning the authenticated user like roles from Spring Security context, or user’s personnal informations (in our example, fullname, email) from the overridden token. These datas are accessible via our utility class MyRoleUtil.

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage0

4. If you click on the page1 link:

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage1

5. If you click on the page2 link:

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage2

6. If you click on the logout link (http://localhost:8080/Spring3Security/loginSecure.do?action=handleLogout) which will be redirected to the login page:

URL : http://localhost:8080/Spring3Security/login.jsp



Advanced Demo and Tests: concurrency access

1. Open a first window and access URL “http://localhost:8080/Spring3Security/index.jsp“, the index page will redirect to the securized page “/loginSecure.do?action=handleLogin”. So Spring will redirect your request to the custom login form:

URL : http://localhost:8080/Spring3Security/login.jsp

2. IN WINDOW n°1: Fill in correct username/password (login == password == mylogin), authentication success, display requested page (welcome page):

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage0

3. Open a second window with New Session and access URL “http://localhost:8080/Spring3Security/index.jsp“, the index page will redirect to the securized page “/loginSecure.do?action=handleLogin”. So Spring will redirect your request to the custom login form:

URL : http://localhost:8080/Spring3Security/login.jsp

4. IN WINDOW n°2: Fill in correct username/password (login == password == mylogin), authentication success, display requested page (welcome page):

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage0

5. IN WINDOW n°2: If you click on the page1 link:

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage1

6. IN WINDOW n°1: If you click on the page1 link, SPRING will block your action to an error page with the message “This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).”, because we have set a limitation of simultaneous connections with the same identifier to “1”.

URL : http://localhost:8080/Spring3Security/myOwnController.do?action=handlePage1

Source: Spring3Security

That’s all!!!

Best regards,

Huseyin OZVEREN

1 thought on “Java/Spring3: Spring Security, authentication provider, override authentication token”

Leave a Reply to Carlos Cancel reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

Related Post