I've looked in so many questions on here, but with no solutions that work for me.
I have a service that I want to run open api and the swagger ui on.
I have no problems running them without security, and when I try add basic authentication with the code below it works as I'd like, BUT it also puts all my other API's behind the same authentication, which I do not want. I thought I could add an additional requestMatcher
like this:
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeHttpRequests()
.requestMatchers("/swagger-ui/**",
"/v3/api-docs/**",
"/v3/api-docs",
"/swagger-ui.html")
.hasRole("USER")
.requestMatchers("/**").permitAll()
.and()
.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
}
When I do this, my other API's are. accessible without security as I expect, and when I go to the swagger ui I get the popup, I can log in, but then the get request to /v3/api-config
fails with a 403 forbidden error or a 400 error, depending on where the permitAll requestMatcher is located.
What is the correct way to do this?
I want the swagger api's to be behind basic auth, but all other api's to be accessible by anyone.
I cannot find an existing answer to help with this.
My current security config is below, this blocks everything and allows swagger after authentication:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
public static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeHttpRequests()
.requestMatchers("/swagger-ui/**",
"/v3/api-docs/**",
"/v3/api-docs",
"/swagger-ui.html")
.hasRole("USER")
.and()
.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.withUsername("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
So this was a weird one. In the service I'm working on we have an endpoint called
/error
.Spring has a default error controller which also has an endpoint called
/error
.This was never a problem before, but apparently with the inclusion of spring-security something changed and it became a problem.
Spring couldn't figure out which resource to use for whatever it was trying to do, and so selected the wrong one, which resulted in weird behaviours.
Interestingly there were no actual errors.
In the debug logs I noticed that we were calling
/error
for some reason (still can't figure that out) and there was a warning that the expected body wasn't in the request, which was odd because we weren't calling that resource, and theGET
request that was failing didn't have a body.It wasn't until we turned on trace logs that we could see that there were two conflicting
/error
resources, and spring was picking out resource instead of the one it was looking for.We renamed our error resource to something else and all the issues went away.
I find it weird that spring doesn't complain properly when that happens though. Surely that sort of conflict requires more than a trace log?
In any case, it is working now.