LocalDBAuthenticationProvider#
com.palmyralabs.palmyra.ext.usermgmt.security.LocalDBAuthenticationProvider
Overview#
Spring Security AuthenticationProvider backed by a local database. Wire it into your SecurityFilterChain and every UsernamePasswordAuthenticationToken is validated against the user_password table via UserPasswordRepository and PasswordMgmtService.
Annotated @Component, @Slf4j, @RequiredArgsConstructor — Lombok generates the constructor over the two final dependencies.
Dependencies#
Injected via the Lombok-generated constructor:
private final UserPasswordRepository userRepository;
private final PasswordMgmtService userMgmtService;Methods#
| Method | Signature |
|---|---|
authenticate |
Authentication authenticate(Authentication authentication) throws AuthenticationException |
supports |
boolean supports(Class<?> authentication) — returns true unconditionally (accepts every Authentication subtype) |
Behaviour — what authenticate() actually does#
- Loads the user via
userRepository.findByLoginName(authentication.getName()). - Reads
authentication.getCredentials(). - If both the credential and the user model are non-null, delegates to
userMgmtService.isValid(userModel, cred.toString()). - On success — returns a new
UsernamePasswordAuthenticationToken(name, "password", emptyAuthorities). Note:- The credential stored in the returned token is the literal string
"password", not the original credential. - Authorities are always an empty
HashSet<GrantedAuthority>; role mapping has to happen upstream (e.g. the ACL extension) or in your ownUserDetailsServicewrapper.
- The credential stored in the returned token is the literal string
- On any failure — returns the original
authenticationobject unchanged rather than throwingBadCredentialsException. This deviates from the typical Spring Security contract; downstream filters must checkisAuthenticated()themselves to detect auth failure.
Wiring#
Register the provider in your security configuration; everything else falls out of Spring’s default filter chain:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final LocalDBAuthenticationProvider localDbProvider;
@Bean
AuthenticationManager authManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.authenticationProvider(localDbProvider)
.build();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(a -> a
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated())
.exceptionHandling(e -> e
.authenticationEntryPoint((req, res, ex) ->
res.sendError(HttpServletResponse.SC_UNAUTHORIZED)))
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}Caveats#
- No exception on bad credentials. If you rely on the default Spring Security behaviour (
BadCredentialsExceptionbubbling up), wrap this provider or checkisAuthenticated()on the returnedAuthentication. - Empty authorities. The returned token carries no roles. If role-based authorization matters, chain a custom provider or
UserDetailsServicethat populatesGrantedAuthorityentries from your roles table (or the ACL extension). supports()returnstruefor everything. If you register otherAuthenticationProviders, put the one with the most specificsupports()first.