, , , ,

Spring Boot Web Application, Part 6 – Spring Security with DAO Authentication Provider

This is part 6 of the tutorial series for building a web application using Spring Boot. In this post we look at adding a DAO Authentication provider for Spring Security.

We started off with the first part by creating our Spring project using the Spring Initializr. In part 2, we rendered a web page using Thymeleaf and Spring MVC. This was followed by part 3 where we looked at setting up Spring Data JPA for database persistence. Part 4 was all about consolidating everything to provide a working Spring Boot MVC Web Application capable of performing CRUD operations.

In the previous part 5 of this series, we configured a basic in-memory authentication provider. It’s a good starting point to learn Spring Security, but as I mentioned there, it’s not for enterprise applications. A production-quality implementation would likely use the DAO authentication provider.

In this part of the series, I will discuss Spring Security with the DAO authentication provider to secure our Spring Boot Web application. We will implement both authentication and role-based authorization with credentials stored in the H2 database. For persistence, we will use the Spring Data JPA implementation of the repository pattern, that I covered in part 3. Although there are several Spring Data JPA implementations, Hibernate is by far the most popular.

As the Spring Data JPA dependency is included in our Maven POM, Hibernate gets pulled in and configured with sensible default properties via Spring Boot.

This post builds upon 5 previous posts. If you’re not familiar with all the content around Spring, I suggest you to go through this series from the start.

JPA Entities

Our application already has a Product JPA entity. We’ll add two more entities, User and Role. Following the SOLID design principle’sprogram to interface ” principle, we will start by writing an interface followed with an abstract class for our entities.

DomainObject.java

AbstractDomainClass.java

The entity classes are as follows.

User.java

Role.java

The User and Role JPA entities are part of the many-to-many relationship. Also, in Line 15 of the User class, notice that the password field is marked as @Transient.

That’s because we don’t want to store the password in text form.

Instead, we will store the encrypted form of the password.

JPA Repositories

Spring Data JPA provides the CRUD Repository feature. Using it, we just define the repository interfaces for our User and Role entities to extend CrudRepository.

The Spring Data JPA repositories for the User and Role entities are as follows.

UserRepository.java

RoleRepository.java

By extending CrudRepository, both the repositories inherit several methods for working with entity persistence, including methods for saving, deleting, and finding entities. Spring Data JPA uses generics and reflection to generate the concrete implementations of both the interfaces.

Spring Data JPA Services

We can now create the services, that will use Spring Data JPA to perform CRUD operations on the User and Role entities.

Of course, we will follow the Interface Segregation principle to maintain loose coupling. It’s always best to “program to interface”, especially when leveraging the benefits of Spring’s dependency injection.

So, let’s start with the service interfaces.

CRUDService.java

UserService.java

RoleService.java

Both RoleService and UserService extends CRUDService that defines the basic CRUD operations on entities. UserService, with the additional findByUsername() method is a more specialized service interface for CRUD operations on User.

We have made the service interfaces generic to mask our service implementations using the Façade design pattern. The implementations can be Spring Data JPA with repository, DAO, or Map patterns, or even plain JDBC, or some external Web service. The client code does not need not to be aware of the implementation. By using interfaces, we are able to leverage multiple concrete implementations of the services.

We’ll write the service implementation classes using the Spring Data JPA repository pattern.

UserServiceImpl.java

In this class, we auto-wired in UserRepository and EncryptionService. Going ahead, we will create EncryptionService using the Jasypt library to add encryption capabilities for storing user passwords. The overridden methods of this class use the UserRepository we created to perform CRUD operations on User.

The RoleServiceImpl provides a similar implementation for RoleService.

RoleServiceImpl.java

Free Spring TutorialPassword Encryption Service

The Jasypt library provides an implementation for unidirectional encryption. We will use Jasypt to encrypt a password before storing it to the database. For authentication, we will provide Jasypt the received password. Under the hood, Jasypt will encrypt the received password and compare it to the stored one.

Let’s add the Jasypt dependency to our Maven POM.

Note: The latest available Jasypt 1.9.2 targets Spring Security 3. But even for Spring Security 4 that we are using, Jasypt doesn’t have compatibility issues.

With Jasypt pulled in, we will write a bean for StrongPasswordEncryptor of Jasypt – a utility class for easily performing high-strength password encryption and checking. The configuration class, CommonBeanConfig is this.

CommonBeanConfig.java

Our generic EncryptionService interface will define two methods to encrypt and compare passwords.

EncryptionService.java

The implementation class is this.

EncryptionServiceImpl.java

In this implementation class, we autowired the StrongPasswordEncryptor bean. In Line 18, the encryptPassword() method encrypts the password passed to it. In Line 22, the checkPassword() method returns a boolean result of the password comparison.

User Details Service Implementation

Spring Security provides a UserDetailsService interface to lookup the username, password and GrantedAuthorities for any given user. This interface provides only one method, loadUserByUsername(). This method returns an implementation of Spring Security’s UserDetails interface that provides core user information.

The UserDetails implementation of our application is this.

UserDetailsImpl.java

In this class, we have defined the fields of our data model and their corresponding setter methods. The SimpleGrantedAuthority we set on Line 16 is a Spring Security implementation of an authority that we will convert from our role. Think of an authority as being a “permission” or a “right” typically expressed as strings.

We need to provide an implementation of the loadUserByUsername() method of UserDetailsService. But the challenge is that the findByUsername() method of our UserService returns a User entity, while Spring Security expects a UserDetails object from the loadUserByUsername() method.

We will create a converter for this to convert User to UserDetails implementation.

UserToUserDetails.java

This class implements the Spring Core Coverter  interface and overrides the convert() method that accepts a User object to convert. In Line 16, the code instantiates a UserDetailsImpl object, and from Line 19 – Line 26, the code initializes the UserDetailsImpl object with data from User.

With the converter ready, it’s now easy to implement the UserDetailsService interface. The implementation class is this.

Here is our implemention.

UserDetailsServiceImpl.java

In the UserDetailsServiceImpl class, we auto wired in UserService and Converter. In Line 31, the lone overridden method loadUserByUsername() converts a User to UserDetails by calling the convert() method of Converter.

Security Configuration

The current security configuration class, SpringSecConfig extends WebSecurityConfigurerAdapter to configure two things. An authentication provider and the application routes to protect. Our route configuration will remain the same. However, we need to register the DAO authentication provider for use with Spring Security.

We will start by setting up a password encoder to encode passwords present in the UserDetails object returned by the configured UserDetailsService. We will define a new bean for Spring Security’s PasswordEncoder that takes in the StrongPassordEncryptor bean.

Remember that we created StrongPassordEncryptor earlier in the CommonBeanConfig Spring configuration class?

Next, we will set up the DAO authentication provider, like this.

In this code, we passed the previously configured PasswordEncoder and UserDetailsService to daoAuthenticationProvider(). The PasswordEncoder is going to use the Jasypt library for encoding the password and verifying that the passwords match. The UserDetailsService will fetch the User object from the database and hand over to Spring Security as a UserDetails object. In the method, we instantiated the DaoAuthenticationProvider and initialized it with the PasswordEncoder and UserDetailsService implementations.

Next, we need to auto wire in the AuthenticationProvider as we want the Spring Context to manage it.

We will also auto wire in the AuthenticationManagerBuilder. Spring Security will use this to set up the AuthenticationProvider.

The complete SpringSecConfig class is this.

SpringSecConfig.java

Application Bootstrapping with Seed Data

For seed data of the application, we have an ApplicationListener implementation class that gets called upon the ContextRefresedEvent on startup. In this class, we will use Spring to inject the UserRepository and RoleRepository Spring Data JPA repositories for our use. We will create two User and two Role entities and save them to the database when the application starts. The code of this class is this.

SpringJpaBootstrap.java

This class in addition to loading product data, invokes the following methods to load users and roles at startup:

  • loadUsers(): Stores two User entities. One with “user” and the other with “admin” as both the user name and password.
  • loadRoles(): Stores two Role entities for the “USER” and “ADMIN” roles.
  • assignUsersToUserRole(): Assigns the User with username “user” to the “USER” role.
  • assignUsersToAdminRole(): Assigns the User with username “admin” to the “ADMIN” role.

Free Spring TutorialThymeleaf Extras module

In the previous part 5 of this series, I discussed the Thymeleaf “extras” integration module to integrate Spring Security in our Thymeleaf templates. Things will largely remain unchanged in this presentation layer, except for two instances.
Currently, both USER and ROLE are being referred from the presentation layer code as ROLE_USER and ROLE_ADMIN. This was required because we relied on Spring Security’s in-memory authentication provider for managing our users and roles, and Spring Security’s internal feature maps a configured role to the role name prefixed with ROLE_. With the DAO authentication provider, our roles are mapped to authorities as it is (We did this in in the UserToUserDetails converter), and we can refer them directly from code as USER and ADMIN.

The second change is brought in by GrantedAuthority used by the Spring Security UserDetails interface. If you recall, we mapped our Role implementation to SimpleGrantedAuthority in the UserToUserDetails converter.

Therefore, in the Thymeleaf templates, we need to change the hasRole() and hasAnyRole() authorization expressions to hasAuthority() and hasAnyAuthorities().

The affected templates are header.html and products.html.

header.html

products.html

Running the Application

Our application is configured to run the H2 database console, which I have explained here. So, when you run the application, you’ll now be able to access the H2 database console at http://localhost:8080/console. You can use it to view the initial authentication-related data loaded by the SpringJpaBootstrap class.
USER Table for Spring Security
Role Table for Spring Security

This is how the home page appears to authenticated users with USER and ADMIN roles.

Home Page View for USER Role
Home Page View for ADMIN Role

With our Security configuration, this is how the product listing page appears to users with different roles.

Home Page View for Anonymous
Home Page View for USER Role
Home Page View for ADMIN Role

Summary

Spring Security has a large scope, and what we configured is only a small part of it. Spring Security supports XML-based and annotation-based finer level security configurations. With Spring Security, we can secure websites down to specific URLs, assign roles to URL, and even roles to different HTTP actions – a security configuration typically employed in RESTful APIs.

What makes Spring Security great is that you can easily hook in another security provider. If you noticed, we hardly made any change in the presentation and business logic layers while transitioning from the earlier basic in-memory authentication provider to the DAO provider. We could also use LDAP, Single Sign-On (SSO), OpenID, and OAuth 2.0 providers. It all depends on the requirements of your application.

Get the Source!

The full source code for this example is available here on GitHub.

Share

You May Also Like

31 comments on “Spring Boot Web Application, Part 6 – Spring Security with DAO Authentication Provider

  1. JT thank you for your post, could you post the link for source? I may missing something here, my UserService isn’t autowiring.

  2. You made my day

  3. Great tutorial!!!

  4. Owesome Post.

    I new on spring boot and this web have a lot of information, well im following your tutorial, but i just can make it works ones. Now when i try to start i see this:

    Whitelabel Error Page

    This application has no explicit mapping for /error, so you are seeing this as a fallback.
    Tue Mar 14 21:48:53 GMT-05:00 2017
    There was an unexpected error (type=Internal Server Error, status=500).
    No message available

    What do you think could cause this issue.

    Have a nice day.

  5. Im new on this but i can solve this on application.properties i put nex:

    spring.mvc.view.prefix=/WEB-INF/jsp/
    spring.mvc.view.suffix=.jsp

    so, it works

  6. how to we remove the in-memory DB and use Postgresql for example?

    • It’s just a matter of wiring in a different data source. I have examples on this site for most major databases.

  7. Hi, congradulatios by post! When running, the respective error:

    Description:

    Parameter 0 of method setUserService in com.beerapp.bootstrap.SpringJpaBootstrap required a bean of type ‘com.beerapp.service.UserService’ that could not be found.

    Action:

    Consider defining a bean of type ‘com.beerapp.service.UserService’ in your configuration.

    • Are you having the UserService interface inside com.beerapp.service.?

      Also, have you tried running the source code on github to replicate the issue?

      • Are you having the UserService interface inside com.beerapp.service.?

        yes

        Also, have you tried running the source code on github to replicate the issue?

        yes, dont not problem. But following the post, there is no implementation of the mapservices package, but no git yes.
        I’ll add the same.

        • I have the similar problem after adding in the remaining packages that were not shown in the tutorial. I do not have any problems with the copy from git though. However, I’ll like to know how do you solve it?

          Hope to hear from anyone who have this issue too. Thanks

          • I had the same issue.

            I didn’t added the remaining packages located on github, just deleting the annotation @Profile(…) did the trick.

            (I didn’t understand what it did anyway)

      • To those of you having this problem, the fix is to use the profile ‘springdatajpa’.
        In order to do this, you’ll have to make the edit in application.properties file. Add this line:
        spring.profiles.active=springdatajpa

        if you notice in the code on githib, he has other profiles available to use such as ‘map’ and ‘jpadao’

  8. Hi JT, thank you very much for the great posts with clear explanations to help newcomers like to understand the idea of the implementation details.

    For the JPA entities User.java and Role.java, are we expecting only 1 table “USER_ROLE” generated as the results of the ManyToMany annotations defined in both the entities, or 2 separate tables of “USER_ROLES” and “ROLE_USERS”?

    After testing it out, my testdb contains 2 separate tables of “USER_ROLES” and “ROLE_USERS” with only 1 of the tables having records created.

    Thanks again.

    • I was also scratching my head over this as I am new to JPA. ROLE_USER table seems to be redundant.
      You can simply remove @JoinTable annotation from Role class and modify @ManyToMany(fetch = FetchType.EAGER) annotation to make it looks like this @ManyToMany(fetch = FetchType.EAGER, mappedBy = “roles”).
      Thanks to removing @JoinTable, ROLE_USER table will not be created and adding mapped=”roles” tells that the relation is handled by ‘roles’ list in User class. User class does not need to be modified at all.
      It seems to work for me 🙂

  9. Thank you so much for this amazing tutorial. I’ve used Spring for 5 years now. I can’t believe how much configuration headache Spring Boot removes. And your tutorial was very clean and precise. It really took all the headache away from having to learn another framework. One of the best I’ve seen.

    • Thanks Bob!!

  10. Hi JT..

    therese 1 thing i still dont quite understand..

    in user repository there 1 custom method findByUsername

    what class that implement it? how can it work when no class implement it..

    thanks before

    • Spring Data JPA provides the implementation for you at run time.

      • I see so spring data jpa already have implement class for findbyusername..

        If i want to make new method like findByUsernameAndPassword.. how should i do? Should i implementing it myself?

        Thanks again jt..

  11. Thanks for the Article – Can you please give a tutorial for OAuth 2.0 as well.

  12. I have a question that why in class SpringSecConfig , you don’t need @EnableWebSecurity annotation?, and when we have to add that annotation to our security configuration class.

  13. Hi JT, great tutorial!
    Is it considered good practice to call an objects domain methods from within a thymeleaf template?

    For example, suppose I have a user controller that binds all users to the model returned to the view. In that thymeleaf view, I would like to iterate over all users and for each user list their role(s). Is it ok to call the user.getRoles() method in thymeleaf, or would it be considered coupling the view too tightly to the controller? Is there a better or best practice way?

    Cheers,
    Brad

    • Yes – that is fine. On larger applications, its common to expose DTOs to the view layer. But in smaller applications, its fine to use the domain object.

      • Thanks for the reply!

        I am also a bit confused as to where the business logic belongs in the structure of MVC. For example, if I have a method that should be called every time a product is updated that manipulates that product in some way, where should that method be located? Also in the objects entity domain class?

        Some sources I have read state that the business logic should be in the domain classes, others say in the Service layer. I am having a difficult time distinguishing the difference…

        Thanks,
        Brad

        • Service layer. Domain objects are data structures.

  14. Why Impl? there is no point of creating an interface for a service which has only a single known implementation.

    • Its always a best practice to code against interface instead of concrete implementation. Your client code remains untouched if you decide for another implementation tomorrow.

Leave a Reply