4
votes

I am trying to implement HTTP Basic Auth using Spring Security Annotations.

I have a REST endpoint, defined as below:

@RequestMapping("/foo/")

I want people only in Admin role to access /foo/ endpoint.

Next, I am configuring Spring Security, as shown below:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    private static String REALM="MY_TEST_REALM";
     
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("tom").password("abc123").roles("USER");
    }
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
  
      //http.csrf().disable()
      http  
      .authorizeRequests()
        .antMatchers("/foo/").hasRole("ADMIN")
        .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint())
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
    }
     
    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }
     
    /* To allow Pre-flight [OPTIONS] request from browser */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

So, I only want bill username with password abc123 to be able to call the REST endpoint.

Next, I define the error that should be returned

public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
 
    @Override
    public void commence(final HttpServletRequest request, 
            final HttpServletResponse response, 
            final AuthenticationException authException) throws IOException, ServletException {
        //Authentication failed, send error response.
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");
         
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 : " + authException.getMessage());
    }
     
    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("MY_TEST_REALM");
        super.afterPropertiesSet();
    }
}

I tried testing with Postman, I am using Basic Auth with the correct credentials but I always get the 401 Error. Am I missing any step?

Please see the screenshot below from Postman. Am I missing any header? enter image description here

and, here's the Header section enter image description here (I am hiding base URL in the above screenshot)

1

1 Answers

2
votes

Edit

Don't forget to make SecurityConfiguration work.

like @Import({ SecurityConfiguration.class }) or ComponentScan("<packageName>")