Spring Boot Not Using UserDetailsService - spring

I am trying to configure a Spring Boot 1.2.5 application for JPA authentication using annotations and it appears to be always using the in-memory provider.
The application:
#EnableWebMvc
#ComponentScan
#EnableAutoConfiguration
#SpringBootApplication
public class ClubBooksApplication {
protected final Logger logger = LoggerFactory.getLogger(getClass());
public static void main(String[] args) {
SpringApplication.run(ClubBooksApplication.class, args);
}
}
The WebSecurityConfigurerAdapter. I have played around with the order but it always seems to configure the in-memory provider. I feel like I could be missing a piece of configuration but this pattern matches the samples I found in my searches.
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
//#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) // After in memory
//#Order(SecurityProperties.IGNORED_ORDER) // Before in memory
//#Order(SecurityProperties.BASIC_AUTH_ORDER) // Not unique
#Order(SecurityProperties.BASIC_AUTH_ORDER - 50) // Before in memory
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private PasswordEncoder passwordEncoder;
protected final Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
logger.info(String.format("configure AuthenticationManagerBuilder: %s", userDetailsService));
super.configure(auth);
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
Here is the log output. You can see it is configuring the UserDetailsService before displaying the generated password. Based on my digging into the code, it appears to only configure the in-memory provider if no other provider is configured but setting the UserDetailsService configures a DAO provider.
2015-08-20 11:19:24.187 INFO 42332 --- [ost-startStop-1] yConfig$$EnhancerBySpringCGLIB$$c647e8e8 : configure AuthenticationManagerBuilder: com.wstrater.server.clubBooks.server.service.impl.UserLoginDetailServiceImpl#46f0f40a
2015-08-20 11:19:24.226 INFO 42332 --- [ost-startStop-1] yConfig$$EnhancerBySpringCGLIB$$c647e8e8 : passwordEncoder
2015-08-20 11:19:24.410 INFO 42332 --- [ost-startStop-1] b.a.s.AuthenticationManagerConfiguration :
Using default security password: 838a7ab0-3bd0-4e87-94ca-de2dfd34b965
2015-08-20 11:19:24.526 INFO 42332 --- [ost-startStop-1] yConfig$$EnhancerBySpringCGLIB$$c647e8e8 : configure HttpSecurity
I have included Actuator in the app and when I try to access http://localhost:8080/mappings, I am prompted with BasicAuth despite configuring form based authentication. The user/generated password works for BasicAuth. My UserDetailsService implementation is not called.
Configuring HttpSecurity. This method is called after the in-memory provider is created and the generated password is displayed so I doubt it impacts the provider configuration. The one thing I find interesting is that I get prompted for BasicAuth despite specifying formLogin(). I bring this up since I am also having issues with mapping my controllers. I think it is unrelated but what do I know.
#Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("configure HttpSecurity");
super.configure(http);
http.authorizeRequests()
.antMatchers("/", "/public/**")
.permitAll()
.antMatchers("/rest/**")
.authenticated()
.antMatchers("/web/**")
.authenticated()
.anyRequest()
.fullyAuthenticated();
http.formLogin()
.loginPage("/login")
.usernameParameter("userName")
.passwordParameter("password")
.failureUrl("/login?error")
.defaultSuccessUrl("/web/")
.permitAll()
.and().logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll()
.and().rememberMe();
}
I can see my controllers are being loaded by Spring since they are listed using http://localhost:8080/beans but I do not see the mappings in http://localhost:8080/mappings.
My login controller is rather simple.
#Controller
#Path("/login")
public class LoginWebController {
#GET
public ModelAndView getLoginPage(#RequestParam(required = false) String error) {
return new ModelAndView("login", "error", error);
}
}
Thanks, Wes.

I eventually solved this after working around and/or avoiding the problem so I may have done several things to solve the issue but I believe it is as simple as removing the call to super.configure(http);. This sets up basic auth.
Wes.

Related

spring boot actuator endpoints with Keycloak security

we have a spring boot project (2.3.0.RELEASE) with actuator endpoints and we are introducing keycloak to the project with KeycloakWebSecurityConfigurerAdapter how can I prevent actuator endpoints being secured by the keycloak filter chain.
We would like to have the "/actuator/**" endpoints secured by basic auth.
Currently we have a custom WebSecurityConfigurerAdapter with #Order(1) where we apply the basic auth to "/actuator/**" and then we have with #Order(2) antotated the KeycloakWebSecurityConfigurerAdapter
so 2 filter chains gets registered and when I call the actuator endpoints the second filter chain fails as unauthorised 401
is it possible to prevent handling the "/actuator/**" resorce path on the second filter chain?
First actuator security configuration.
#Configuration
#Order(1)
public class ActuatorWebSecurityConfig extends WebSecurityConfigurerAdapter {
private final String username;
private final String password;
private final PasswordEncoder encoder;
public ActuatorWebSecurityConfig(
#Value("${spring.security.user.name}") String username,
#Value("${spring.security.user.password}") String password,
Optional<PasswordEncoder> encoder) {
this.username = username;
this.password = password;
this.encoder = encoder.orElseGet(PasswordEncoderFactories::createDelegatingPasswordEncoder);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(username)
.password(encoder.encode(password))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/actuator/**")
.authorizeRequests(authorize -> authorize.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
}
}
second keycloak securoty configuration
#Order(2)
#KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
private final String swaggerUrl;
private final CorsFilter corsFilter;
private final CustomSecurityConfig customSecurityConfig;
#Autowired
public SecurityConfig(
#Value("${springdoc.swagger-ui.url:#{null}}") String swaggerUrl,
CorsFilter corsFilter,
CustomSecurityConfig customSecurityConfig) {
this.swaggerUrl = swaggerUrl;
this.corsFilter = corsFilter;
this.customSecurityConfig = customSecurityConfig;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakProvider = keycloakAuthenticationProvider();
keycloakProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));
.headers().frameOptions().disable()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/public/**", "/resources/**", "/resources/public/**").permitAll()
.antMatchers(OPTIONS, "/**").permitAll();
.authorizeRequests()
.antMatchers("/**")
.authenticated();
}
}
I have tried with on keycloak config
.antMatchers("/actuator/**").permitAll();
and with
http.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));
but nothing works I receive unauthorised 401 for actuator
the registered filter chains :
2022-01-18 17:38:44,688 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: Ant [pattern='/actuator/**'], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#25c6a9de, org.springframework.security.web.context.SecurityContextPersistenceFilter#56f3f9da, org.springframework.security.web.header.HeaderWriterFilter#33dcbdc2, org.springframework.security.web.csrf.CsrfFilter#522fdf0c, org.springframework.security.web.authentication.logout.LogoutFilter#365ad794, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#23df16cf, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#227cba85, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#b38dc7d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#142422a4, org.springframework.security.web.session.SessionManagementFilter#2f0b7b6d, org.springframework.security.web.access.ExceptionTranslationFilter#74bca236, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#30587737]
2022-01-18 17:38:44,691 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: NegatedRequestMatcher [requestMatcher=Ant [pattern='/actuator/**']], [com.betex.auth.filters.CorsFilter#20a9f5fb, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#10e28d97, org.springframework.security.web.context.SecurityContextPersistenceFilter#c6b08a5, org.springframework.security.web.header.HeaderWriterFilter#5f05cd7e, org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter#2a54c92e, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter#55b62db8, org.springframework.security.web.authentication.logout.LogoutFilter#274f51ad, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#54980154, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#25874884, org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter#8cb7185, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter#4dac40b, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#37d43b9b, org.springframework.security.web.session.SessionManagementFilter#11e8e183, org.springframework.security.web.access.ExceptionTranslationFilter#56f1db5f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#78543f0d]
When you extend KeycloakWebSecurityConfigurerAdapter, the adapter register a Bean of type KeycloakAuthenticationProcessingFilter. This filter is registered in the Spring Security's SecurityFilterChain, and because it's a Bean, it is also automatically registered by Spring Boot in the original chain, therefore even if Spring Security doesn't apply it, it will be applied later on in original the filter chain.
Try disabling this filter from being registered by Spring Boot, like so:
#Bean
public FilterRegistrationBean registration(KeycloakAuthenticationProcessingFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
In addition, if you are using OAuth 2, you may consider using spring-security-oauth2-resource-server and simplifying your Resource Server's configuration. Take a look at the documentation. This way you don't need to extend the custom adapter, just rely on the out-of-the-box configuration from Spring Security.

Spring security - Specific session creation policy per matchers

I'm trying to implement SessionCreationPolicy.ALWAYS for the /testMVCController/** endpoint and SessionCreationPolicy.STATELESS for rest of endpoints (/**).
Expected scenario:
When accessing to /testMVCController/displayUsers the user logs in once and the log I have implemented in UserDetailsService logs the authorities associated to that user.
After that, all the requests to /testMVCController/displayUsers or other URL under /testMVCController/** will not log the authorities again because the session creation policy is always and the user is already logged in.
This works when I don't specify the 2nd security configuration (X509ClientSessionCreationPolicyStateless) but when I add it, all the requests become session stateless.
It is not working with the current security configuration because after I log in with my client certificate, at any request executed under /testMVCController/** endpoint (e.g. /testMVCController/displayUsers), the authenticationUserDetailsService is consulted and the list of authorities is logged for each file request the browser makes (.js file, .css files, ...), even after the initial login.
So, if there are 3 requests (/testMVCController/displayUsers, displayUsers.js, displayUsers.css) the list of authorities log present in authenticationUserDetailsService is logged 3 times.
I configured SecurityConfiguration as shown below but it is not working:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfiguration {
#Configuration
#Order(1)
public static class X509ClientSessionCreationPolicyAlways extends WebSecurityConfigurerAdapter {
#Autowired
private X509CUDService x509CUDService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/testMVCController/**")
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.x509()
.authenticationUserDetailsService(x509CUDService)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
}
}
#Configuration
#Order(2)
public static class X509ClientSessionCreationPolicyStateless extends WebSecurityConfigurerAdapter {
#Autowired
private X509CUDService X509CUDService ;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.x509()
.authenticationUserDetailsService(X509CUDService);
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
}
I've searched this issue and I found various links (e.g. Spring session creation policy per-request?, Spring Session: How to create separate session management policies for different URLs and Multiple HttpSecurity) but none of them worked.
Thanks in advance!
I was missing some details on my configuration. I was catching all the requests to /testMVCController/** and that was working, but in addition to catch the requests to any endpoint of the type /testMVCController/** (e.g.: /testMVCController/usersList), I also have to catch the requests that these pages make to get their scripts (.js files, .css files, .png files).
What was happening was: the request to /testMVCController/usersList), was configured with SessionCreationPolicy.ALWAYS, but the subsequent requests such as usersList.js, usersList.css, etc were configured with SessionCreationPolicy.STATELESS, and in these cases the X509CustomUserDetailsService was always consulted.
Example:
GET request to /testMVCController/usersList works, but there also requests in this usersList page to usersList.js, usersList.css, etc.
So, once I included these resource paths in the antMatchers all worked perfectly.

Spring (boot) Security preauthentication with permitted resources still authenticated

I am using Spring Boot 1.5.6 (also have tried with 1.5.4).
I am using a
RequestHeaderAuthenticationFilter
and a
PreAuthenticatedAuthenticationProvider
to secure my spring mvc web app and also permit access to both a controller path and static resources.
In my
RequestHeaderAuthenticationFilter
set up I want
setExceptionIfHeaderMissing(true);
so that I know if the header variable has been sent in the request.
When I try to access any of the permitted resources, Spring Security always looks for the header variable in the request and throws a
PreAuthenticatedCredentialsNotFoundException
Why is spring security still trying to look up the preauthenticated principal even though I am trying to access a permitted (non-protected) resource?
How can I circumvent this behaviour?
My java config for WebSecurityConfigurerAdapter is below
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
#Autowired
protected UserDetailsService userDetailsService;
#Bean
public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider(){
log.info("Configuring pre authentication provider");
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper =
new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(
userDetailsService);
PreAuthenticatedAuthenticationProvider it = new PreAuthenticatedAuthenticationProvider();
it.setPreAuthenticatedUserDetailsService(wrapper);
return it;
}
#Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception{
RequestHeaderAuthenticationFilter it = new RequestHeaderAuthenticationFilter();
it.setAuthenticationManager(authenticationManager());
it.setExceptionIfHeaderMissing(true);
return it;
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
log.info("configure authentication provider");
auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
log.info("Configure HttpSecurity");
http
.authorizeRequests()
.antMatchers("/permitted/**", "/css/**", "/js/**", "/images/**", "/webjars/**")
.permitAll()
.anyRequest()
.authenticated()
.and().addFilter(requestHeaderAuthenticationFilter())
;
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/permitted/**", "/css/**", "/js/**", "/images/**", "/webjars/**");
}
}
I had the same problem and it turned out it was related to the fact that in addition to being registered in the SecurityFilterChain, Spring Boot was also registering the RequestHeaderAuthenticationFilter with the Servlet Context. The solution is to use a FilterRegistrationBean to prevent Boot from auto registering the filter with the Servlet Context.
More details here:
Spring Boot Security PreAuthenticated Scenario with Anonymous access

Spring Boot Management security works differently with port set

I'm trying to configure a Spring Boot application (1.2.3, but this also fails with the 1.2.4.BUILD-SNAPSHOT version) with Actuator support. I want to use the Actuator security config for controlling access to the management endpoints, and our own authentication for the rest of the application.
Here is my security config:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
#Autowired
private CustomAuthenticationProvider customAuthProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(customAuthProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.regexMatchers(API_DOC_REGEX).permitAll()
.regexMatchers(String.format(PATH_REGEX, PUBLIC_ACCESS)).permitAll()
.regexMatchers(String.format(PATH_REGEX, INTERNAL_ACCESS)).access("isAuthenticated() && authentication.hasOrigin('INTERNAL')")
.regexMatchers(String.format(PATH_REGEX, EXTERNAL_AUTHENTICATED_ACCESS)).authenticated()
.antMatchers("/**").denyAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.addFilterAfter(customAuthProcessingFilter(), BasicAuthenticationFilter.class)
.csrf().disable();
}
}
This works correctly when I don't set a management port, but when I set the management port, the management URLs return 401 responses. If I comment out the line .antMatchers("/**").denyAll(), then everything goes through without requiring authentication at all. So it looks like it is using my application's security config for the Actuator endpoints when I set a custom port, but I'm not sure why.
How do I get it to use it's own security when running on a custom port?
Expanding on the comment from #M. Deinum, adding another adapter for the Management stuff (even though it already has one) seems to have fixed it. This is the class I ended up with:
#Order(0)
#Configuration
public class ManagementSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
ManagementServerProperties managementProperties;
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.requestMatchers()
.requestMatchers(new RequestMatcher()
{
#Override
public boolean matches(HttpServletRequest request)
{
return managementProperties.getContextPath().equals(request.getContextPath());
}
})
.and()
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}

In Spring Security 3.2.5, what is causing an infinite loop inside the AuthenticationManager implementation?

I had an interesting situation not long ago which caused an infinite loop (and eventually a stack overflow) in Spring Security's AuthenticationManager. For months, everything worked as expected, but then I decided to transfer my XML configuration to code-only configuration. Here was my basic setup in Java configuration:
#Configuration
#EnableWebMvcSecurity
#ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
#Autowired
AuthenticationProviderImpl authenticationProvider;
#Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
// Authentication provider
.and()
.authenticationProvider(authenticationProvider)
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
However, I soon found out that this configuration causes issues with my AuthenticationProviderImpl (which implements the Spring Security AuthenticationProvider interface). When the implementation's overridden authenticate method throws a BadCredentialsException, the exact same method in that class is called again perpetually until the stack overflows. The good news is that I fixed my configuration by simply overriding configure(AuthenticationManagerBuilder builder) in the SecurityConfig and declaring my implementation of the AuthenticationProvider there instead of in configure(HttpSecurity http). Here is the fixed version:
#Configuration
#EnableWebMvcSecurity
#ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
#Autowired
AuthenticationProviderImpl authenticationProvider;
#Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder builder) {
// Configure the authentication manager WITH the authentication
// provider. Not overriding this method causes very bad things to
// happen.
builder.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
.and()
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
Though I believe my problem is solved with the fixed configuration, I still have no idea why the application was infinitely calling authenticate() when an exception was thrown by my implementation of AuthenticationProvider? I tried stepping through and examining the Spring Security classes, but I was not finding a logical answer. Thanks ahead for your expertise!
A few weeks ago I reproduced this behavior, too, see this thread on stackoverflow.
Dealing with the question I figured out that loops occur when the AuthenticationManager internally iterates through it's list of associated AuthenticationProviders, then finds a custom provider and tries to do the authentication using the provider that has been found. If the provider delegates the authentication back to the AuthenticationManager by calling authenticate(), you are in the loop. I guess your AuthenticationProviderImpl does something like that?
The order of your in the providers inside the java.util.List of the AuthenticationManager matters. The order is given by your configuration, e.g. by doing what you tried at first:
// Authentication provider
.and()
.authenticationProvider(authenticationProvider)
By changing your configuration, you influenced the internally managed list of providers attached to your manager, which in the end will solve your code.

Resources