Even though JSPs have fallen out of fashion lately, they are still a core part of many enterprise infrastructures. In this tutorial, we’ll show you how to secure them using the excellent Spring Security suite and Stormpath’s Spring Boot integration for user management.
JSPs and Spring Boot
We’ll start by serving up a simple JSP homepage using Spring Boot. The most basic JSP is plain HTML with a variable or two thrown in.
<!doctype html> <html> <body> <p>Hello, <%="World"%>!</p> </body> </html>
If rendered correctly we should see ‘Hello, World!’ when loading the code. To do this we first put it into the src/main/webapp/WEB-INF/jsp
directory.
Image may be NSFW.
Clik here to view.
Then inside of application.properties
we need to specify where our JSP files reside.
spring.mvc.view.prefix: /WEB-INF/jsp/ spring.mvc.view.suffix: .jsp
Now create a basic Application.java
.
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
And then create an even more basic Request.java
.
@Controller public class Request { @GetMapping("/") String home() { return "home"; } }
Mapping a forward slash to home
really means the file home.jsp
with the path defined in our application.properties.
The last thing we need is a pom.xml
. Here we include the Spring Boot Starter Parent (so we don’t have to specify dependency versions), the Spring Boot Maven Plugin (so we can run our app directly), the Tomcat Jasper (to serve our JSPs) and the Spring Boot Starter Web (for route controlling).
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.stormpath.sample</groupId> <artifactId>stormpath-security</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Now when we run with mvn spring-boot:run
and visit localhost:8080
we should see our hello world message.
Image may be NSFW.
Clik here to view.
Add Security
Spring Security is divided into two parts, authentication, and authorization. The first ensures your user identity while the second handles what the user can and can’t do.
To authenticate we are going to use Stormpath’s Java integration which is as simple as adding http.apply(stormpath())
to a basic security adapter.
@Configuration public class Security extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.apply(stormpath()); } }
We also need to add our Stormpath application details to our application.properties
.
stormpath.application.href = <your app href> stormpath.client.apiKey.id = <your api key id> stormpath.client.apiKey.secret = <your api key secret>
Note: For security reasons you should not store your Stormpath keys inside of Java files. Rather use environment variables. See here.
In addition we need to add the Stormpath starter to our pom.xml
.
<dependency> <groupId>com.stormpath.spring</groupId> <artifactId>stormpath-default-spring-boot-starter</artifactId> <version>1.1.3</version> </dependency>
However, this includes Thymeleaf templating which clashes with Jasper (which we use to serve our JSPs). We need to exclude it. Instead of the above code use the following.
<dependency> <groupId>com.stormpath.spring</groupId> <artifactId>stormpath-default-spring-boot-starter</artifactId> <version>1.1.3</version> <exclusions> <exclusion> <groupId>com.stormpath.spring</groupId> <artifactId>stormpath-thymeleaf-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency>
If you restart your application and refresh the homepage you should see Stormpath trying to log you in. This is because we haven’t specified access controls per page. By default everything is locked down.
Image may be NSFW.
Clik here to view.
Typing in the details for a user account in your Stormpath application should take you to the ‘Hello, World!’ message as before.
Authorization
Finally to illustrate authorization we will use Spring Security’s JSP tag libraries which allows us to control behaviour based on Access Expressions (we’ll deal with those in a second).
First we add the tag libraries to our pom.xml
.
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> </dependency>
Next we import the library to our JSP by adding the following line to the top.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
With that we can use the special sec
tags to control how the JSP is rendered. For example take the following section of code.
<sec:authorize access="hasAuthority('supervisor')"> This content will only be visible to users who have the "supervisor" authority in their list of <tt>GrantedAuthority</tt>s. </sec:authorize>
Only users with authority supervisor
will be able to see the code in between the tags.
Role, Authority, and Access Expressions
Spring Security allows you to define policies on methods and attributes using the Spring Expression Language. For example you could use the @PreAuthorize
annotation to specify whether a user can access a function.
@PreAuthorize("hasRole('ROLE_USER')") public void create(Contact contact);
Part of the expression language is the concept of Role and Authority Spring Security uses in order to associate rights to users. To illustrate this take a look at the following xml config excerpt used before the Java configurations that are popular today today.
<http auto-config="true"> <intercept-url pattern="/admin**" access="ROLE_ADMIN" /> <intercept-url pattern="/dba**" access="ROLE_ADMIN,ROLE_DBA" /> </http>
This is how we would say who was allowed to see the /admin
and /dba
urls. It is not per user but per role. We then have to define who has what role when creating users.
<authentication-manager> <authentication-provider> <user-service> <user name="karl" password="123456" authorities="ROLE_USER" /> <user name="admin" password="123456" authorities="ROLE_ADMIN" /> <user name="dba" password="123456" authorities="ROLE_DBA" /> </user-service> </authentication-provider> </authentication-manager>
Note: In Stormpath we use hasAuthority
throughout. This is because hasRole
is the same as hasAuthority
but just with the string ‘ROLE_’ prepended. See details of our Spring Boot migration for more.
Stormpath Groups
Image may be NSFW.
Clik here to view.
Groups in Stormpath are analogous to Spring Security authorities. And to specify a group we use the href shown when you open the group up in the Stormpath Admin Console.
<sec:authorize access="hasAuthority('https://api.stormpath.com/v1/groups/<your href here>')">
If we add the referenced group to the user we logged in with previously and reload, we should see the message inside the sec
tags.
Image may be NSFW.
Clik here to view.
In this way, we can control who is allowed to access which sections of code such as buttons and forms.
JSP + Stormpath FTW
Hopefully, you can see how easy it is to secure your JSPs using Stormpath and Spring Security. With just a few files you can create a flexible system that allows centrally managing users and controlling what they can see and do based on the groups they belong to.
Interested in learning more about user management with Stormpath? Well you’re in luck, because we’ve got everything you need to get started!
- Token Authentication in Spring Boot
- Build User Management In Spring Boot & React
- Build a Simple Web App with Spring Boot, Spring Security, and Stormpath
- Add Stormpath to Your JHipster Application
- 5 Spring Boot API Tips
The post Securing JSPs with Spring Security and Stormpath appeared first on Stormpath User Identity API.