Form Authentication with wrong credentials leads t

2019-09-17 04:56发布

问题:

I have a Spring web application which should be protected by Form Authentication (I cannot use Spring Security for some reasons).

If I request a protected resource I will be redirected to the login form and can enter the credentials. When the credentials are correct, I will be redirected to the requestet resource. Everything like it should be.

But when I enter wrong credentials I get a HTTP 405 message, not the error page. Why?

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Authentication</web-resource-name>
            <url-pattern>/test/auth/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>users</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/loginerror.html</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>users</role-name>
    </security-role>

</web-app>

login.html

<!DOCTYPE html>
<html>
<body>

<form method="post" action="j_security_check">
    <table>
        <tr>
            <td colspan="2">Please type in your user name and password</td>
        </tr>
        <tr>
            <td>Name:</td>
            <td><input type="text" name="j_username" width="40"/></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type="password" name="j_password" /></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="Login" /></td>
        </tr>
    </table>
</form>

</body>
</html>

loginerror.html

<!DOCTYPE html>
<html>
<body>

error!

</body>
</html>

Log

WARN [http-nio-8080-exec-79] o.s.web.servlet.PageNotFound: Request method 'POST' not supported

Controller

@RestController
@RequestMapping("/test")
public class TestController {

    private final static Logger LOG = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private HttpServletRequest request;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test() {
        printAuth();
        return "test";
    }

    @RequestMapping(value = "/auth/test", method = RequestMethod.GET)
    public String testAuth() {
        printAuth();
        return "testAuth";
    }

    @RequestMapping(value = "/auth/test2", method = RequestMethod.GET)
    public String testAuth2() {
        printAuth();
        return "testAuth2";
    }

    private void printAuth() {
        Principal principal = request.getUserPrincipal();
        LOG.debug("Request: " + request);
        LOG.debug("Principal: " + principal);
        LOG.debug("Principal name :" + principal.getName());
        LOG.debug("User in Role 'users': " + request.isUserInRole("users"));
    }

}

Update:

I tried the same authentication with a spimple "non Spring" application and it works fine. So I assume that the Spring servlet "catches" the request somehow. Is it possible to avoid that?

回答1:

From wiki:

405 Method Not Allowed: A request method is not supported for the requested resource; for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource.

All you have to do is to change your controller RequestMethod from GET to POST

You can't Post an HTTP form + try to handle it using GET method.

something like this:

@RestController
@RequestMapping("/test")
public class TestController {

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public String test() {
      ...
    }

    @RequestMapping(value = "/auth/test", method = RequestMethod.POST)
    public String testAuth() {
      ...
    }

    @RequestMapping(value = "/auth/test2", method = RequestMethod.POST)
    public String testAuth2() {
       ...
    }

}

According to your image:

You are obviously trying to POST your form to this URL: /test/auth

And according to your controller code:

@RequestMapping(value = "/auth/test", method = RequestMethod.GET)
public String testAuth() {
    printAuth();
    return "testAuth";
}

You are using GET and it's wrong to do, Try to change it to POST.



回答2:

Like I assumed in my update the Spring servlet is responsible for this problem. Therefore I had to make shure that an another servlet serves the login pages instead of the Spring servlet.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/WEB-INF/classes/static/login/*</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Authentication</web-resource-name>
            <url-pattern>/test/auth/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>users</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/WEB-INF/classes/static/login/login.html</form-login-page>
            <form-error-page>/WEB-INF/classes/static/login/loginerror.html</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>users</role-name>
    </security-role>

</web-app>