Getting into Spring Boot, Part 22 Locked and Rammed – Security with Spring Boot
The topic of security is at the top of the agenda for many companies. We will deal with the basic protection of spring projects in the last article of this series for the time being.
Related companies
Calling a REST service with postman and authentication header.
(Picture: Koller / Spring.io)
The risk of data being stolen or encrypted by an attack gives many responsible people sleepless nights. Even Spring Boot can not take away the topic of explosiveness and complexity, but at least a basic protection of a project is realized quickly, it is done simply by adding the starter spring-boot-starter-security in POM.XML:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
The security settings probably do not yet correspond to your own ideas, but an MVC application, as discussed in previous parts of this series, is at least rudimentarily secured. This is shown by accessing any page of the web application.
Login page after integrating the starter into a web application.
(Picture: Koller / Spring.io)
Instead of the expected HTML page, a login page appears under /login after integrating the security starter. Spring is obviously doing a lot of work in the background here. The username required for access is user, the password can be found in the log outputs in the console:
Using generated security password: 83f9365e-91a1-4d5a-b534-6bbac903a0e8
After entering this data, you will then land on the originally desired page. This works similarly for a REST service. Instead of the expected JSON response, after adding the security starter, you will receive a 401/Unauthorized message when calling any endpoint:
{
"timestamp": "08:40:33.130+00:00",
"status": 401,
"error": "Unauthorized",
"path": "/customers"
}
Calling a REST service with postman and authentication header.
(Picture: Koller / Spring.io)
The service can only be called up again (in the example with Postman) by specifying a username and password in the form of a basic Authentication header.
Authentication
The password in the console changes with each reboot and is obviously not intended for productive use. The adaptation of the security configuration to your own requirements takes place in a WebSecurityConfigurerthe easiest way to inherit from the class WebSecurityConfigurerAdapter created. In the configuration class as shown in the following example, security is described by various methods.
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER")
.and()
.withUser("admin").password("{noop}password").roles("ADMIN");
}
}
In the example, using the AuthenticationManagerBuilder the two users user and admin, both with the password password and the roles USERS and ADMIN define. The password is not encrypted in this simple example (noop stands for NoOpPasswordEncoder).
Both the web application and the REST endpoint can be called up with the assigned account data after the restart, the output with the password generated by Spring in the console is omitted. In practice, you might want to compare the entered password with a value from a database.
No problem: instead of the method inMemoryAuthentication() this can be realized by calling jdbcAuthentication() from AuthenticationManagerBuilder. The following piece of code shows an example:
auth.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser(User.withUsername("user").password(passwordEncoder().encode("pass")).roles("USER"));
Authorization
Now that the user is authenticated (who is it?) does the authorization follow (what is he allowed to do?). For this, the configure() method is overridden. Here, too, an object, this time of the HttpSecurity type, is configured by calling various methods. Each of these gives a configurer such as HttpBasicConfigurer or FormLoginConfigurer back. The link is done by the and() method:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/adminspace").access("hasRole('ADMIN')")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin() // .loginPage("/login")
.and()
.httpBasic();
}
In the example above, authentication is enabled via the standard login page (call formLogin()) and via Basic Authentication (call httpBasic()). All requests must be authenticated and the URL /adminspace is only for users with the role ADMIN accessible. A separate login page can be configured by calling LoginPage(), in the code this is indicated as a comment.
Formulating the constraints is far from self-explanatory, but there are numerous configuration examples in the HttpSecurity class in the form of Javadoc comments.
Methods of Level Security
The protection described above with the help of the HttpSecurity object is based on servlet filters, incoming requests are checked and rejected if necessary. In addition to this mechanism, there is a second one that relies on AOP proxies and does not require web technologies.
With the help of this variant, called method level security, methods can be secured in services, for example. For this purpose, the annotation is placed in front of the method to be saved PreAuthorize and as a value attribute Spring Expression Language (Spel)-Expression specified. The method in the following example can again only be called with the ADMIN role:
@Service
public class AnyService { @PreAuthorize(value = "hasRole('ADMIN')")
public void anyMethod() {
...
}
}
For this to work, the annotation is still @enableglobalmethodsecurity_ to be accommodated in one configuration:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
In the example, the attributes prePostEnabled the pre- and post-annotations are enabled. In addition to the pre- and PostAuthorize annotations, there are also the pre- and PostFilter annotations. They also work with SpEL and are used to filter collections or arrays depending on the expression, and thus remove elements before returning. The alternative attributes securedEnabled and jsr250Enabled do the annotations concern @Secured_ and @roleallowed_ – both do not work with SpEL expressions and only validate against roles.
The complex topic of security in Spring is only touched upon with this post, there are entire books on it (for example Spring Security in Action by Laurențiu Spilcă). You can also find out more about the underlying concepts under Spring Security Architecture.
(ID:47710477)