Spring Boot Security : java.lang.IllegalArgumentException: A UserDetailsService must be set - spring-boot

Below is security config class:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
CustomUserDetailService userDetailsService;
#Bean
public DaoAuthenticationProvider authProvider() {
CustomAuthProvider authProvider = new CustomAuthProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
return authProvider;
}
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests()
.mvcMatchers("/favicon.ico", "/signup", "/cdn.jsdelivr.net", "/cdn.jsdelivr.net/**").permitAll()
.anyRequest().authenticated().and().formLogin(form -> form.loginPage("/login").permitAll())
.authenticationManager(new ProviderManager(List.of(authProvider()))).csrf().disable().build();
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
#Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
Here is my DaoAuthenticationProvider:
#Service
public class CustomAuthProvider extends DaoAuthenticationProvider {
Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
private AuthUserRepo authUserRepo;
#Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
logger.info("CustomAuthProvider authentication ::::: {} ", authentication);
logger.info("CustomAuthProvider authentication.getPrincipal() ::::: {} ",
authentication.getPrincipal().toString());
final String name = authentication.getName();
logger.info("CustomAuthenticationProvider ::::: " + authentication.getCredentials().toString());
final String password = authentication.getCredentials().toString();
logger.info("CustomAuthenticationProvider ::::: " + name);
if ((name == null || password == null)) {
throw new BadCredentialsException("Invalid username or password");
}
Optional<AuthUser> authUser = authUserRepo.findByEmail(name);
if (authUser.isEmpty()) {
throw new BadCredentialsException("Invalid username or password");
}
final Authentication result = super.authenticate(authentication);
return new UsernamePasswordAuthenticationToken(authUser.get(),
result.getCredentials().toString(), result.getAuthorities());
}
}
Here is my CustomUserDetailService:
#Service
public class CustomUserDetailService implements UserDetailsService {
Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
AuthUserRepo authUserRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
logger.info("CustomUserDetailService -> UserName :::: {}", username);
Optional<AuthUser> savedUser = authUserRepo.findByEmail(username);
if (savedUser.isEmpty()) {
throw new UsernameNotFoundException("No user found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(savedUser.get().getEmail(),
savedUser.get().getPassword(), true, true, true, true, getAuthorities());
}
private Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
final List<GrantedAuthority> authorities = new ArrayList<>();
List<String> roles = Arrays.asList("Associate", "Manager");
for (String string : roles) {
authorities.add(new SimpleGrantedAuthority(string));
}
return authorities;
}
}
I am not java.lang.IllegalArgumentException: A UserDetailsService must be set. I have set UserdetailService in my security config.
Below is exception stacktrace:
M 16-Sept-2022 02:14:32.372 [restartedMain] ERROR [org.springframework.boot.SpringApplication:824] - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customAuthProvider' defined in file [/Users/itadminsalesken/Downloads/spring5login/target/classes/security/spring5login/conf/CustomAuthProvider.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A UserDetailsService must be set
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at security.spring5login.Spring5loginApplication.main(Spring5loginApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalArgumentException: A UserDetailsService must be set
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.doAfterPropertiesSet(DaoAuthenticationProvider.java:85)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.afterPropertiesSet(AbstractUserDetailsAuthenticationProvider.java:119)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 21 common frames omitted

Have you tried initializing UserDetailsService in securityConfig class with #Bean? It might have causing problems since #Configuration beans are created before #Service beans.

Related

Spring Security work well when runtime, but got error while ddoing gradle build

I've been make WebSecurity like this:
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private final Environment environment;
private final UsersService usersService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(Environment environment, UsersService usersService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.environment = environment;
this.usersService = usersService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(usersService)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().disable();
http.authorizeRequests()
.antMatchers("/users/**")
.hasIpAddress(environment.getProperty("app.gateway-ip"))
.and()
.addFilter(authenticateUser());
}
private AuthenticationFilter authenticateUser() throws Exception {
AuthenticationFilter authenticationFilter = new AuthenticationFilter(environment, usersService, authenticationManager());
authenticationFilter.setFilterProcessesUrl(environment.getProperty("app.auth.login.url-path"));
return authenticationFilter;
}
}
and an AuthenticationFilter like this:
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final Environment environment;
private final UsersService usersService;
public AuthenticationFilter(Environment environment, UsersService usersService, AuthenticationManager authenticationManager) {
this.environment = environment;
this.usersService = usersService;
super.setAuthenticationManager(authenticationManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRequestModel credentials = new ObjectMapper()
.readValue(request.getInputStream(), LoginRequestModel.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
credentials.getEmail(),
credentials.getPassword(),
new ArrayList<>()
)
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String username = ((User) authResult.getPrincipal()).getUsername();
UserDto userDetails = usersService.getUserDetailsByEmail(username);
String token = Jwts.builder()
.setSubject(userDetails.getUserId())
.setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(environment.getProperty("app.auth.token.expiration-time"))))
.signWith(SignatureAlgorithm.HS512, environment.getProperty("app.auth.token.secret"))
.compact();
response.addHeader("token", token);
response.addHeader("userId", userDetails.getUserId());
}
}
It all can work well in runtime, but when I tried to build it, the build failed because the test is error. When I try to run the test, I get this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: Pattern cannot be null or empty
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.15.jar:5.3.15]
My test class only contain this code:
#SpringBootTest
class UserServiceApplicationTests {
#Test
void contextLoads() {
}
}
What I've done:
I've done adding some jaxb dependencies, but still not working
In your application you call
authenticationFilter.setFilterProcessesUrl(
environment.getProperty("app.auth.login.url-path")
);
Your build environment does not have the property app.auth.login.url-path.
The Framework tries to create an AntPathRequestMatcher with the patter provided but the pattern is empty because the property does not exist.

Exception with auth

I have config
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtTokenProvider jwtTokenProvider;
private static final String ADMIN_ENDPOINT = "/api/v1/admin/**";
private static final String LOGIN_ENDPOINT = "/api/v1/auth/login";
#Autowired
public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(LOGIN_ENDPOINT).permitAll()
.antMatchers(ADMIN_ENDPOINT).hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(jwtTokenProvider));
}
}
And rest controller
#RestController
#RequestMapping(value = "/api/v1/auth/")
public class AuthenticationRestControllerV1 {
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
private final UserService userService;
#Autowired
public AuthenticationRestControllerV1(AuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider, UserService userService) {
this.authenticationManager = authenticationManager;
this.jwtTokenProvider = jwtTokenProvider;
this.userService = userService;
}
#PostMapping("login")
public ResponseEntity login(#RequestBody AuthenticationRequestDto requestDto) {
try {
String username = requestDto.getUsername();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, requestDto.getPassword()));
User user = userService.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User with username: " + username + " not found");
}
String token = jwtTokenProvider.createToken(username, user.getRoles());
Map<Object, Object> response = new HashMap<>();
response.put("username", username);
response.put("token", token);
return ResponseEntity.ok(response);
} catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid username or password");
}
}
}
If I send POST query through POSTMAN, there are error
java.lang.StackOverflowError: null
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at com.sun.proxy.$Proxy134.authenticate(Unknown Source) ~[na:na]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:501) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor52.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
Problem is situated in controller, in this line:
authenticationManager.authenticate(new
UsernamePasswordAuthenticationToken(username,requestDto.getPassword()));
How to fix this problem?

Testing spring controller with spring security enabled fails to load application context

I have added spring security to my app and now my controller unit tests have stopped working, failing to load application context. The security I have added generates a jwt token that must be provided to access my API endpoints. The error seems to be it cannot find a qualifying bean for UserDetailsService. Any help would be appreciated. My set up follows:
JwtUserDetailsService:
#Service
public class JwtUserDetailsService implements UserDetailsService {
#Autowired
private UserRepositoryJWT userRepository;
#Autowired
private PasswordEncoder bcryptEncoder;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntityJWT user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(),
new ArrayList<>());
}
}
Security Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecuirtyConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
#Bean
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and()
.csrf().disable()
.authorizeRequests().antMatchers("/authenticate", "/register").permitAll().
anyRequest().authenticated().and(). exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
My unit test for a controller that the user must be authenticated to hit is:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = ReportingController.class)
public class ReportingController_UT {
#Autowired
private MockMvc mvc;
#MockBean
private ReportingService reportingService;
#Test
public void getDailyTestInfo_WithBuildingIDInURL_ShouldCallgetDailyReportInfoMethod() throws Exception {
when(reportingService.getDailyReportInfo(anyInt())).thenReturn(anyList());
mvc.perform(get(GET_DAILY_REPORTS_URL).characterEncoding(UTF_8)
.contentType(MediaType.APPLICATION_JSON));
verify(reportingService,times(1)).getDailyReportInfo(anyInt());
}
Running the test throws the following exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.postProcessFields(MockitoTestExecutionListener.java:95)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.injectFields(MockitoTestExecutionListener.java:79)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.api.jwt.JwtUserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:636)

Spring boot 2+ Could not Autowire. There is more than one bean of 'UserDetailsService'

Hello Everyone i'm new in spring security and jwt. I'm implementing Jwt in my spring boot project to secure user login and i'm using spring boot 2.1.5
and i don't know much about new bean restriction in spring boot 2+ .
I need some help .. here i'm trying to #Autowired UserDetailsService and code run fine ..and result is also fine.. but intellij shows error at
#Autowired UserDetailsService jwtUserDetailsService
saying ... Could not autowire. There is more than one bean of UserDetailsService type.
Can anyone explain me what what happens wrong here why i can't autowired and why and what are the Autowired restriction in spring boot 2+ ?
And thanks in advance
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private JwtFilter jwtFilter;
#Autowired
private UserDetailsService jwtUserDetailsService; // here i got error only
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/api/user/add", "/generate").permitAll().anyRequest().authenticated().and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
my customUserDetailService is
#Service
public class JwtUserDetailService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user != null) {
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username does't exists");
}
}
}
My JwtController class which expose restend point to generate jwt token
#CrossOrigin
#RestController
public class JwtController {
#Autowired
private JwtUtils jwtUtils;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtUserDetailService jwtUserDetailService;
#PostMapping(value = "/generate")
public ResponseEntity<?> generateToken(#RequestBody JwtRequest jwtRequest) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtRequest.getUsername(),
jwtRequest.getPassword()));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVAILD_CREDENTIALS", e);
}
final UserDetails userDetails = jwtUserDetailService.loadUserByUsername(jwtRequest.getUsername());
final String token = jwtUtils.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
}
My JwtFilter Class
#Component
public class JwtFilter extends OncePerRequestFilter {
#Autowired
private JwtUserDetailService jwtUserDetailService;
#Autowired
private JwtUtils jwtUtils;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtils.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.jwtUserDetailService.loadUserByUsername(username);
if (jwtUtils.validate(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Other thing as just normal like entity, repository, and some secured restend points
UserDetailsService was provided by spring.
To Autowire you need to configure it with.
#Bean
public UserDetailsService getUserDetails(){
return new JwtUserDetailService(); // Implementation class
}
If you are not interested in Bean Configuration.
you can autowire JwtUserDetailService directly.
#Autowired
private JwtUserDetailService jwtUserDetailsService;
I got the same error in another context. The reason was the Idea donĀ“t know which bean of type 'UserDetailsService' to use.
My solution is through annotation Qualifier:
#Qualifier("beanNameWhichYouWantUse")
#Autowired
private UserDetailsService jwtUserDetailsService;
If use Idea: give mouse point on the error, select from context menu:
"More actions" -> "Add qualifier"
and finally select the bean
You can put this code in application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration

OAuth2 An Authentication object was not found in the SecurityContext

I am trying to configure the spring security for my application. The authentication is up and running, and I am able to generate the oauth tokens using the oauth/token url. Now when I use this token I am getting the error
17:47:08,668 DEBUG SessionManagementFilter:124 - Requested session ID Lna1JBtS5foU2qDaGONIzBcGgvt94FTSneANgG77 is invalid.
17:47:08,670 DEBUG FilterSecurityInterceptor:219 - Secure object: FilterInvocation: URL: /api/user/update; Attributes: [hasAnyRole('ROLE_ANONYMOUS, USER')]
17:47:08,671 DEBUG ExceptionTranslationFilter:164 - Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:223)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
Below are my configuration
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private MyAuthenticationProvider myAuthenticationProvider;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token", "/api/signup").permitAll()
.anyRequest().hasAnyRole("ANONYMOUS, USER");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/signup");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
public TokenStoreUserApprovalHandler userApprovalHandler() {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore());
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore());
return store;
}
}
AuthorizationServer class
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM = "ABCDEF";
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("user").secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT").scopes("read", "write", "trust") //
.accessTokenValiditySeconds(60 * 60 * 24 * 1) // Access token is only valid for 1 days.
.refreshTokenValiditySeconds(60 * 60 * 24 * 30); // Refresh token is only valid for 30 days.
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenEnhancer(tokenEnhancer()).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").realm(REALM);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new MicroInvestTokenEnhancer();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123456789");
return converter;
}
}
Authentication Provider
#Component("myAuthenticationProvider")
public class MyAuthenticationProvider implements AuthenticationProvider {
#Autowired
private LoginService loginService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
MicroInvestAuthenticationToken auth = null;
if (authentication != null) {
final String username = authentication.getPrincipal().toString();
final String password = authentication.getCredentials().toString();
LoginResponse user = loginService.login(username, password);
if (user != null) {
final List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("USER"));
auth = new MicroInvestAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), grantedAuthorities);
auth.setUser(user);
}
}
return auth;
}
#Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class).isAssignableFrom(authentication);
}
}

Resources