Spring Security Simple Authentication

In this post, we will create a simple application, that displays Spring Security form-based authentication. The user is prompted to give his credentials. If they are correct, he enters to the dashboard. If they are wrong, he gets an error message. Dashboard is accessible only by authenticated users. 

The full github repository can be found here:  SpringSecuritySimpleAuthentication

Technologies Used

  • Spring MVC
  • Spring Security
  • Hibernate
  • MySQL
  • Maven
  • Jsp , Jstl

Database

We need one table in our database which will contain the users. We create only a username and a password field and perform our first insert. The password value equals with ‘123456’ but is encrypted using the bcrypt function, in order to comply with our security configuration that we will setup later.

queries.sql

CREATE TABLE user
(
  user_id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT ,
  username VARCHAR(400) NOT NULL,
  password VARCHAR(400) NOT NULL
);

INSERT INTO user (username, password) VALUES ("testUser", "$2a$10$04TVADrR6/SPLBjsK0N30.Jf5fNjBugSACeGv1S69dZALR7lSov0y");

 

Implementation

The first step is to add Spring Security to the Maven configuration. 

pom.xml : 

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>

 

Next the must initialize the Spring Security Filter Chain, which will enable the security implementation. In web.xml file we configure the filter, and the location of the spring-security.xml file.

web.xml :

<!--Spring Security Filter-->
<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>

 

Spring Security Configuration

Now Spring Security is activated, and we need to configure it. We will do that in another xml file, which we will name spring-security.xml. We have already setup the file’s location in the web.xml.

In this file we configure the following :

  • The package where our functionality that needs to be secured is.
  • The urls that will be secured.
  • The roles/authorities/permissions.
  • The authorization failure url.
  • The login page url.
  • The default target url, in which the authorized users will be redirected after the successfull login.
  • The logout success url.
  • The names of the username and password parameters that Spring Security expects.
  • The authentication manager.
  • The User Details Service which we inject into the authentication provider.
  • The encryption type that will be used for the password.

spring-security.xml :

<?xml version="1.0" encoding="UTF-8"?>
<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"
             xmlns:context="http://www.springframework.org/schema/context"
             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.2.xsd
                   http://www.springframework.org/schema/context
                   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

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

    <http auto-config="true" use-expressions="true">

        <intercept-url pattern="/dashboard**" access="hasAuthority('USER')" />

        <form-login
            login-page="/login"
            default-target-url="/dashboard"
            authentication-failure-url="/login?error"
            username-parameter="username"
            password-parameter="password" />

        <logout logout-success-url="/login?logout" />

    </http>

    <authentication-manager>
    <authentication-provider user-service-ref="userDetailsService" >
      <password-encoder hash="bcrypt" />
    </authentication-provider>
  </authentication-manager>

</beans:beans>

 

User Details Service

The last but also very important step is to implement the User Details Service interface which we have already injected into the Authentication Provider. We override the loadUserByUsername method and inside it we get the user from the database using the username, collect the authorities, assign them to the user object and build the spring security User object.

CustomUserDetailsService.java :

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    /**Method that returns a UserDetails object
     *
     * @param username
     * @return
     * @throws org.springframework.security.core.userdetails.UsernameNotFoundException
     */
    @Transactional(readOnly = true)
    @Override
    public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

        //get user from the database, via Hibernate
        com.antogeo.entity.User user = userDao.getUserByUsername(username);

        //Collect User authorities
        List<GrantedAuthority> authorities = buildUserAuthority(user);

        //Build Spring Security User
        User springSecurityUser = buildUserForAuthentication(user, authorities);
        return springSecurityUser;
    }

    /**Build the Spring Security User.
     *
     * @param user
     * @param authorities
     * @return
     */
    private User buildUserForAuthentication(com.antogeo.entity.User user, List<GrantedAuthority> authorities) {

        return new User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(com.antogeo.entity.User user) {

        Set<GrantedAuthority> authoritiesSet = new HashSet<GrantedAuthority>();

        //Use one role for all
        authoritiesSet.add(new SimpleGrantedAuthority("USER"));

        //Transform the Set into List
        List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(authoritiesSet);
        return result;
    }

    public UserDao getUserDao() {return userDao;}

    public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}

 

The Login Page

The only action we have to make in the login.jsp page, is to set the post url to “/j_spring_security_check”. By doing this, the form post request will be sent through the security filter chain and end up to the default-target-url or the authentication-failure-url based on the result.

login.jsp :

<c:url var="post_url"  value="/j_spring_security_check" />

<form:form  action ="${post_url}" method='POST' commandName="loginForm" cssClass="form-signin">
    <h2 class="form-signin-heading">Welcome!</h2>
    <label for="inputUsername" class="sr-only">Username</label>
    <form:input path="username" id="inputUsername" placeholder="Username" size="30" cssClass="form-control" />
    <form:errors path="username" cssClass="error"/>

    <label for="inputPassword" class="sr-only">Password</label>
    <form:password path="password" id="inputPassword" placeholder="Password" size="30" cssClass="form-control"/>
    <form:errors path="password" cssClass="error"/>

    <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
</form:form>

 

Use Case

Let’s run and try the example now. We use the tomcat’s url following by our apps name and the login page opens. In the login form, we try to enter the app with wrong credentials and we see the error message.

After that we use the correct username and password and click login.

  

We get redirected to the Dashboard page. There we can see our username which is displayed using the Principal object and the logout button.

 

By clicking the logout button our session gets invalidated and we are get redirected back to the login page with a message.

 

Installation and Run

  • Run the database/queries.sql  queries to your database.
  • Add your database credentials to resources/db.properties file.
  • Build the project using mvn clean install
  • Run the application using tomcat

Test Credentials

Username Password
testUser 123456