Search code examples
javaspringauthenticationspring-securitybasic-authentication

Spring Security Basic Authentication always causes 404


I've been building a REST API using Spring. I'm using Basic Authentication with Spring Security (3.2) and I'm having an issue where any unauthenticated request causes a 404 error, even with an implementation of AuthenticationEntryPoint (regardless, Spring should give a 401 as far as I am aware by default). Requesting the resource in my browser, I am not even prompted for credentials. Here's a screenshot of the problem:

404 Error

After reading the documentation and a number of tutorials on the subject, I can't seem to find where I've gone wrong. The only thing I can imagine is happening is some exception that's being caught.

Spring Security configuration:

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private static final String REALM_NAME = "Autopulse API";

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // Set to stateless authentication.
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.csrf().disable();
        httpSecurity.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        httpSecurity.userDetailsService(userDetailsService);

        httpSecurity.authorizeRequests()
          .antMatchers("/make/private").authenticated();

        httpSecurity.httpBasic().realmName(REALM_NAME);
    }
}

Authentication Entry Point:

@Slf4j
@Component
public class HttpBasicAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}

Controller:

@Slf4j
@RestController
@RequestMapping("/make")
public class MakeController {
    @RequestMapping(value = "/private", method = RequestMethod.GET)
    public String getPrivateStuff() {
        return "private things!";
    }
}

When I provide valid user credentials in the Authorization header, I can see the protected resource ("private things!"), however if I do not provide an Authorization header, or I enter invalid credentials, I simply get the 404 error. I can attach my user details service and user details classes if required.


Solution

  • I figured it out. The problem came down to Spring and exception handling. I had a class called ExceptionController that looked like:

    @Slf4j
    @RestController
    @ControllerAdvice
    public class ExceptionController implements ErrorController {
    
      // @ExceptionHandler methods here.
    
      @Override
      public String getErrorPath() {
        return null;
      }
    }
    

    It turns out that, by implementing ErrorController, I was handing control to this class AFTER the authentication entry point where Spring could not find the appropriate method and would eventually throw the unwanted 404 error. The fix was to remove those details:

    @Slf4j
    @RestController
    @ControllerAdvice
    public class ExceptionController {
    
      // @ExceptionHandler methods here.
    
    }