i was working with spring 2.x.x without any problem until today. Now im trying to create a rest API with spring security enabled (spring boot 3.3.1) and i want to use HttpBasic authentication. So i just set up my project and started to test security things. However, spring is throwing this exception all the time and im not being able to find out what is the source of this.
Here is my security configuration:
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfigurer {
private HttpBasicFilter httpBasicFilter;
private InMemoryUserDetailsManager inMemoryUserDetailsManager;
private PasswordEncoder encoder;
@Bean
public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf(AbstractHttpConfigurer::disable)
.sessionManagement((configurer) -> {
configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
.authenticationManager(authenticationManager())
.authorizeHttpRequests(
requests -> requests
.requestMatchers("api/**").authenticated()
.requestMatchers("api/v1/auth/**").permitAll()
)
.userDetailsService(inMemoryUserDetails())
.addFilterBefore(httpBasicFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin(AbstractHttpConfigurer::disable)
.exceptionHandling(customizer -> {
customizer.authenticationEntryPoint((request, response, exception) -> {
exception.printStackTrace();
response.setStatus(401);
response.setHeader("Content-Type", "application/json; charset=UTF-8");
new ObjectMapper().writeValue(response.getOutputStream(), exception.getMessage());
});
})
.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
}
@Bean
public InMemoryUserDetailsManager inMemoryUserDetails() { // just for testing purpose
if(inMemoryUserDetailsManager == null) {
UserDetails user = User
.withUsername("admin")
.password(passwordEncoder().encode("admin321"))
.roles("ADMIN")
.build();
inMemoryUserDetailsManager = new InMemoryUserDetailsManager(user);
}
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
if(encoder == null) encoder = new BCryptPasswordEncoder(8);
return encoder;
}
@Bean
public AuthenticationManager authenticationManager() {
AuthenticationProvider provider = new CustomAuthenticationProvider(inMemoryUserDetails(), passwordEncoder());
return provider::authenticate;
}
@Bean
public HttpBasicFilter httpBasicFilter() {
if(httpBasicFilter == null) httpBasicFilter = new HttpBasicFilter(authenticationManager());
return httpBasicFilter;
}
}
And this is my filter:
public class HttpBasicFilter extends BasicAuthenticationFilter {
public HttpBasicFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String username, password;
String authHeader = request.getHeader("Authorization");
if(StringUtils.isBlank(authHeader) || !StringUtils.startsWith(authHeader, "Basic ")) throw new AuthenticationException("Full authentication is required to access this resource");
String usernamePassword = new String(Base64.getDecoder().decode(authHeader.replace("Basic ", "")));
if(StringUtils.isBlank(usernamePassword) || !usernamePassword.contains(":") || usernamePassword.split(":").length != 2) throw new AuthenticationException("Invalid authorization token");
String[] credentials = usernamePassword.split(":");
username = credentials[0];
password = credentials[1];
getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(username, password, List.of()));
// Proceed with the request
chain.doFilter(request, response);
}
}
And here is my authenticationProvider:
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final InMemoryUserDetailsManager inMemoryUserDetailsService;
private final PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
UserDetails user = inMemoryUserDetailsService.loadUserByUsername(username);
if(user == null) throw new BadCredentialsException("Invalid credentials");
Authentication authenticationResult = new UsernamePasswordAuthenticationToken(username, password, List.of());
if (passwordEncoder.matches(password, user.getPassword())) {
SecurityContextHolder.getContext().setAuthentication(authenticationResult); // it comes to this line when i debug, so authentication is being done successfully
} else {
throw new BadCredentialsException("Invalid credentials");
}
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.equals(authentication);
}
}
i am sending the request to this address: /api/v1/auth/signup so actually there shouldn’t be any authentication logic, but this is for another topic, my main problem is some spring filters does not recognize (or overrides) my authentication.
My Postman Request:
the full form of exception:
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
at org.springframework.security.web.access.ExceptionTranslationFilter.handleAccessDeniedException(ExceptionTranslationFilter.java:199)
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:178)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:147)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:91)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:632)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:410)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:330)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:267)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:362)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:222)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:1570)
What i tried:
-
Use DaoAuthenticationProvider by extending it from my CustomAuthenticationProvider
-
Change the position of HttpBasic filter (i tried to put it before or after other filters)
What i expect:
- If i set authentication field of spring’s security context, it should recgonize this and let the user pass into application