5

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"
Anoobizzz
  • 93
  • 1
  • 9
  • Just to make it clear, you are sending the request with an `Authentication`header and the header contains a valid username and password? – dur Jul 24 '18 at 18:02
  • @dur No, its Authorization header and its content doesn't matter since that endpoint should be opened. – Anoobizzz Jul 24 '18 at 19:31
  • No, the authentication is before authorization, so username and password matters. – dur Jul 24 '18 at 19:46
  • Possible duplicate of https://stackoverflow.com/questions/47433314/spring-security-permitall-denies-access-when-sending-authorization-header – dur Jul 24 '18 at 19:51
  • @dur Well if what you say is true than it is kind of weird since before Spring supported security.basic.path and actuator sensetivity configurations and other rest endpoints were not affected. – Anoobizzz Jul 24 '18 at 21:16
  • Spring Boot 1.x has separated configurations for actuator and application. It supported a lot of properties (doing some magic). Because of too much problems, Spring Boot 2 removed almost all properties (the magic). Now you have to go the Spring Security way, because there is no more Spring Boot way. – dur Jul 25 '18 at 07:02

2 Answers2

4

By calling .authorizeRequests() , you enforce authorization of all these requests because you've not called .ignore() on some matcher.

I suggest to use ignore on a ** matcher and then incrementally enforce authorization on specified matchers ontop of the permit-all layer so that everything is accessible except of the ones explicitly specified.

This accomplishes what you want to do but beware, it's not a best practise for a very good reason: You should deny all unauthorized traffic by default and only explicitly permit unauthorized requests for specific route templates.

That said, it would be wiser to just use ignore explicitly on the routes you want to be accessible without authentication, not just ** (for example only for /home - /about - /login - /signup)

ntakouris
  • 898
  • 1
  • 9
  • 22
  • Thanks, but unfortunately still doesn't resolve my problem, unless i'm doing it wrong. – Anoobizzz Jul 24 '18 at 13:26
  • @Anoobizzz start by enabling access to all the endpoints and check 1 by 1 after permitAll or ignore, to see where things go wrong – ntakouris Jul 25 '18 at 15:12
0

Found a solution un cased if case when using the spring security oauth2 library. For me it went wrong in the org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter. The default behaviour this filter extracts all Authorization when send.

I solved this by reconfiguring this one;

OAuth2AuthenticationProcessingFilter.setTokenExtractor(myTokenExtractor)

My token extractor I have implemented like this

public class MyTokenExtractor implements TokenExtractor {

private final BearerTokenExtractor bearerTokenExtractor = new BearerTokenExtractor()
@Overide
public Authentication extract(HttpServletRequest request) {
  String requestURI = request.getRequestURI();
  if (requestURI.startsWith("/someuri") {
    return null;
  }
  return bearerTokenExtractor.extract(request);
}
Mark Bakker
  • 1,278
  • 8
  • 19