HttpServletRequest.login does not keep logged in for subsequent requests

大憨熊 提交于 2021-02-19 06:15:29

问题


After logging in using HttpServletRequest.login(String, String), using the code below, on following requests I still get a Basic Authentication prompt. Why is the login function not working in my configuration?

My endpoint:

@POST
@Path("login")
@Consumes(MediaType.APPLICATION_JSON)
public void login(@Valid LoginRequest loginRequest) {
    try {
        User user = userController.findUserByUsername(loginRequest.getUsername()).orElseThrow(NotFoundException::new);
        httpServletRequest.login(loginRequest.getUsername(), loginRequest.getPassword());
        log.info(securityContext); // not null now!
    }
    catch (ServletException e) {
        throw new NotAuthorizedException(e.getMessage(), e, AuthenticationHeaderFilter.CHALLENGE);
    }
}

And my jboss-web.xml

  <?xml version="1.0" encoding="UTF-8"?>
  <jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://www.jboss.com/xml/ns/javaee
        http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
    <security-domain>MyRealm</security-domain>
  </jboss-web>

And my web.xml:

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>MyRealm</realm-name>
</login-config>

<security-role>
    <role-name>admin</role-name>
</security-role>

<security-role>
    <role-name>user</role-name>
</security-role>

<security-constraint>
    <display-name>Authenticated content</display-name>
    <web-resource-collection>
        <web-resource-name>Authentication required</web-resource-name>
        <url-pattern>/api/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>user</role-name>
    </auth-constraint>
</security-constraint>

<security-constraint>
    <display-name>Anonymous content</display-name>
    <web-resource-collection>
        <web-resource-name>Exclude from Security</web-resource-name>
        <url-pattern>/api/me/login</url-pattern>
    </web-resource-collection>
</security-constraint>

回答1:


Actually, the contract for HttpServletRequest#login does not mandate that the authenticated identity be remembered for the duration of the HTTP session (if one already exists), and certainly not that an HTTP session should be created upon successful authentication (for if one does not exist).

Technically speaking, the HttpServletRequest#login call goes straight through to the identity store (the method's Javadoc uses the term login mechanism for that). An identity store is a kind of database that typically only performs the credential validation and does not have knowledge about its environment (i.e. doesn't know about HTTP sessions, or remote EJB context IDs, or JCA inflow security IDs of whatever).

The authentication mechanism IS aware of its environment, and this one is invoked by calling HttpServletRequest#authenticate. But, this would normally be expected to start an interaction dialog with the user when not being authenticated yet, not remember the authenticated identity in the session if the user happens to be authenticated (the fact this happens to work on JBoss seems more like a coincidence than something that is supposed to happen).

That all said, section 13.10 of the Servlet spec does allow containers to create an HTTP session:

Containers may create HTTP Session objects to track login state. If a developer creates a session while a user is not authenticated, and the container then authenticates the user, the session visible to developer code after login must be the same session object that was created prior to login occurring so that there is no loss of session information.

(emphasis mine)

But... it's not overly clear if this text is in regard to calling the login() method or the authenticate() one.

In short, this is one of the many small gaps in the Java EE security spec; it's just not defined how to programmatically do a login with a given username/password and explicitly say if you want or do not want that to be for the current request only or for the remainder of the HTTP session.

We hope to fix issues like this in the Java EE Security API (JSR 375) for Java EE 8.




回答2:


The answer is that after invoking httpServletRequest#login(String, String) you should still invoke httpSevletRequest#authenticate(HttpServletResponse). My final, working code, is:

httpServletRequest.login(loginRequest.getUsername(), loginRequest.getPassword());
httpServletRequest.authenticate(httpServletResponse);



回答3:


As you want programmatic authentication, there is no need of <login-config> in web.xml



来源:https://stackoverflow.com/questions/38896538/httpservletrequest-login-does-not-keep-logged-in-for-subsequent-requests

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!