/** Returns the Principal representing the logged in user. */
  public Principal getUserPrincipal() {
    requestLogin();

    Principal user;
    user = (Principal) getAttribute(AbstractLogin.LOGIN_NAME);

    if (user != null) return user;

    WebApp webApp = getWebApp();
    if (webApp == null) return null;

    // If the authenticator can find the user, return it.
    Login login = webApp.getLogin();

    if (login != null) {
      user = login.getUserPrincipal(this);

      if (user != null) {
        getResponse().setPrivateCache(true);
      } else {
        // server/123h, server/1920
        // distinguishes between setPrivateCache and setPrivateOrResinCache
        // _response.setPrivateOrResinCache(true);
      }
    }

    return user;
  }
  /** @since Servlet 3.0 */
  @Override
  public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
    WebApp webApp = getWebApp();

    if (webApp == null)
      throw new ServletException(
          L.l("No authentication mechanism is configured for '{0}'", getWebApp()));

    // server/1aj{0,1}
    Authenticator auth = webApp.getConfiguredAuthenticator();

    if (auth == null)
      throw new ServletException(
          L.l("No authentication mechanism is configured for '{0}'", getWebApp()));

    Login login = webApp.getLogin();

    if (login == null)
      throw new ServletException(
          L.l("No authentication mechanism is configured for '{0}'", getWebApp()));

    Principal principal = login.login(this, response, true);

    if (principal != null) return true;

    return false;
  }
  /**
   * Returns true if the user represented by the current request plays the named role.
   *
   * @param role the named role to test.
   * @return true if the user plays the role.
   */
  public boolean isUserInRole(String role) {
    ServletInvocation invocation = getInvocation();

    if (invocation == null) {
      if (getRequest() != null) return getRequest().isUserInRole(role);
      else return false;
    }

    HashMap<String, String> roleMap = invocation.getSecurityRoleMap();

    if (roleMap != null) {
      String linkRole = roleMap.get(role);

      if (linkRole != null) role = linkRole;
    }

    String runAs = getRunAs();

    if (runAs != null) return runAs.equals(role);

    WebApp webApp = getWebApp();

    Principal user = getUserPrincipal();

    if (user == null) {
      if (log.isLoggable(Level.FINE)) log.fine(this + " no user for isUserInRole");

      return false;
    }

    RoleMapManager roleManager = webApp != null ? webApp.getRoleMapManager() : null;

    if (roleManager != null) {
      Boolean result = roleManager.isUserInRole(role, user);

      if (result != null) {
        if (log.isLoggable(Level.FINE)) log.fine(this + " userInRole(" + role + ")->" + result);

        return result;
      }
    }

    Login login = webApp == null ? null : webApp.getLogin();

    boolean inRole = login != null && login.isUserInRole(user, role);

    if (log.isLoggable(Level.FINE)) {
      if (login == null) log.fine(this + " no Login for isUserInRole");
      else if (user == null) log.fine(this + " no user for isUserInRole");
      else if (inRole) log.fine(this + " " + user + " is in role: " + role);
      else log.fine(this + " failed " + user + " in role: " + role);
    }

    return inRole;
  }
  @Override
  public boolean login(boolean isFail) {
    try {
      WebApp webApp = getWebApp();

      if (webApp == null) {
        if (log.isLoggable(Level.FINE)) log.finer("authentication failed, no web-app found");

        getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);

        return false;
      }

      // If the authenticator can find the user, return it.
      Login login = webApp.getLogin();

      if (login != null) {
        Principal user = login.login(this, getResponse(), isFail);

        return user != null;
        /*
        if (user == null)
          return false;

        setAttribute(AbstractLogin.LOGIN_NAME, user);

        return true;
        */
      } else if (isFail) {
        if (log.isLoggable(Level.FINE))
          log.finer("authentication failed, no login module found for " + webApp);

        getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);

        return false;
      } else {
        // if a non-failure, then missing login is fine

        return false;
      }
    } catch (IOException e) {
      log.log(Level.FINE, e.toString(), e);

      return false;
    }
  }
  /** @since Servlet 3.0 */
  @Override
  public void login(String username, String password) throws ServletException {
    WebApp webApp = getWebApp();

    Authenticator auth = webApp.getConfiguredAuthenticator();

    if (auth == null)
      throw new ServletException(
          L.l("No authentication mechanism is configured for '{0}'", getWebApp()));

    // server/1aj0
    Login login = webApp.getLogin();

    if (login == null)
      throw new ServletException(L.l("No login mechanism is configured for '{0}'", getWebApp()));

    if (!login.isPasswordBased())
      throw new ServletException(
          L.l("Authentication mechanism '{0}' does not support password authentication", login));

    removeAttribute(Login.LOGIN_USER);
    removeAttribute(Login.LOGIN_PASSWORD);

    Principal principal = login.getUserPrincipal(this);

    if (principal != null)
      throw new ServletException(L.l("UserPrincipal object has already been established"));

    setAttribute(Login.LOGIN_USER, username);
    setAttribute(Login.LOGIN_PASSWORD, password);

    try {
      login.login(this, getResponse(), false);
    } finally {
      removeAttribute(Login.LOGIN_USER);
      removeAttribute(Login.LOGIN_PASSWORD);
    }

    principal = login.getUserPrincipal(this);

    if (principal == null) throw new ServletException("can't authenticate a user");
  }