Usage

This short example shows how to use the LTPA2 Security Module. This example uses Spring Boot.

Requirements

  • Spring Security 6.0+

  • Spring Boot 3.1+

Integration

pom.xml

Add it as an dependency together with you Spring Security dependencies.

<project>
	<!-- ... -->

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-ldap</artifactId>
		</dependency>
		<dependency>
			<groupId>de.sephiroth-j</groupId>
			<artifactId>spring-security-ltpa2</artifactId>
			<version>[2.0.0,)</version>
		</dependency>
	</dependencies>

	<repositories>
		<repository>
			<id>mrepo.sephiroth-j.de</id>
			<url>https://mrepo.sephiroth-j.de/</url>
		</repository>
	</repositories>

	<!-- ... -->
</project>

Security Configuration for Web Servlet

Add the Ltpa2Filter using Ltpa2Configurer. It needs a SecretKey instance of the shared key that is used for the symmetric encryption and decryption of the LTPA2 token. In order to verify the provided token, it also needs the PublicKey from the identity provider (for example IBM Secure Gateway / DataPower) that sends the LTPA2 token.

As the user is pre-authenticated, an instance of UserDetailsService is required to setup the security context and populate it with the granted roles for the authenticated user. In this example we will simply use InMemoryAuthentication with a hard-coded list of users and their roles.

Example with In-Memory Authentication
@Configuration
@EnableWebSecurity
public class WebSecurityConfig
{
	@Bean
	public SecurityFilterChain ltpa2SecurityFilterChain(final HttpSecurity http, final UserDetailsService userDetailsService) throws Exception
	{
		http
			.authorizeHttpRequests(authorize -> authorize
				// all other require any authentication
				.anyRequest().authenticated()
			)
			// configure LTPA2 Support
			.apply(new Ltpa2Configurer())
				.sharedKey(sharedKey())
				.signerKey(signerKey())
			;
		http.userDetailsService(userDetailsService);
		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService()
	{
		final UserDetails user = User.builder()
			.username("user")
			.password("{noop}password")
			.roles("USER")
			.build();
		return new InMemoryUserDetailsManager(user);
	}
}
Example with LDAP
@Configuration
@EnableWebSecurity
public class WebSecurityConfig
{
	@Bean
	public SecurityFilterChain ltpa2SecurityFilterChain(final HttpSecurity http, final UserDetailsService userDetailsService) throws Exception
	{
		http
			.authorizeHttpRequests(authorize -> authorize
				// all other require any authentication
				.anyRequest().authenticated()
			)
			// configure LTPA2 Support
			.apply(new Ltpa2Configurer())
				.sharedKey(sharedKey())
				.signerKey(signerKey())
			;
		http.userDetailsService(userDetailsService);
		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService()
	{
		final DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://127.0.0.1:33389/dc=foo,dc=bar");
		contextSource.afterPropertiesSet();

		final LdapUserDetailsManager manager = new LdapUserDetailsManager(contextSource);
		manager.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=user", "cn"));
		manager.setGroupSearchBase("ou=groups");
		return manager;
	}
}

Security Configuration for Web Reactive

Add an AuthenticationWebFilter using Ltpa2AuthManager and the Ltpa2AuthConverter. The Ltpa2AuthConverter needs a SecretKey instance of the shared key that is used for the symmetric encryption of the LTPA2 token. In order to verify the provided token, it also needs the PublicKey from the identity provider (for example IBM Secure Gateway / DataPower) that sends the LTPA2 token.

As the user is pre-authenticated, an instance of ReactiveUserDetailsService is required to setup the security context and populate it with the granted roles for the authenticated user. In this example we will simply use MapReactiveUserDetailsService with a hard-coded list of users and their roles.

Example with In-Memory Authentication
@Configuration
@EnableWebFluxSecurity
public class WebSecurityConfig
{

	@Bean
	public SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http, final AuthenticationWebFilter ltpa2AuthenticationWebFilter)
	{
		http
			.csrf(CsrfSpec::disable)
			.httpBasic(HttpBasicSpec::disable)
			.authorizeExchange(authorize -> authorize
			// all other require any authentication
			.anyExchange().authenticated())
			// apply ltpa2 authentication filter
			.addFilterAt(ltpa2AuthenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);
		return http.build();
	}

	@Bean
	AuthenticationWebFilter ltpa2AuthenticationWebFilter(ReactiveUserDetailsService userDetailsService) throws GeneralSecurityException
	{
		final Ltpa2AuthConverter converter = new Ltpa2AuthConverter();
		converter.setSharedKey(sharedKey());
		converter.setSignerKey(signerKey());

		final AuthenticationWebFilter webfilter = new AuthenticationWebFilter(new Ltpa2AuthManager(userDetailsService));
		webfilter.setServerAuthenticationConverter(converter);
		return webfilter;
	}

	@Bean
	public ReactiveUserDetailsService userDetailsService()
	{
		final UserDetails user = User.builder()
			.username("user")
			.password("{noop}password")
			.roles("USER")
			.build();
		return new MapReactiveUserDetailsService(user);
	}
}

Where to put the token in a HTTP-Request

Tokens are either taken from an HTTP header (default Authorization with prefix LtpaToken2) or a cookie (default LtpaToken2). Both names can be configured as needed, as well as the value prefix.

Examples
# default header and value prefix
curl -i -H "Authorization: LtpaToken2 <token-value>" http://localhost:8080/hello
# custom header name without value prefix
curl -i -H "My-Auth-Header: <token-value>" http://localhost:8080/hello
# default cookie
curl -i -b "LtpaToken2=<token-value>" http://localhost:8080/hello
# custom cookie name
curl -i -b "My-Auth-Cookie=<token-value>" http://localhost:8080/hello