Spring Boot 2: Basic Http Auth causes unprotected endpoints to respond with 401 "Unauthorized" if Authorization header is attached

时间:2018-07-24 10:16:57

标签: java spring spring-boot spring-security

After migration to Spring Boot 2 and adding basic authorization requirement for actuator and another application controlling endpoint it became impossible to call any unprotected endpoint with Authorization header.

Configuration snippet:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            .requestMatchers(EndpointRequest.to("shutdown")).fullyAuthenticated()
            .antMatchers("/payment/status/*").fullyAuthenticated()
            .and().httpBasic();
}

E.g. call to .../health with "Authorization: Basic ..." will cause 401 "Unauthorized" even though it is not protected by spring security.

Question: How can i adjust the configuration so that it is possible to send request with Authorization header to any unprotected endpoint without being denied?

UPD: This fix worked as i wanted

@Override
public void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            .requestMatchers(EndpointRequest.to("shutdown")).fullyAuthenticated()
            .antMatchers("/payment/status/*").fullyAuthenticated()
            .antMatchers("/payment/**").permitAll()
            .and().httpBasic();
}

UPD2: Nevermind, just tested another request and still receive 401 "Unauthorized".

curl localhost:8080/payment/<any_endpoint> -H "Authorization: Basic asdadas"
{"code":401,"message":"Unauthorized"}

This approach unfortunately overrides HttpSecurity matchers, e.g.: /payment/ becomes accessible

@Override
public void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeRequests()
            .requestMatchers(EndpointRequest.to("shutdown")).fullyAuthenticated()
            .antMatchers("/payment/status/*").fullyAuthenticated()
            .and().httpBasic();
}

@Override
public void configure(WebSecurity webSecurity) throws Exception {
    webSecurity.ignoring().antMatchers("/payment/**");
}

UPD 3: I've created a simple project with this issue being reproduced https://github.com/Anoobizzz/SpringSecurity2BasicAuthDemo

  1. /internal & /shutdown are only accessible with user:P455W0RD
  2. /exposed accessible without authorization
  3. /exposed with header "Authorization: Basic 123123" responds with 401 "Unauthorized"

1 个答案:

答案 0 :(得分:4)

通过调用.authorizeRequests(),您可以强制执行所有这些请求的授权,因为您尚未在某个匹配器上调用.ignore()

我建议在ignore匹配器上使用**,然后在允许所有层之上对指定匹配器逐步执行授权,以便除明确指定的那些内容之外的所有内容都可以访问。

这可以完成您想做的事情,但是请注意,这不是最佳实践,有一个很好的理由:默认情况下,您应拒绝所有未经授权的流量,并且仅明确允许对特定路由模板的未经授权的请求。

也就是说,明智的做法是,仅在希望不经身份验证即可访问的路由上显式使用ignore,而不仅仅是**(例如,仅针对/home - /about - /login - /signup