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#

  1. Loads the user via userRepository.findByLoginName(authentication.getName()).
  2. Reads authentication.getCredentials().
  3. If both the credential and the user model are non-null, delegates to userMgmtService.isValid(userModel, cred.toString()).
  4. 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 own UserDetailsService wrapper.
  5. On any failure — returns the original authentication object unchanged rather than throwing BadCredentialsException. This deviates from the typical Spring Security contract; downstream filters must check isAuthenticated() 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 (BadCredentialsException bubbling up), wrap this provider or check isAuthenticated() on the returned Authentication.
  • Empty authorities. The returned token carries no roles. If role-based authorization matters, chain a custom provider or UserDetailsService that populates GrantedAuthority entries from your roles table (or the ACL extension).
  • supports() returns true for everything. If you register other AuthenticationProviders, put the one with the most specific supports() first.