-2

When a POST request to a non-existing end-point in the application is sent, the server returns 405 instead of 404. A similar problem for Requests with an existing endpoint occurs, the status code returns 200 whenever everything goes right, but when an internal server error occurs (for example User not found), the http response becomes 405 (instead of 500). With GET requests everything works as it should.

The weird thing is, if I put on the debugger, and I follow the process of the error to be thrown, it is handling a 500 error. But apparently somewhere in the end something goes wrong and I get a 405 returned.

My web security config:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

  @Autowired
  private UserDetailsService jwtUserDetailsService;

  @Autowired
  private JwtRequestFilter jwtRequestFilter;

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    // configure AuthenticationManager so that it knows from where to load
    // user for matching credentials
    // Use BCryptPasswordEncoder
    auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
  }

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

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Value("${allowedOrigin}")
  private String origin = "http://localhost:4200";

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    //You can enforce the use of HTTPS when your app is running on Heroku by adding
    // the following configuration to your Spring Boot app.
    httpSecurity.requiresChannel()
      .requestMatchers(r - > r.getHeader("X-Forwarded-Proto") != null)
      .requiresSecure();


    httpSecurity
      .cors()
      .and().csrf()
      .disable()
      // dont authenticate this particular request
      .authorizeRequests()
      .antMatchers("/api/authenticate")
      .permitAll()
      // all other requests for /api need to be authenticated
      .antMatchers("/api/**", "/admin/**")
      .authenticated()
      .and()
      .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    // Add a filter to validate the tokens with every request
    httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("*"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  }
}

UPDATE:

I do not have any ControllerAdivce and there is no Global Exception handler written.

The "Allow" header in the 405 response reads "GET, HEAD", even when the POST request actually entered the POST endpoint.

Kaasbanaan
  • 11
  • 1
  • 4
  • Is there any ControllerAdivce, or Global exception handler written? – mfaisalhyder Jul 09 '21 at 14:30
  • No, there is no ControllerAdvice and no Global exception written, it's a fairly new project.. that's why it's so frustrating, I don't see where it could be going wrong. the strange thing is that when I do a POST, it enters the endpoint, but the header says "allow": "GET, HEAD" – Kaasbanaan Jul 09 '21 at 15:10

2 Answers2

1

It turned out an ErrorController with an unimplemented method for the "/error" path was causing the problem. Whenever an exception or an error was thrown it was resolved to "/error" and picked up by the ErrorController, which for some reason resolved it to a 405. After implementing the method the HTTP statuses are returned correctly.

@RestController
public class RoutingController implements ErrorController {

  private static final String PATH = "/error";

  @RequestMapping(value = PATH)
  public String handleError(HttpServletRequest request) {
    Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
    Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
    return String.format("<html><body><h2>Error Page</h2><div>Status code: <b>%s</b></div>" +
      "<div>Exception Message: <b>%s</b></div><body></html>",
      statusCode, exception == null ? "N/A" : exception.getMessage());
  }

  public String getErrorPath() {
    return PATH;
  }
}
Kaasbanaan
  • 11
  • 1
  • 4
0

Based on your HttpSecurity configuration you only allowing Post requests, you will get 405 (method not allowed) for other HTTP methods like GET, PUT....

 antMatchers(HttpMethod.POST).permitAll();
S. Anushan
  • 728
  • 1
  • 6
  • 12
  • I added that part as a work around, i removed it in the meanwhile.. it doesn't need to be there. antMatchers(HttpMethod.POST).permitAll(); what this does is permit all POST requests, and no role or authentication is needed. It will not block other HTTP method requests like GET, PUT,... – Kaasbanaan Jul 09 '21 at 16:50