0
votes

I've been trying to follow this tutorial :

https://www.baeldung.com/spring-security-basic-authentication

I have created a couple of rest endpoints like this :

@RestController
public class PostController {

    @Autowired
    PostCommentService postCommentService;

    @Autowired
    PostService postService;

    @GetMapping("/comment")
    public PostComment getComment(@RequestParam Long id) {
       return postCommentService.findPostCommentById(id);
    }

    @PostMapping("/createPost")
    public void createPost(@RequestBody PostDTO body){
        postService.createPost(body);
    }
}

Now for security I am using spring like this:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
 </dependency>

This is the config class for spring security:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyBasicAuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers( "/comment").permitAll()
                .anyRequest().authenticated()
                .and()
            .httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint);

        http.addFilterAfter(new CustomFilter(),
                BasicAuthenticationFilter.class);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password(passwordEncoder().encode("password"))
            .authorities("ROLE_USER");
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

The CustomFilter looks like this:

public class CustomFilter extends GenericFilterBean {

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
    }

}

And this is the AuthenticationEntryPoint:

@Component
public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
        throws IOException {
        response.addHeader("WWW-Authenticate", "Basic realm= + getRealmName() + ");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 - " + authEx.getMessage());
    }

    @Override
    public void afterPropertiesSet(){
        setRealmName("spring");
        super.afterPropertiesSet();
    }
}

Now the problem is that whenever I try to send a POST request I end up getting this error message:

HTTP Status 401 - Full authentication is required to access this resource

I have tried two approaches to send the request, one via postman

enter image description here

And the second one via curl:

curl -i --user admin:password --request POST --data {"text":"this is a new Post"} http://localhost:8080/createPost

I am at my wits' end here, hence the need to create this post. Any help will be much appreciated.

This is the curl response in case it might shed light on the matter:

1.1 401 Set-Cookie: JSESSIONID=6FE84B06E90BE7F2348C0935FE3DA971; Path=/; HttpOnly X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY WWW-Authenticate: Basic realm= + getRealmName() + Content-Length: 75 Date: Thu, 10 Sep 2020 13:47:14 GMT

HTTP Status 401 - Full authentication is required to access this resource

1

1 Answers

1
votes

This happens because Spring Security comes with CSRF protection enabled by default (and for a good reason). You can read about Cross Site Request Forgery here. In your case the CsrfFilter detects missing or invalid CSRF token and you're getting the 401 response. The easiest way to make your example work would be to disable csrf-ing in your security configuration but, of course, you shouldn't do this in a real application.

    @Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf()
            .disable()
            .authorizeRequests()
            .antMatchers( "/comment").permitAll()
            .anyRequest().authenticated()
            .and()
            .httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint);

    http.addFilterAfter(new CustomFilter(),
            BasicAuthenticationFilter.class);
}