docs: protected Subject doHashTableLogin(Subject clientSubject, JaspiRequest jaspiRequest) throws WSLoginFailedException {
          Subject authenticatedSubject = null;
          final Hashtable<String, Object> hashTable = getCustomCredentials(clientSubject);
          String unauthenticatedSubjectString = UNAUTHENTICATED_ID;
          String user = null;
          if (hashTable == null) {
              // The JASPI provider did not add creds to the clientSubject. If we
              // have a session subject then just return success and we'll use the
              // session subject which has already been set on the thread
              Subject sessionSubject = getSessionSubject(jaspiRequest);
              if (sessionSubject != null) {
                  if (tc.isDebugEnabled())
                      Tr.debug(tc, "No HashTable returned by the JASPI provider. Using JASPI session subject.");
                  return sessionSubject;
              }
              MessageInfo msgInfo = jaspiRequest.getMessageInfo();
              boolean isProtected = Boolean.parseBoolean((String) msgInfo.getMap().get(IS_MANDATORY_POLICY));
              if (isProtected) {
                  String msg = "JASPI HashTable login cannot be performed, JASPI provider did not return a HashTable.";
                  throw new WSLoginFailedException(msg);
              } else {
                  user = unauthenticatedSubjectString;
                  if (tc.isDebugEnabled())
                      Tr.debug(tc, "Web resource is unprotected and Subject does not have a HashTable.");
              }
          } else {
              user = (String) hashTable.get(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME);
          }
          boolean isUnauthenticated = unauthenticatedSubjectString.equals(user);
          if (isUnauthenticated) {
              authenticatedSubject = getUnauthenticatedSubject();
              if (tc.isDebugEnabled())
                  Tr.debug(tc, "JASPI Subject is unauthenticated, HashTable login is not necessary.");
          } else {
              if (user == null)
                  user = "";
              Subject loginSubject = clientSubject;
              // If we have a session subject then do the hashtable login with the session subject
              // so we pick up all the creds from the original session login. Add the custom
              // credential hashtable (that the JASPI provider returned) to the session subject.
              // Note we must "clone" the session subject as it is read only
              final Subject sessionSubject = getSessionSubject(jaspiRequest);
              if (sessionSubject != null) {
                  final Subject clone = new Subject();
                  clone.getPrivateCredentials().addAll(sessionSubject.getPrivateCredentials());
                  clone.getPublicCredentials().addAll(sessionSubject.getPublicCredentials());
                  clone.getPrincipals().addAll(sessionSubject.getPrincipals());
                  // add the hashtable from the JASPI provider
                  clone.getPrivateCredentials().add(hashTable);
                  loginSubject = clone;
              }
              final HttpServletRequest req = jaspiRequest.getHttpServletRequest();
              final HttpServletResponse res = (HttpServletResponse) jaspiRequest.getMessageInfo().getResponseMessage();
              if (tc.isDebugEnabled()) {
                  Tr.debug(tc, "JASPI login with HashTable: " + hashTable);
              }
              AuthenticationResult result = getWebProviderAuthenticatorHelper().loginWithHashtable(req, res, loginSubject);
  
              authenticatedSubject = result.getSubject();
              // Remove the custom credential hashtable from the session subject
              if (sessionSubject != null) {
                  removeCustomCredentials(sessionSubject, hashTable);
              }
              if (authenticatedSubject == null) {
                  throw new WSLoginFailedException("JASPI HashTable login failed, user: " + user);
              }
          }
          return authenticatedSubject;
      }