Spring (Authenticator only)
This guide describes the configuration of the Spring implementation of Apache Causeway' Authenticator SPI.
It does not however provide any implementation of Authorizor SPI. You will therefore need to configure an alternative implementation, eg the Bypass implementation (to disable authorisation checks completely), or use the SecMan implementation (see here for details).
Dependency Management
If your application inherits from the Apache Causeway starter app (org.apache.causeway.app:causeway-app-starter-parent
) then that will define the version automatically:
<parent>
<groupId>org.apache.causeway.app</groupId>
<artifactId>causeway-app-starter-parent</artifactId>
<version>2.1.0</version>
<relativePath/>
</parent>
Alternatively, import the core BOM. This is usually done in the top-level parent pom of your application:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.causeway.core</groupId>
<artifactId>causeway-core</artifactId>
<version>2.1.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
Dependency
In the webapp module of your application, add the following dependency:
<dependencies>
<dependency>
<groupId>org.apache.causeway.security</groupId>
<artifactId>causeway-security-spring</artifactId>
</dependency>
</dependencies>
Update AppManifest
In your application’s AppManifest
(top-level Spring @Configuration
used to bootstrap the app), import the CausewayModuleSecuritySpring
module and remove any other CausewayModuleSecurityXxx
modules.
Also, as this module provides no implementation of the Authorizor SPI, instead you will need some an alternative implementation, such as the Bypass implementation. (Note: this will in effect disable authorisation checks).
@Configuration
@Import({
...
CausewayModuleSecuritySpring.class, (1)
AuthorizorBypass.class, (2)
...
})
public class AppManifest {
}
1 | make sure that no other CausewayModuleSecurityXxx module is imported. |
2 | or some other implementation of Authorizor . |
Design
The module brings in a transitive dependency to org.springframework.boot:spring-boot-starter-security
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
This enables security by default, and should then be adjusted as required to enable access. See the Spring documentation for details on how to do this, for example:
-
Baeldung article on
spring-boot-starter-security
-
Tutorialspoint tutorial on
spring-boot-starter-security
The module itself configures a filter that is installed at the end of Spring Security’s filter chain. It uses the SecurityContextHolder to obtain the current authentication:
val springAuthentication = SecurityContextHolder.getContext().getAuthentication();
if(springAuthentication==null
|| !springAuthentication.isAuthenticated()) {
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return; // not authenticated
}
For an authenticated user the org.apache.causeway.viewer.wicket.roles.USER
role — as required by Web UI (Wicket viewer) — is automatically added to the list of roles.
Walk-through : In-memory
Using Spring Security we can configure your app with various authentication providers. In this section we describe how to modify the HelloWorld starter app to use an in-memory authenticator.
Code Changes
First, we need an implementation of WebSecurityConfigurerAdapter
to setup the inmemory authenticator:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("sven")
.password(passwordEncoder().encode("pass"))
.roles("USER"); (1)
;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
1 | at least one role must be assigned to each user. |
Next, we configure the necessary components (including SecurityConfig
, above).
As discussed above, we need to reference Apache Causeway' Spring security module and also an implementation of Authorizor SPI, eg the Bypass implementation:
@Configuration
@Import({
...
CausewayModuleSecuritySpring.class,
AuthorizorBypass.class,
SecurityConfig.class,
...
})
public class AppManifest {
}
Lastly (and optionally), the swagger/REST API is not configured for spring security, so we replace the index.html
page with one to redirect straight to the Wicket Viewer:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="refresh" content="0;url=/wicket/" />
</head>
<body>
<div id="wrapper">
<!-- we just redirect immediately, because swagger/restful API not configured to use spring security -->
</div>
</body>
</html>
AuthenticatorConverter SPI
The module provides a number of implementations of AuthenticationConverter that (attempt to) convert a Spring Authentication
object into an Apache Causeway UserMemento
.
Several implementations are provided by default for most of the common representations of a user principal, including support for UserDetails (as returned in the in-memory walk through above) and OAuth2User. This SPI does though provide additional flexibility for other security technologies that may be supported by Spring.