Skip to content

Latest commit

 

History

History

security

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Spring Boot: Security

This module demonstrates how to apply and test Spring Security and other basic security precautions.

Spring Security

Web-Security

This showcase implements general web-level security with two different authentication methods:

We use two different 'scopes' - SCOPE_ACTUATOR and SCOPE_BOOKS - to provide users with general access. These are 'authorities' assigned to a user inside the authorization process.

The detailed configuration is implemented in the WebSecurityConfiguration class.

Method-Security

This showcase implements method-level security using the following annotations:

  • @RolesAllowed - JEE default annotation. Uses simple 'role' names to grant access to the annotated method. Spring will be mapping the provided name to an 'authority' with the name ROLE_$name!

  • @PreAuthorize - Powerful Spring annotation. Allows us to use Spring Expression Language to define the criteria needed to be granted access to a method. This includes accessing method parameters and including their values into the expression.

  • @Secured - old school Java 5 annotation. Uses its value as the name of an 'authority' that grants access to the annotated method.

There is also the less commonly used @PostAuthorize annotation. Like @PreAuthorization it allows for more complex rules. The difference being that it will be evaluated after the method was executed. This allows the expressions to access return values. But it is not useful in preventing unauthorized execution of code. The main use is in preventing data leakage, not actions.

The method-level security is configured in the MethodSecurityConfiguration class and used in the BookCollection component.

Testing

The most useful feature of Spring Security - for integration testing - is the @WithMockUser annotation. It allows tests to declare the characteristics of an authenticated user for the scope of the annotated test / class.

This is used for method-level (see BookCollectionTests) as well as web-level (see BooksRestControllerTests) security.

In addition to incorporating security tests with you usual functional testing, there should always be a more general security test for your web-level security rules. This is implemented in WebSecurityConfigurationTests as an example.

Note

Be aware that Spring Actuator does have web endpoints, but they are not part of the usual WebMVC or WebFlux technology stack. Therefore, they cannot be tested using mid-level integration slices like @WebMvcTest!

You can - and should - include security tests in your general smoke testing efforts. See ApplicationSecurityTests as an example. Note that you do not need duplicated testing effort. If you test all of your web-level configuration security rules in an application-level test (like a general smoke test), you do not need a separate @WebMvcTest based integration test for the WebSecurityConfiguration!

Input Validation

One important factor in establishing a basic application security level is to never trust data that is provided externally. We’ll refer to this as input validation. The basic principle is easy. Validate all data that comes into your application.

This includes request bodies, query and path parameters, headers etc. - everything your application actually reads and uses in some way. It is also not limited to HTTP APIs. If you consume events or other types of messages, the same principle applies.

In this showcase input validation is done using simple domain types for everything:

Be it the request body to create a new book or to query for existing books using an ISBN (see BooksRestController). These domain types are self-validating, meaning an instance of them cannot be created without validating the data. Providing invalid data (wrong format, too long, etc.) will fail to convert / de-serialize the data and result in a 400 Bad Request response by the framework (see BooksRestControllerTests).

Note

An alternative approach would be to activate and use JEE validation annotations on parameters and request bodies.

The reason we are using domain types comes down (mostly) to preference. Domain types can be used throughout the application’s code and guarantee that only valid values can be used anywhere. This improves type-safety, reduces code that checks for formats or constraints and leads to better test example data as well.

Annotation-driven validation however needs to be actively triggered and does nothing to distinguish one String parameter from any other.