Search code examples
javaauthenticationjakarta-ee

How is j_username value being managed once login is performed?


I have a web app with an authentication mechanism of type FORM, so when user asks for a protected resource login.jsp intercepts the request, sends j_username and j_password to the server where the user is authenticated and authorized to get that particular resource, which is sent back to the client.

During the following requests, j_username seems not to be stored anywhere (request parameter/attribute, session attribute) but you can get that value calling request.getUserPrincipal().getName().

Who and how is actually coupling that value with current user? Where is j_username really stored? My guess is that the application server is the one that is keeping track of the pairs [userid,sessionid] so that when request.getUserPrincipal().getName() is invoked it can send back the userid associated with the current session.

But this is just a guess, can anyone comfirm/refute?


Solution

  • My guess is that the application server is the one that is keeping track of the pairs [userid,sessionid] so that when request.getUserPrincipal().getName() is invoked it can send back the userid associated with the current session.

    This is nowhere specified in the servlet specification. The "de facto" approach for FORM based authentication however indeed boils down to this. You can also easily confirm this by seeing the user principal disappear when you invalidate or expire the HTTP session.

    The actual implementation depends on the servletcontainer used. In case of Tomcat, it's stored in its org.apache.catalina.Session class (representing the internal HttpSession facade), which has a getPrincipal() method which copies the Principal to every HttpServletRequest.

    The place where it happens is the org.apache.catalina.authenticator.AuthenticatorBase, in the invoke() method. Below is an extract of relevance from Tomcat 10.0.21 source code:

    509         if (cache) {
    510             Principal principal = request.getUserPrincipal();
    511             if (principal == null) {
    512                 Session session = request.getSessionInternal(false);
    513                 if (session != null) {
    514                     principal = session.getPrincipal();
    515                     if (principal != null) {
    516                         if (log.isDebugEnabled()) {
    517                             log.debug("We have cached auth type " + session.getAuthType() +
    518                                     " for principal " + principal);
    519                         }
    520                         request.setAuthType(session.getAuthType());
    521                         request.setUserPrincipal(principal);
    522                     }
    523                 }
    524             }
    525         }
    

    At line 514 you can see it's extracted from HTTP session (at least, Tomcat's internal facade thereof which is not accessible via public API), and at line 521 you can see it being set on Tomcat's internal facade of the HTTP request which in turn is publicly accessible via HttpServletRequest#getUserPrincipal().

    If you're curious how and when Session#setPrincipal() is called, head to register() method of the very same class.

    All other servletcontainer implementations have a similar approach.

    See also: