1. Overview
First things first - I am pretty new to Spring Security so if you see something trivial, please keep that in mind I am trying to create a custom way for my server side project to authenticate incoming requests following this tutorial.
2. Problem
The authentication works for every incoming request. I want it to work only for specified ones, just like when using basic authentication.
3. Code
Filter
@Component
@RequiredArgsConstructor
public class MyCustomAuthenticationFilter implements Filter {
private final AuthenticationManager authenticationManager;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String authorization = httpRequest.getHeader("CustomAuth");
MyCustomAuthentication myCustomAuthentication = new MyCustomAuthentication(authorization, null);
Authentication authResult = authenticationManager.authenticate(myCustomAuthentication);
if (authResult.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authResult);
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
Manager / config
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public APIKeyAuthenticationProvider apiKeyAuthenticationProvider() {
return new APIKeyAuthenticationProvider();
}
public MyCustomAuthenticationFilter myCustomAuthenticationFilter() throws Exception {
return new MyCustomAuthenticationFilter(authenticationManagerBean());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(apiKeyAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().permitAll()
.and()
.addFilterAt(myCustomAuthenticationFilter(), BasicAuthenticationFilter.class)
.csrf().disable();
}
}
Provider
public class APIKeyAuthenticationProvider implements AuthenticationProvider {
private final String secretKey = "password";
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String requestKey = authentication.getName();
if (requestKey.equals(secretKey)) {
MyCustomAuthentication fullyAuthenticated = new MyCustomAuthentication(null, null, null);
return fullyAuthenticated;
} else {
throw new BadCredentialsException("Header value is not correct");
}
}
/**
* If authentication type is MyCustomAuthentication, then
* apply this provider
* @param authentication
* @return
*/
@Override
public boolean supports(Class<?> authentication) {
return MyCustomAuthentication.class.equals(authentication);
}
}
Authentication
public class MyCustomAuthentication extends UsernamePasswordAuthenticationToken {
public MyCustomAuthentication(Object principal, Object credentials) {
super(principal, credentials);
}
public MyCustomAuthentication(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
4. Question
What do I need to change to make this custom filter authenticate only endpoints specified in the configure
method?
Thank you in advance for any help ✌️
5. Versions
- java - 11
- spring boot - 2.6.6
- spring framework - 5.3.18