Simple Spring and JPA with Hibernate tutorial. Part 3: Simple Security
Spring security In this blog post we continue adding functionality to our Spring and JPA application. We will be adding basic security using Spring Security (formerly known as Acegi Security). However to achieve this we’ll also look at some new elements:
- Spring’s ContextLoaderListener and hierarchical contexts
- Entity relationships in JPA
- Multiple Spring xml files and their organization
- Maven’s quirks with transitive dependencies
This example builds on top of the code that was written for part 2, but we will rearrange several pieces. Let’s start by looking at the pom.xml where we’ve added two new dependecies:
- We add a property for the Spring Security version, just like we did for Spring. In version 3, Spring and Spring Security have different release schedules and versions. Both projects should have their versions synchronized by version 4.
- We add 3 Spring Security dependencies:
spring-security-core
provides the basic classes used by the frameworkspring-security-config
provides the elements needed to configure the framework, for example the xsd files used in the xml configuration.spring-security-web
provides the hooks to provide URL based security.- Spring security requires the
spring-aop
dependency. However, since the Spring and Spring Security versions are not in sync, it depends on a version ofspring-aop
that is incompatible with Spring 3.2.4 (the one we’re using). To solve this, we add an explicit dependency to the right version. When a project depends on two different versions of the same library, Maven will pick the one closer to the root. What we have done is declared the dependency at the very root of the project, to ensure our version is used. Luckily our version ofspring-aop
is compatible with the Spring Security version we’re using.
Now let’s look the at the web.xml, where we have a few new elements (src/main/webapp/WEB-INF/web.xml
):
- In this new application we introduce another way of configuring the Spring container, through a listener. The listener will create a parent context. We will also create a child context, instantiated by the DispatcherServlet. The child context will have access to the beans of the parent context, but not the other way around.
- The location of the xml file to instantiate the parent context is defined with a context parameter named
contextConfigLocation
. We will look at this file in detail. In this parameter you can configure more than one file, but for now - To actually secure the application, we add a new filter. In the spring world, the MVC framework and the security framework are separate mechanisms.
- The security filter is normally applied to the whole application, with a mapping of
/*
. We can later tune this apply rules to only some URLs.
Let’s start looking at the spring-context.xml, where we configure the parent spring context (src/main/webapp/WEB-INF/spring-context.xml
):
- In Spring, it is good practice to separate configuration files based on their purpose. Back in the day before annotations, these files could grow enormously. Nowadays they’re shorter, but it still helps to keep them separate. The import element will include the contexts of another file, and the corresponding beans will be created in the current context. We will examine the spring-security.xml file later on.
- We have copied the component-scan element into this new file. However we’re excluding beans that have
@Controller
annotation. Those beans will be registered by the Spring MVC configuration file. - We have moved all of the JPA configuration (from
tx:annotation-driven
to the end of the file) into the main Spring xml file. I could also be possible to create a new file to keep all database/JPA related bean configuration.
Let’s look at the security configuration (src/main/webapp/WEB-INF/spring-security.xml
):
- The http element provides securing of URLs (Spring Security also allows securing Java methods, but we’ll look at that in another post). Of notice here is the attribute
use-expressions="true"
, which allows using Spring EL instead of simply listing allowed roles. - We are securing a single URL, which covers the whole application, and allows access to any use that is successfully authenticated. Multiple urls can be added to fine tune access control, and will be evaluated in the order in which they are declared.
- The form-login element provides a basic form based authentication. You can later customized the login page to fit the style of your application. Spring Security provides other ways of authentication, including HTTP BasicAuthentication, and several Single Sign On schemes.
- The
authentication-manager
is the bean that will verify the user credentials as well as provide the authorities or roles a user has. We will look at our implementation of the user service later.
Finally, we look at (the now much shorter) spring-context.xml
. We’ve removed all of the elements not related to Spring MVC.
- Of note in this file is the
context:include-filter
which will only load controllers. Remember that this file is loaded as a subcontext, contrary to the spring-security.xml which is loaded in the main or parent context.
We have also two new entities, Role
and Employee
. We’ll look at Role
first (src/main/java/test/model/Role.java
):
This is a very basic entity, almost the same as the Person entity we had created in the first part. The most significant difference is that we’re missing the @GeneratedValue
annotation in the id field. This means that if we want to insert new roles, we need to manually specify an id.
Next we’ll look at the Employee
entity (src/main/java/test/model/Employee.java
):
This is also a very basic entity, except for the addition of a collection field.
The roles
field will contain a list of roles assigned to the employee.
This is indicated with the @ManyToMany
annotation.
In order to map the many-to-many relationship (many employees map to many roles), we need a join table.
In this case the default join table will be called Employee_Role
, and it will have two columns Employee_id
and roles_id
.
The default can be changed by adding the @JoinTable
annotation, which allows us to define the table name, as well as the column names.
After seeing the new entities, we can get a better idea of how they will look by looking at the data we’re inserting into the database:
Let’s look at the data we use to seed the database (src/main/resources/import.sql
):
In this file we’re now also inserting two employees, and the corresponding roles for each employee. Since the id of the employee is not know (we could assume they would be 1 and 2, but there’s no guarantee), we use a SELECT
to find the correct Id.
Now let’s look at the employee service and DAO. This is the only part that requires some significant Java code. Everything else has been XML and some annotations in a POJO. This shows how much coding you’re saving by using such a framework.
Let’s look at the EmployeeDAO
first (`src/main/java/test/dao/impl/EmployeeDAO.java):
- This class has only one method. In this method we’re using the
TypedQuery
, which allows our query results to already have the correct type, and save us some potentially dangerous type casting. - In this query we’re using a parameter with a named placeholder
:userName
. We then pass the user name we’re looking for with the methodsetParameter
. - The
getSingleResult
method will return a single Employee. If no employee is found, a runtime exception ofNoResultException
type will be thrown.
Finally, we look a the user service (src/main/java/test/service/impl/UserService.java
);
- The UserService implements the Spring Security interface UserDetailsService. At this point it does not implement any our interfaces, but eventually will, once we add extra functionality that requires finding users.
- The employee is found using our DAO.
- If the employee is not found, a Spring Security exception of type UsernameNotFoundException is thrown. In this section we could also catch the RuntimeExceptions coming from the DAO, in order to manipulate the errors displayed by Spring Security. If we don’t, Spring Security would display the message of the excpetion, which might not be the most user friendly message (for example “No entity found for query” when user is not found).
- The actual return value of the method is loadUserByUsername is a Spring Security interface, UserDetails. We use a private method to create the right type of object from the Employee object.
- In our private method, each Role object becomes a SimpleGrantedAuthority, another Spring Security object.
- Finally we create a User object, based on the information found in the Employee object and the list of GrantedAuthority.
We can then compile and run our small application with:
mvn tomcat:run
You can try to run the service but will be greeted with a login screen: http://localhost:8080/spring-hib-jpa/view.html :
You can then try to enter a username an password, and unless it matches what we inserted in database, you’ll get an error:
If you enter a valid username and password you will see main screen of our little test application:
This is a very basic example, but we’ve set up security on our application. And while there was plenty of XML configuration, there were no code changes. This separation of business logic and security logic should allow for a better and easier to maintain application.
Source Code
As always the code is available for you to downloand and play with. Clone it from it from github:
git clone https://github.com/aolarte/tutorials.git
The finished code is contained in directory spring3_simple_security
.
Simple Spring and JPA with Hibernate tutorial series:
- Part 1: The basics
- Part 2: Forms and persisting entities
- Part 3: Simple security
Comments