I have some spring controller tests that worked fine before.
I recently added authentication using a userDetailsService, and now when i run controller tests it says this:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'nl.kars.lms.service.MyUserDetailsService' available:
expected at least 1 bean which qualifies as autowire candidate.
I don't understand why, because everything should be configured correctly. It only happens when running the controller tests, running the app works perfectly fine. Here are my classes.
Test case
#RunWith(SpringRunner.class)
#WebMvcTest(ActionController.class)
public class ActionControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private ActionService service;
#Test
public void testGetActions_returns_result_from_service() throws Exception {
int actionId = 1;
Action action = new Action();
action.setId(actionId);
List<Action> actionsList = Arrays.asList(action);
given(service.getActions()).willReturn(actionsList);
mvc.perform(get("/actions")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].id", Matchers.is(actionId)));
}
}
Configuration
#EnableWebSecurity
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
MyUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**")
.fullyAuthenticated()
.and().httpBasic();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
UserDetailsService
#Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private EmployeeService employeeService;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return new EmployeeDetails(employeeService.getEmployeeByEmail(email));
}
}
My question is, how do i stop the error from occuring? What am i doing wrong? I am lost at this point.
Thanks
Since you have named Your MyUserDetailsService as userDetailsService in #Service("userDetailsService") you have two options
First One :
Use #Qualifier("userDetailsService") in SecurityConfiguration.
Second Option: Autowire UserDetailsService instead of MyUserDetailsService in SecurityConfiguration.
I suggest you try the first option
#Autowired
#Qualifier("userDetailsService")
MyUserDetailsService userDetailsService;
Related
Holla developers , i'm trying to frame the spring security process on my app using maven as wrapper , and right now i'm quite confused about how could i set verifications about user being logged or not in order to trigger specific functions on one of my controllers , lets say in my SecurityConfig file i set this :
...some imports....
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
RenterService renterService;
#Autowired
UserDetailsServiceImpl userDetailsService;
#Autowired
private AuthEntryPointJwt unauthorizedHandler;
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public Authentication authentication(){
return authentication();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/cubancoder/multirenter/**","/v2/api-docs","/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
Then lets say i enable a service and its implementation to get all products through my controller
SERVICE:
...some imports...
public interface ProductService {
Map<String,Object> getAllProducts()throws GeneralException;
}
SERVICE IMPLEMENTATION:
...some imports...
#Service
public class ProductServiceImpl implements ProductService{
public static final ModelMapper modelMapper = new ModelMapper();
#Autowired
ProductRepository productRepository;
#Autowired
ProductDtos productDtos;
#Autowired
AuthenticationValidation securityApp;
#Autowired
RenterDtos renterDtos;
#Autowired
RenterRepository renterRepository;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
public Map<String,Object> getAllProducts() throws GeneralException {
Map<String,Object>dto=new HashMap<>();
List<Product>listProducts=productRepository.findAll();
if(auth==null){
dto.put("renter",null);//IF NO ONE IS LOGGED
}
else{
dto.put("renter",renterDtos.makeRenterDto(securityUser(auth)));IF THER IS A USER LOGGED
}
dto.put("list_ofProducts", listProducts.stream().map(service->productDtos.makeProductDto(service)).collect(Collectors.toList()));
return dto;
}
private Renter securityUser(Authentication auth)throws NotFoundException {
return renterRepository.findByRenterName(auth.getName()).orElseThrow(()->new NotFoundException("SError","EmailNotFound"));
}
}
No matter if user is logged or not always falls on user being null
if(auth==null){
dto.put("renter",null);//IF NO ONE IS LOGGED
}
Any idea about how could i improve this situation?
Thanks in advance!!
The problem is that there is a single instance of ProductServiceImpl which is initializing auth at startup time when there is no user in the SecurityContextHolder. Instead, you should initialize auth in the method which ensures that the auth variable is initialized at request time and there is a unique auth instance for every request (avoids race conditions). Something like this:
#Service
public class ProductServiceImpl implements ProductService{
public static final ModelMapper modelMapper = new ModelMapper();
#Autowired
ProductRepository productRepository;
#Autowired
ProductDtos productDtos;
#Autowired
AuthenticationValidation securityApp;
#Autowired
RenterDtos renterDtos;
#Autowired
RenterRepository renterRepository;
// remove auth as a member variable because it will be a shared variable across all requests and is null when the class initializes at startup
public Map<String,Object> getAllProducts() throws GeneralException {
// initialize auth as a stack variable so that it is no longer shared across requests and it is initialized when a user is in context (at request time)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
...
}
// ...
}
I'm creating a Spring Boot application with Spring Security. I've created a custom login page that uses an auth endpoint in our AuthController. My SecurityConfiguration class extends WebSecurityConfigurerAdapter.
At the moment, I'm trying to create tests for this without any results. Most of this is new to me and I'm still learning, specially testing. I'm not even sure if I've done this right at all.
Any help is appreciated.
SECURITYCONFIGURATION
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final PasswordEncoder passwordEncoder;
private final ApplicationUserService applicationUserService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/register", "/index*", "/static/**", "/*.js", "/*.json", "/*.ico").permitAll()
.antMatchers(HttpMethod.POST,"/api/auth/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
//.loginProcessingUrl("/api/auth/authenticate")
.defaultSuccessUrl("/home", true);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(applicationUserService);
return provider;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AUTHCONTROLLER
#RequiredArgsConstructor
#RestController
#RequestMapping("api/auth/")
public class AuthController {
private final UserService userService;
#PostMapping("authenticate")
public ResponseEntity<?> verifyUser(#RequestBody User user) throws Exception {
return userService.authenticateUser(user);
}
}
USERSERVICE
#Service
#RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final AuthenticationManager authenticationManager;
public ResponseEntity<?> authenticateUser(User user) throws Exception {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(user.getEmail(),user.getPassword()));
if (!authentication.isAuthenticated())
return new ResponseEntity<>(new ResponseObject("Error"), HttpStatus.UNAUTHORIZED);
else {
SecurityContextHolder.getContext().setAuthentication(authentication);
return new ResponseEntity<>(user,HttpStatus.OK);
}
}
}
TESTCLASS
#WebMvcTest(AuthController.class)
class AuthControllerTest {
User user;
#MockBean
UserService userService;
#Autowired
MockMvc mockMvc;
#BeforeEach
void setUp() {
user = User.builder()
.email("test#hotmail.com")
.password("password")
.id(1L).build();
}
#Test
void verifyUser() throws Exception {
given(userService.authenticateUser(any(User.class))).willReturn(new ResponseEntity<>(HttpStatus.OK));
mockMvc.perform(post("/api/auth/authenticate")
.contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
.andExpect(status().isOk());
}
}
ERRORS
Failed to load ApplicationContext java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfiguration' defined in file [\SecurityConfiguration.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
While attempting some tests using the Spring Boot framework, I am running into an issue with finding a Bean that the test unit depends on.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authServerApplication': Unsatisfied dependency expressed through field 'passwordEncoder'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
My test class:
#RunWith(SpringRunner.class)
#DataJpaTest
#SpringBootTest
public class UserDetailsTest {
#Autowired
private TestEntityManager entityManager;
// #MockBean
// private PasswordEncoder passwordEncoder;
#Autowired
private UserRepository userRepo;
#Test
public void test() {
OAuthUser user = null;
this.entityManager.persist(new OAuthUser("Kelly", "Marchewa", "kmarchewa", "password"));
user = userRepo.findByUserName("kmarchewa");
System.out.println(user.getPassword());
assertThat(user.getUserName()).isEqualTo("kmarchewa");
}
}
If I uncomment the #MockBean portion, the code will compile fine. However, I want to test the repository on its ability to encode and decode passwords too. To my understanding of the documentation, the #SpringBootTest annotation should be able to automatically "pick-up" the #Configuration classes. I have a main #SpringBootApplication:
#SpringBootApplication
public class AuthServerApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(AuthServerApplication.class, args);
}
#Bean
public CommandLineRunner demo(UserRepository repository) {
return(args) -> {
OAuthUser user = new OAuthUser();
user.setFirstName("Kelly");
user.setLastName("Marchewa");
user.setPassword(passwordEncoder.encode("Admin"));
user.setUserName("Admin");
// repository.save(user);
};
}
}
This Spring Boot Application depends on three other #Configuration classes: AppConfig, SecurityConfig, and AuthServerConfig. For this issue, the SecurityConfig and AppConfig classes are relevant (they include references to the PasswordEncoder bean).
AppConfig (partial)
#Configuration
public class AppConfig {
#Value("${spring.datasource.url}")
private String datasourceUrl;
#Value("${spring.datasource.driverClassName}")
private String dbDriverClassName;
#Value("${spring.datasource.username}")
private String dbUsername;
#Value("${spring.datasource.password}")
private String dbPassword;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/// more code here
}
SecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private OAuthUserDetailsService userService;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
// Hash password
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName("test")
.and()
.csrf()
.disable();
}
}
The UserRepository class is very simple:
public interface UserRepository extends CrudRepository<OAuthUser, Long> {
public OAuthUser findByUserName(String name);
}
How can I ensure all required beans are found for my tests?
Thanks.
EDIT:
I receive the same error if I attempt to #Autowire the bean in my test class.
#Autowired
private PasswordEncoder passwordEncoder;
The problem is #DataJpaTest this annotation should be used only for Data repositories test and not full integration (which is what you are doing) as because it only persistence beans are created in context and not all you beans (the reason bean can not be found). What you need to do is use only #SpringBootTest and declared h2 as testing dependency, in that way a full recreation of your application will be created using in memory database
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();
}
}
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.