About

This module enables support for Spring security for an Across based application. The standard Spring security filter chain and method security annotation processors will be registered automatically if this module is present. It also allows other Across modules to customize the security rules of your application.

1. General information

1.1. Artifact

<dependencies>
    <dependency>
        <groupId>com.foreach.across.modules</groupId>
        <artifactId>spring-security-module</artifactId>
        <version>3.0.1.RELEASE</version>
    </dependency>
</dependencies>

1.2. Module dependencies

Module Type Description

AcrossHibernateJpaModule

extension

Creates the AuditableEntityInterceptor bean.

1.3. Module settings

SpringSecurityModule does not have any settings.

1.4. Cache configuration

SpringSecurityModule uses the following caches:

Name Description

securityPrincipalCache
(SpringSecurityModuleCache.SECURITY_PRINCIPAL)

Caches SecurityPrincipal instances by principal name. Used by the default SecurityPrincipalService.

2. What’s new in this version?

3.0.0.RELEASE

Requires Across 3.0.0 or higher.

The security implementation has been rewritten to reuse existing Spring Boot security auto-configuration where possible. In certain applications (for example with Actuator or the H2 Console), this might mean that additional security will now be active by default.

List of changes:

  • WebSecurityConfigurer beans from other modules or the parent ApplicationContext are now also supported

    • it is no longer strictly required to use SpringSecurityWebConfigurer from a module

  • default Spring Boot security configuration will be applied as of this version

    • an additional default Security filter for ignoring requests is automatically added, a module or application can provide one or more IgnoredRequestCustomizer

    • the default InMemoryAuthenticationManager

  • unlike a regular Spring Boot application this module does not activate basic authentication by default

    • basic authentication for the entire application is only explicitly enabled if you set property security.basic.enabled to true

2.0.1.RELEASE

Minor bugfixes.

2.0.0.RELEASE

Requires Across 2.0.0+.

1.1.0.RELEASE

SecurityPrincipalService#authenticate() now returns a Closeable instance.

1.0.0.RELEASE

Initial public release available on Maven central.

3. Module configuration

The SpringSecurityModule registers 2 separate modules. The SpringSecurityInfrastructureModule provides the SecurityPrincipal infrastructure as early as possible during the bootstrap phase. The SpringSecurityModule itself is responsible for registering the security filters. Only the SpringSecurityModule should be manually added to the AcrossContext, the infrastructure module will be added automatically.

4. Configuring web security

This chapter details how security configuration can be applied in an Across application. It does not explain how to create security rules or how Spring Security works. Please refer to the official Spring security documentation for this.

4.1. Authentication manager

SpringSecurityModule will always build an AuthenticationManager when it is present. If you do not build one yourself, a default one with an in-memory user based on the SecurityProperties will be added. Unless a password is set using security.user.password, one will be generated when the application starts, and printed in the logs.

Any module can configure the global AuthenticationManager, by injecting an @EnableGlobalAuthentication class in the SpringSecurityModule. This is usually done by adding it as a module extension (@ModuleConfiguration in an extensions package).

Example configuration of the global AuthenticationManager
@ModuleConfiguration(SpringSecurityModule.NAME)
@EnableGlobalAuthentication
public class AuthenticationConfiguration
{
        @Autowired
        public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception {
                auth.inMemoryAuthentication()
                    .withUser( "admin" ).password( "admin" )
                    .authorities( new SimpleGrantedAuthority( "access administration" ) );
        }
}

4.2. Basic security

SpringSecurityModule supports the default SecurityProperties provided by Spring Boot. Unlike a regular Spring Boot application however, basic security for the entire application is not enabled by default.

If you set property security.basic.enabled to true, basic security will be applied for the entire application.

Spring Boot SecurityProperties
# SECURITY (SecurityProperties)
security.basic.authorize-mode=role # Security authorize mode to apply.
security.basic.enabled=false # Enable basic authentication.
security.basic.path=/** # Comma-separated list of paths to secure.
security.basic.realm=Spring # HTTP basic realm name.
security.enable-csrf=false # Enable Cross Site Request Forgery support.
security.filter-order=0 # Security filter chain order.
security.filter-dispatcher-types=ASYNC, FORWARD, INCLUDE, REQUEST # Security filter chain dispatcher types.
security.headers.cache=true # Enable cache control HTTP headers.
security.headers.content-security-policy= # Value for content security policy header.
security.headers.content-security-policy-mode=default # Content security policy mode.
security.headers.content-type=true # Enable "X-Content-Type-Options" header.
security.headers.frame=true # Enable "X-Frame-Options" header.
security.headers.hsts=all # HTTP Strict Transport Security (HSTS) mode (none, domain, all).
security.headers.xss=true # Enable cross site scripting (XSS) protection.
security.ignored= # Comma-separated list of paths to exclude from the default secured paths.
security.require-ssl=false # Enable secure channel for all requests.
security.sessions=stateless # Session creation policy (always, never, if_required, stateless).
security.user.name=user # Default user name.
security.user.password= # Password for the default user name. A random password is logged on startup by default.
security.user.role=USER # Granted roles for the default user name.

Although SpringSecurityModule does not enable basic security by default, other libraries might still apply security unless it is explicitly disabled. An example is the H2 Console which will apply the basic security unless security.basic.enabled is explicitly set to false.

4.3. Custom security

The SpringSecurityModule enables support for SpringSecurityWebConfigurer implementations to be provided by different modules. Usually this is done by implementing your own SpringSecurityWebConfigurerAdapter. Every SpringSecurityWebConfigurerAdapter results in a separate request filter to be added to the Spring security filter chain. Once a request has been handled by a filter, all remaining filters will be skipped.

For this reason it is vital that SpringSecurityWebConfigurerAdapter instances are added in the correct order and are correctly scoped to the subset of requests they are meant for. The SpringSecurityModule respects all bean ordering rules that Across provides: using the module order by default and allowing the use of @Order, @OrderInModule or their respective interfaces.

Note
As of version 3.0.0, default WebSecurityConfigurer beans from modules are supported as well for security configuration.

Spring security itself allows very advanced configuration and customization. Please refer to the official Spring security documentation for more details.

4.4. Disabling security on requests

If you want to exclude certain paths from security (for example for static resources), you can either set them using the property security.ignored or provide an IgnoredRequestCustomizer to add them.

4.5. Auto-configuration support

Most of the actual security configuration is applied in the context of the SpringSecurityModule. Even though WebSecurityConfigurer or SpringSecurityWebConfigurer beans can be provided by other modules, when they need fine-grained access to the Spring security beans (eg. ObjectPostProcessor) it is usually better to inject them in the SpringSecurityModule.

When adapting auto-configuration classes of existing starters, you should try shifting the relevant security configurations to the SpringSecurityModule. This can often be done simply by adding an entry in a META-INF/across.configuration`

Example META-INF/across.configuration (excerpt of SpringSecurityModule)
# Move existing security auto-configurations to SpringSecurityModule
com.foreach.across.AutoConfigurationEnabled=\
  org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration->SpringSecurityModule,\
  org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration->SpringSecurityModule

If this is not sufficient, you might have to write a custom AcrossBootstrapConfigurer adapter, and inject that class instead of the original auto-configuration. Please see the Across framework reference documentation for more information on the across.configuration file.

4.6. Debugging security configuration ordering

If you want to trace the different configurers that are being applied, you should enable DEBUG logging for class com.foreach.across.modules.spring.security.config.AcrossWebSecurityConfiguration. This will output the different configurer beans in the order they will be applied, along with their type, bean and module name (if available).

5. SecurityPrincipal abstraction

The SpringSecurityModule provides an additional abstraction layer on top of the standard Authentication in the form of the SecurityPrincipal interface. Other modules like the UserModule and OAuth2Module provide an implementation of the SecurityPrincipal concept.

Since SecurityPrincipal is a relatively straightforward interface, a principal can be pretty much anything (user, group, machine…​). The only requirement is that every SecurityPrincipal has a unique principal name that identifies it.

Several beans are available for interacting with the current security principal:

Type Description

SecurityPrincipalService

Allows you to fetch any SecurityPrincipal by its unique principal name using a backing SecurityPrincipalRetrievalStrategy. Also provides some helper methods to quickly authenticate or de-authenticate a principal.

CurrentSecurityPrincipalProxy

Proxies the current security principal (if there is one). Allows authority checking from anywhere in your code using the hasAuthority(String) method.

The SpringSecurityAclModule wires a CurrentAclSecurityPrincipalProxy instead that provides additional methods to check for ACL permissions.

Example of using the SecurityPrincipalService to authenticate a principal
// execute a section within the scope of an authenticated SecurityPrincipal,
// when the block closes the previous authentication will be reset
try ( CloseableAuthentication authenticatedBlock
                    = securityPrincipalService.authenticate( principal ) ) {
    // do something
}

5.1. SecurityPrincipalRetrievalStrategy

The default SecurityPrincipalService uses a backing SecurityPrincipalRetrievalStrategy to fetch the actual principal based on its unique name. If you want to define your own custom implementation you can do so by replacing the strategy implementation, see the javadoc and source code for more information.

5.2. SecurityPrincipal caching

The default SecurityPrincipalService uses the securityPrincipalCache for retrieving principal instances. If the cache does not return an instance, the request is delegated to the the SecurityPrincipalRetrievalStrategy. Actually maintaining the cache however is left to the implementation providers, the default SecurityPrincipalService only caches null values (principal not found). Examples can be found in SecurityPrincipal providing modules, for example UserModule.

5.3. SecurityPrincipalLabelResolver

Any module can define one or more SecurityPrincipalLabelResolver beans. These are used to generate a pretty label for a given SecurityPrincipal instance. SecurityPrincipalLabelResolver instances are ordered and the first resolver to return a valid label will be used.

SecurityPrincipalLabelResolver beans should not be used directly but through the exposed SecurityPrincipalLabelResolverStrategy.

Note
It is a best practice to provide a SecurityPrincipalLabelResolver for every SecurityPrincipal implementation your module provides. The resolver beans do not need to be exposed.

6. AllowableActions

SpringSecurityModule also provides an AllowableActions construct that can easily be used to define a set of actions that can be performed on an item. The purpose is for code to check if an action is present in the AllowableActions collection, meaning that the action can be performed. This helps decoupling your business code from the specifics of the security layer and can be supported in both an ACL and non-ACL context.

A single AllowableAction is identified by a unique string, making it very easy to extend. Useful implementations can be found in the com.foreach.across.modules.spring.security.actions package. The AuthorityMatchingAllowableActions maps AllowableAction on AuthorityMatcher and provides concrete implementation supporting both Authentication and SecurityPrincipal.

Actions can be mapped against anything (most likely authorities or ACL permissions) and can also be completely different depending on the target they need to be applied to. This allows for as much granularity you might want, without having to change your permission model.

Example of mapping AllowableActions against GrantedAuthorities
@Autowired
private CurrentSecurityPrincipalProxy currentPrincipal;

public AllowableActions createAllowableActionsForCurrentSecurityPrincipal() {
    Map<AllowableAction, AuthorityMatcher> actionAuthorityMatcherMap = new HashMap<>();
    actionAuthorityMatcherMap.put( AllowableAction.READ, AuthorityMatcher.allOf( "read items" ) );
    actionAuthorityMatcherMap.put( AllowableAction.UPDATE, AuthorityMatcher.allOf( "write items" ) );

    return AuthorityMatchingAllowableActions.forSecurityPrincipal( currentPrincipal, actionAuthorityMatcherMap )
}
Tip
Use the AllowableAction concept to hide specifics of the security permission layer.

7. AuditableEntityInterceptor

If the AcrossHibernateJpaModule is present in the Across context, an AuditableEntityInterceptor bean will be created. Any entity implementing the com.foreach.across.modules.hibernate.business.Auditable interface will get its auditing properties updated before it is persisted.