Spring OAuth2 Custom Authentication Manager ClassCastException - java

i've a big problem and no idea how to solve it...
I need to use customAuthenticationManager for third party log-in in my spring boot application, but when i declare custom authenticator i get :
Handling error:
ClassCastException, java.lang.String cannot be cast to com.nexus.demooauth.models.User
If i use default authentication manager (the one that comes with spring boot) everything works fine.
Here is Websecurity.java
#Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
AuthorizationServerConfig.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
UserDetailsService customUserDetailsService;
#Autowired
DataSource dataSource;
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public PasswordEncoder passwordEncoder() {
return new Plainencoder();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
//configurer.userDetailsService(customUserDetailsService);
configurer.authenticationManager(authenticationManager);
configurer.tokenEnhancer(tokenEnhancer());
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("gigy").secret("secret").accessTokenValiditySeconds(8400)
.scopes("read", "write").authorizedGrantTypes("password", "refresh_token");
}
CustomAuthenticationManager.java
#Service
public class CustomAuthenticationManager implements AuthenticationManager{
private final Logger logger = LoggerFactory.getLogger(CustomAuthenticationManager.class);
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String pw = authentication.getCredentials().toString();
logger.info("was here" + username.toString() + " , " + pw.toString());
return new UsernamePasswordAuthenticationToken(username, pw, authentication.getAuthorities());
}
It actually prints in logger
2018-05-15 17:58:34.453 INFO 7212 --- [nio-8089-exec-1] c.n.d.s.CustomAuthenticationManager : was heretest , test
When debugging it breaks when returning new UsernamePasswordAuthenticationToken in some obfuscated class.

Actually found the anserw.
The problem was in CustomTokenEnhancer that was making this invalid conversion.

Related

Prevent spring from injecting the default AuthenticationManager

I'm trying to create a spring security configuration with two different AuthenticationProviders and exposing a rest interface to verify credentials (this is just used in the dev environment and will be replaced by an oAuth service in prod.) But when I inject the AuthenticationManager into the Controller, spring creates a default AuthenticationManager and injects it into the RestController. How can I make spring inject the AuthenticationManager configured in the WebSecurityConfigurationAdapter? I'm using spring-boot-starter-security:1.5.7.RELEASE. Here is my security configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#Configuration
public class LocalWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private final DevUserDetailsService devUserDetailService;
private final ServiceUserDetailService serviceUserDetailService;
#Autowired
public LocalWebSecurityConfigurationAdapter(DevUserDetailsService devUserDetailService, ServiceUserDetailService serviceUserDetailService) {
this.devUserDetailService = devUserDetailService;
this.serviceUserDetailService = serviceUserDetailService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().antMatchers("/api/public/**").permitAll()
.antMatchers("/api/login").permitAll()
.antMatchers("/api/**").fullyAuthenticated()
.anyRequest().permitAll()
.and().exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint())
.and().httpBasic();
}
#Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(devUserDetailService);
DaoAuthenticationProvider serviceUserAuthProvider = new DaoAuthenticationProvider();
serviceUserAuthProvider.setUserDetailsService(serviceUserDetailService);
serviceUserAuthProvider.setPasswordEncoder(passwordEncoder());
auth.authenticationProvider(serviceUserAuthProvider);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
And here is my RestController:
#RestController
#RequestMapping("/api/login")
public class LoginController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final AuthenticationManager authenticationManager;
public LoginController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#RequestMapping(method = RequestMethod.POST)
public Map<String, String> login(#RequestBody Map<String, String> body) {
String user = body.get("user");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, body.get("password"));
try {
authenticationManager.authenticate(token);
return Collections.singletonMap("status", "ok");
} catch (BadCredentialsException e) {
return Collections.singletonMap("status", "bad credentials");
} catch (AuthenticationException e) {
log.warn("Could not authenticate user {} because {}.", user, e.getMessage(), e);
return Collections.singletonMap("status", "general error");
}
}
}
And since you guys are probably experts in spring, is there a best practice to create different security configurations depending on the environment (using the profile) the code is running on without creating redundant code? I tried a super class, but spring didn't like that a lot.
I finally found a solution. By using configureGlobal inside my configuration class the AuthenticationManager gets shared across all spring managed Components.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DevUserDetailsService devUserDetailService,
#Qualifier("serviceUserAuthenticationProvider") AuthenticationProvider serviceUserAuthProvider) throws Exception {
auth.userDetailsService(devUserDetailService);
auth.authenticationProvider(serviceUserAuthProvider);
}
For reusing configuration, I still didn't find a good solution. Creating an abstract “super configuration” for all the common configuration is creating troubles as soon as a method is annotated with #Bean and creating multiple WebSecurityConfigurerAdapter results in one overwriting the other, so if there is a best practice, I'm still interested in a proper solution. I've managed to do what I wanted, but it still feels like a little of a hack to me. For anyone stumbling across a similar issue I hope this helps a little.
Declare the bean in LocalWebSecurityConfigurationAdapter:
#Bean(name="appAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
and inject it other components just like any other bean:
public LoginController(#Qualifier("appAuthenticationManager") AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}

Spring Security Prevent Multiple Login For Same User Not Working

I am working with a Spring MVC application with Spring Security 4.x as security framework. Now I am trying to prevent multiple login for the same user on different browser like Firefox and Google Chrome, but I don't know why it's not working for me. My implementation is as below:
#ComponentScan("com.application")
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
#Qualifier("secureUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
private LoginSuccessHandler loginSuccessHandler;
#Autowired
private LoginFailHandler loginFailHandler;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(UrlMapping.getLoginUrl(), UrlMapping.getSignInUrl()).permitAll()
.anyRequest().authenticated().accessDecisionManager(accessDecisionManager()).and().formLogin()
.loginPage(UrlMapping.getLoginUrl()).loginProcessingUrl(UrlMapping.getSignInUrl())
.failureUrl(UrlMapping.getSignInUrl()).failureHandler(loginFailHandler)
.successHandler(loginSuccessHandler).usernameParameter("email").passwordParameter("password").and()
.exceptionHandling().accessDeniedPage(UrlMapping.getUnauthorizedUrl()).and().logout()
.logoutSuccessUrl("/").deleteCookies("JSESSIONID", "SESSION").invalidateHttpSession(true).and()
.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
}
#Bean
PasswordEncoder encoder() {
return new BCryptPasswordEncoder(15);
}
#SuppressWarnings("unchecked")
#Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(new WebExpressionVoter(),
new RoleVoter(), new AuthenticatedVoter(), new MinuteBasedVoter());
return new UnanimousBased(decisionVoters);
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
Anyone please help or tell me if something is missing.

Refresh token call fails using spring security an oauth2 with error: UserDetailsService is required

I am using Spring Security OAuth2 for authorizations. When trying to refresh the token I get an error: UserDetailsService is required (interestingly I get this error only on unix machines and not on windows). I am using Spring OAuth2 version 2.0.7.
For some reason the AuthenticationManager in the DefaultTokenService is not empty and it tries to authenticate the user to check if he still exists. I think it gets initialized because of some spring security vs. spring oauth2 configuration problems.
I am not using any custom UserDetailsService, hence it should not authenticate the users at this point. However, when I debug it I see that it tries to use one from the WebSecurityConfigurerAdapter and gets to this error. Even if I provide my custom dummy UserDetailsService, it is not using that one, but tries to use the other one, which is null. Am I missing here something? I can not find out why is this happening?
Here is my Oauth2 configuration
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private MySpringTokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private MyClientDetailsServiceImpl clientDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
Here is my Spring security configuration
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll()
.antMatchers("/login.jsp", "/login").permitAll()
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
.sessionManagement().sessionFixation().none();
// #formatter:on
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/index*", "/myRest/events/**", "/events/**", "/myRest/events", "/events", "/swagger/**", "/kibana/**",
"/elastic/**", "/version/**", "/api-docs/**", "/js/**", "/oauth/uncache_approvals", "/oauth/cache_approvals");
}
}
Authorization server endpoint needs UserDetailsService. In your OAuth2Config class configure user details service like the following:
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
}
You can also configure it in WebSecurityConfigurerAdapter:
#Autowired
private AuthorizationServerEndpointsConfiguration endpoints;
#Override
protected void configure(HttpSecurity http) throws Exception {
if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
UserDetailsService userDetailsService = http.getSharedObject(UserDetailsService.class);
endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
}
// #formatter:off
http
.authorizeRequests()
.antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll()
.antMatchers("/login.jsp", "/login").permitAll()
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
.sessionManagement().sessionFixation().none();
// #formatter:on
}
Adding on to #VijayaNandwana's answer and considering #FilipMajernik's comment,
I created a class for OAuthConfig and made the order less than the class which extends WebSecurityConfigurerAdapter.
#Configuration
#Order(1)
public class OAuthConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private JdbcTemplate jdbcTemplate;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(jdbcTemplate.getDataSource());
}
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
}
}
And Class which extends WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
#Order(2)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//Configurations
}
If implementing custom DefaultTokenServices, we don't need UserDetailsService.
#Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// ...
.tokenServices(tokenServices(endpoints));
}
public AuthorizationServerTokenServices tokenServices(final AuthorizationServerEndpointsConfigurer endpoints) {
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
// ...
tokenServices.setAuthenticationManager(
new ProviderManager(List.of(new MyCustomAuthProvider())));
return tokenServices;
}
}
The commit message says:
Add AuthenticationManager to default token services
So that it can be used to check user account changes in a refresh
token grant. If a global UserDetailsService is available it will be
used as a default (e.g. if user has a GlobalAuthenticationConfigurer).
It works by constructing a PreAuthenticationAuthenticationProvider
and using that the authenticate the user in DefaultTokenServices.
To customize that process, users can create their own
DefaultTokenServices and inject an AuthenticationManager.
Fixes gh-401
The authorisation endpoint requires a UserDetailsService.
Add this:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
endpoints.userDetailsService(userDetailsService);
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled();
}
}

How do I set up PreAuthenticationAuthenticationProvider?

I've been trying to get OAuth 2 working for my application but I continue running into configuration-related errors, specifically involving authentication tokens. The application is set up to act as both authorization and resource server. I've successfully configured it to issue tokens using password grant type, with an in-memory token store. However, every time I try to send requests for restricted resources, I get errors saying:
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
So, I tried setting up a PreAuthenticationAuthenticationProvider in my configuration:
#Autowired
private UserDetailsManager userManager;
#Bean
public AuthenticationProvider preAuthenticationAuthenticationProvider() {
PreAuthenticatedAuthenticationProvider authenticationProvider =
new PreAuthenticatedAuthenticationProvider();
UserDetailsByNameServiceWrapper userDetailsWrapper = new UserDetailsByNameServiceWrapper(userManager);
authenticationProvider.setPreAuthenticatedUserDetailsService(userDetailsWrapper);
return authenticationProvider;
}
However, I'm getting NullPointerException in weird places, like:
java.lang.NullPointerException: null
at org.springframework.security.authentication.AccountStatusUserDetailsChecker.check(AccountStatusUserDetailsChecker.java:17) ~[spring-security-core-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]
I'm wondering what the simplest configuration for this is, and why I need it in the first place? Is it because I have #PreAuthorize annotations?
Here's how I set up the resource server:
#Configuration
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore).authenticationManager(authenticationManager);
}
#Override
public void configure(HttpSecurity http) throws Exception {
//http configuration
}
}
The TokenStore is just an instance of InMemoryTokenStore and AuthenticationManager is set up this way:
#Configuration
protected static class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
protected UserDetailsManager userManager;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(preAuthenticationAuthenticationProvider())
.userDetailsService(userManager).passwordEncoder(PASSWORD_ENCODER);
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Bean
protected AuthenticationProvider preAuthenticationAuthenticationProvider() {
PreAuthenticatedAuthenticationProvider authenticationProvider =
new PreAuthenticatedAuthenticationProvider();
UserDetailsByNameServiceWrapper userDetailsWrapper = new UserDetailsByNameServiceWrapper(userManager);
authenticationProvider.setPreAuthenticatedUserDetailsService(userDetailsWrapper);
return authenticationProvider;
}
}
What I was missing are AuthorizationServiceTokenServices and ResourceServerTokenServices. Both these interfaces are implmented by Spring's DefaultTokenServices.
#Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setAuthenticationManager(authenticationManager);
return tokenServices;
}
In the authorization server configuration (AuthorizationServiceConfigurerAdapter), I have the following setup:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenServices(tokenServices()).authenticationManager(authenticationManager);
}
In the resource server configuration (ResourceServerConfigurerAdapter):
#Autowired
private DefaultTokenServices tokenServices;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices);
}
With all these components, my app works without any PreAuthenticationAuthenticationProvider bean defined.

Spring Security, Boot: replace default DaoAuthenticationProvider

I am trying to add user ip verification during login process. If ip address of the user is not in the database the application should reject the authentication.
The problem: Given the setup below it turns out that auth.authenticationProvider() is not replacing the default DaoAuthenticationProvider, but adds UserIpAuthenticationProvider as a first AuthenticationProvider in the list.
In the case when username/password combination is incorrect the framework ends up calling UserDetailsService.loadUserByUsername() twice, once from UserIpAuthenticationProvider, another time from internal DaoAuthenticationProvider which throws the final BadCredentialsException().
The question: is there any setting that can be set in Spring Boot so that Spring Security does not add it's own internal instance DaoAuthenticationProvider, but only use my UserIpAuthenticationProvider, which already has all the necessary functionality (perhaps by somehow replacing AuthenticationManagerBuilder to be able to override userDetailsService() method?).
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T> userDetailsService(
T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return apply(new DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>(userDetailsService));
}
Configuration: In my understanding, UserDetailsService is supposed to provide all the necessary details about the user so that AuthenticationProvider can make a decision whether the authentication was successful or not.
Since all the necessary information is loaded from the database, it seems natural to extend DaoAuthenticationProvider and add an additional verification in overriden additionalAuthenticationChecks() method (white-listed IP list is in the database, so they are loaded as part of the user object in IpAwareUser).
#Named
#Component
class UserIpAuthenticationProvider extends DaoAuthenticationProvider {
#Inject
public UserIpAuthenticationProvider(UserDetailsService userDetailsService)
{
...
}
#SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
super.additionalAuthenticationChecks(userDetails, authentication);
WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
IpAwareUser ipAwareUser = (IpAwareUser) userDetails;
if (!ipAwareUser.isAllowedIp(details.getRemoteAddress()))
{
throw new DisabledException("Login restricted from ip: " + details.getRemoteAddress());
}
}
}
This is injected into SecurityConfiguration:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilter(authenticationFilter);
http.authorizeRequests()
.antMatchers("/", "/javascript/**", "/css/**").permitAll()
.antMatchers("...").access("...")
.anyRequest().authenticated()
.and().formLogin().loginPage("/").permitAll()
.and().logout().invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll()
.and().csrf().disable()
;
}
#Inject
private UserDetailsService userDetailsService;
#Inject
private UserIpAuthenticationProvider userIpAuthenticationProvider;
#Inject
private JsonUsernamePasswordAuthenticationFilter authenticationFilter;
#Bean
public JsonUsernamePasswordAuthenticationFilter authenticationFilter() {
return new JsonUsernamePasswordAuthenticationFilter();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(userIpAuthenticationProvider);
auth.userDetailsService(userDetailsService);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() throws Exception {
return new JsonAuthenticationSuccessHandler();
}
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() throws Exception {
return new JsonAuthenticationFailureHandler();
}
}
and application configuration:
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackageClasses = {SecurityConfiguration.class, DataController.class, DaoService.class})
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application;
}
}
Any guidance on this will be much appreciated.
The comments on the question contained the answer:
#ArunM: your project gave me an idea: I do not need to call auth.userDetailsService(userDetailsService); in SecurityConfiguration.configure(), which will prevent creation of internal DaoAuthenticationProvider! My UserIpAuthenticationProvider can get instance of UserDetailsService via injection.
The AuthenticationManagerBuilder.userDetailsService method does not only set the default UserDetailsService but also applies a DaoAuthenticationConfigurer which registers the DaoAuthenticationProvider.
If you want a customized DaoAuthenticationProvider, pass the UserDetailsService to the provider in the constructor or inject it. And to prevent the default DaoAuthenticationProvider from being registered, don't call AuthenticationManagerBuilder.userDetailsService.
This is also mentioned in this Spring Security issue.
Defining your own DaoAuthenticationProvider
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
return new UserIpAuthenticationProvider();
}
should replace the Spring Boot default instance (not that the bean type is DaoAuthenticationProvider and not UserIpAuthenticationProvider)

Categories