2
votes

It seems like Spring isn't routing/authorizing HTTP POST requests correctly. When I send a HTTP POST request I always get "405 Method Not Allowed" response and this in the log file:

org.springframework.web.servlet.PageNotFound - Request method 'POST' not supported

The controller allows POST for the URL:

@RequestMapping(value = "/mypostreq", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@Secured("ROLE_USER")
public String mypostreq(@RequestBody String callBody, HttpServletRequest req, HttpServletResponse res) { return ""; }

Here is the web.xml configuration:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml</param-value>
</context-param>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/web-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

After I send a HTTP GET request I get the usual from HTTP GET -- 401 -- HTTP GET + Authorize -- 200 OK. At that point I use a cookie to authorize further requests. When sending authorized HTTP POSTs with a cookie everything works as expected. Basically I should get HTTP 401 response to the POSTs instead of 405.

I suspect it is the routing, but cannot identify what exactly.

Here is my web-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
                           http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <mvc:annotation-driven/>
    <context:annotation-config/>
    <context:component-scan base-package="com.solution"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/error/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

And the application-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:couchdb="http://www.ektorp.org/schema/couchdb"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                           http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

    <security:http entry-point-ref="digestEntryPoint">
        <security:custom-filter ref="digestFilter" before="BASIC_AUTH_FILTER"/>
        <security:http-basic />
        <!-- Restricts anonymous access to all the pages -->
        <security:intercept-url pattern="/clientapi/content*/sound/**" access="" /> 
        <security:intercept-url pattern="/clientapi/currentcall" access="ROLE_USER" />
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider ref="daoAuthenticationProvider"/>
    </security:authentication-manager>

    <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="solutionUserDetailsService"/>
    </bean>

    <!-- Digest authentication -->
    <bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
        <property name="userDetailsService" ref="solutionUserDetailsService"/>
        <property name="authenticationEntryPoint" ref="digestEntryPoint"/>
    </bean>

    <bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
        <property name="realmName" value="Labs solution"/>
        <property name="key" value="asdfasdf"/>
        <property name="nonceValiditySeconds" value="10"/>
    </bean>

</beans>

Request/Response looks like this:

POST https://1.1.1.1/Solution-1.0/clientapi/currentcall HTTP/1.1
Accept: application/json
Content-Type: application/json
Host: 1.1.1.1
Content-Length: 82
Expect: 100-continue
Connection: Keep-Alive

{ "action" : "start" }



HTTP/1.1 405 Method Not Allowed
Server: SolutionServer
Date: Thu, 05 Sep 2013 08:03:36 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: JSESSIONID=B2A5F1FAC6E9JSNF4E62C4F9CBA24F38; Path=/Solution-1.0/; Secure; HttpOnly
WWW-Authenticate: Digest realm="Labs Solution", qop="auth", nonce="MTM3ODMMKS8yNjA3MDpjNDczNGJhYWJjYThkMGE4NTZkNmRiOGRjZWIwNDE5NQ=="
Allow: GET

0
1
Could you post your security-context file ? - sam
Judging from the error yuor mapping is wrong or the request you send. Also your controller method returns nothing basically resolving to nothing to show (you return "" from your method). However for a complete overview can you post your configuration and web.xml... - M. Deinum
Also can you please share the request details, i.e. url, request data you sending when making a post request ? - coder
I have added the rest of the configuration and a sample request/response. - akafazov
The solution to above problem seems similar to this stackoverflow.com/a/25230315/349710 - Pujan

1 Answers

2
votes

I had a similar problem. The problem was in controller, which handled error pages and supported only GET method. When I changed it to both GET and POST it started work.

Example:

@Controller
public class ErrorController {
    @RequestMapping(value = "/error" method = {RequestMethod.GET, RequestMethod.POST})
    public String error(@RequestParam(value = "err", required = false) Integer paramErrorCode, Locale locale,
            ModelMap model, HttpServletRequest httpRequest) {
         // Do something   
     }

See details https://stackoverflow.com/a/57571936/1839027