I need to configure the Spring Security so that users that have either Basic Auth or API Key can access the API in the absence of one other. The below code works for Basic Auth but when I switch to API Key in Postman, I can not access the API using the correct API key/value added to the Header in Postman in the Authorization tab and I am getting 401.
However, when I just use ApiKeyWebSecurityConfigurerAdapter by itself, I can access the API even with the wrong API key/value pair. Any help would be appreciated.
Note: I used this and https://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/html5/#multiple-httpsecurity as reference.
Security Config:
@EnableWebSecurity
public class MultiHttpSecurityConfig {
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.userDetailsService(userDetailsService())
.httpBasic(Customizer.withDefaults());
}
@Bean
public UserDetailsService userDetailsService() {
return new JpaUserDetailService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
@Configuration
public static class ApiKeyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Value("${myApp.http.auth-token-header-name}")
private String principalRequestHeader;
@Value("${myApp.http.auth-token}")
private String principalRequestValue;
@Override
protected void configure(HttpSecurity http) {
http
.csrf()
.disable();
APIKeyAuthFilter filter = new APIKeyAuthFilter(principalRequestHeader);
filter.setAuthenticationManager(new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
if (!principalRequestValue.equals(principal)) {
throw new BadCredentialsException("The API key was not found or not the expected value.");
}
authentication.setAuthenticated(true);
return authentication;
}
});
}
}
}
Filter:
public class APIKeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
private String principalRequestHeader;
public APIKeyAuthFilter(String principalRequestHeader) {
this.principalRequestHeader = principalRequestHeader;
}
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return request.getHeader(principalRequestHeader);
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return "N/A";
}
}