/**
   * Perform access control based on the specified authorization constraint. Return <code>true
   * </code> if this constraint is satisfied and processing should continue, or <code>false</code>
   * otherwise.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @param constraint Security constraint we are enforcing
   * @exception IOException if an input/output error occurs
   */
  protected boolean accessControl(
      HttpRequest request, HttpResponse response, SecurityConstraint constraint)
      throws IOException {

    if (constraint == null) return (true);

    // Specifically allow access to the form login and form error pages
    // and the "j_security_check" action
    LoginConfig config = context.getLoginConfig();
    if ((config != null) && (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
      String requestURI = request.getDecodedRequestURI();
      String loginPage = context.getPath() + config.getLoginPage();
      if (loginPage.equals(requestURI)) {
        if (debug >= 1) log(" Allow access to login page " + loginPage);
        return (true);
      }
      String errorPage = context.getPath() + config.getErrorPage();
      if (errorPage.equals(requestURI)) {
        if (debug >= 1) log(" Allow access to error page " + errorPage);
        return (true);
      }
      if (requestURI.endsWith(Constants.FORM_ACTION)) {
        if (debug >= 1) log(" Allow access to username/password submission");
        return (true);
      }
    }

    // Which user principal have we already authenticated?
    Principal principal = ((HttpServletRequest) request.getRequest()).getUserPrincipal();
    if (principal == null) {
      if (debug >= 2) log("  No user authenticated, cannot grant access");
      ((HttpServletResponse) response.getResponse())
          .sendError(
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              sm.getString("authenticator.notAuthenticated"));
      return (false);
    }

    // Check each role included in this constraint
    Realm realm = context.getRealm();
    String roles[] = constraint.findAuthRoles();
    if (roles == null) roles = new String[0];

    if (constraint.getAllRoles()) return (true);
    if ((roles.length == 0) && (constraint.getAuthConstraint())) {
      ((HttpServletResponse) response.getResponse())
          .sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.forbidden"));
      return (false); // No listed roles means no access at all
    }
    for (int i = 0; i < roles.length; i++) {
      if (realm.hasRole(principal, roles[i])) return (true);
    }

    // Return a "Forbidden" message denying access to this resource
    ((HttpServletResponse) response.getResponse())
        .sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.forbidden"));
    return (false);
  }
  /**
   * Register an authenticated Principal and authentication type in our request, in the current
   * session (if there is one), and with our SingleSignOn valve, if there is one. Set the
   * appropriate cookie to be returned.
   *
   * @param request The servlet request we are processing
   * @param response The servlet response we are generating
   * @param principal The authenticated Principal to be registered
   * @param authType The authentication type to be registered
   * @param username Username used to authenticate (if any)
   * @param password Password used to authenticate (if any)
   */
  protected void register(
      HttpRequest request,
      HttpResponse response,
      Principal principal,
      String authType,
      String username,
      String password) {

    if (debug >= 1) log("Authenticated '" + principal.getName() + "' with type '" + authType + "'");

    // Cache the authentication information in our request
    request.setAuthType(authType);
    request.setUserPrincipal(principal);

    // Cache the authentication information in our session, if any
    if (cache) {
      Session session = getSession(request, false);
      if (session != null) {
        session.setAuthType(authType);
        session.setPrincipal(principal);
        if (username != null) session.setNote(Constants.SESS_USERNAME_NOTE, username);
        else session.removeNote(Constants.SESS_USERNAME_NOTE);
        if (password != null) session.setNote(Constants.SESS_PASSWORD_NOTE, password);
        else session.removeNote(Constants.SESS_PASSWORD_NOTE);
      }
    }

    // Construct a cookie to be returned to the client
    if (sso == null) return;
    HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
    HttpServletResponse hres = (HttpServletResponse) response.getResponse();
    String value = generateSessionId();
    Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, value);
    cookie.setMaxAge(-1);
    cookie.setPath("/");
    hres.addCookie(cookie);

    // Register this principal with our SSO valve
    sso.register(value, principal, authType, username, password);
    request.setNote(Constants.REQ_SSOID_NOTE, value);
  }
  /**
   * Enforce any user data constraint required by the security constraint guarding this request URI.
   * Return <code>true</code> if this constraint was not violated and processing should continue, or
   * <code>false</code> if we have created a response already.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @param constraint Security constraint being checked
   * @exception IOException if an input/output error occurs
   */
  protected boolean checkUserData(
      HttpRequest request, HttpResponse response, SecurityConstraint constraint)
      throws IOException {

    // Is there a relevant user data constraint?
    if (constraint == null) {
      if (debug >= 2) log("  No applicable security constraint defined");
      return (true);
    }
    String userConstraint = constraint.getUserConstraint();
    if (userConstraint == null) {
      if (debug >= 2) log("  No applicable user data constraint defined");
      return (true);
    }
    if (userConstraint.equals(Constants.NONE_TRANSPORT)) {
      if (debug >= 2) log("  User data constraint has no restrictions");
      return (true);
    }

    // Validate the request against the user data constraint
    if (request.getRequest().isSecure()) {
      if (debug >= 2) log("  User data constraint already satisfied");
      return (true);
    }

    // Initialize variables we need to determine the appropriate action
    HttpServletRequest hrequest = (HttpServletRequest) request.getRequest();
    HttpServletResponse hresponse = (HttpServletResponse) response.getResponse();
    int redirectPort = request.getConnector().getRedirectPort();

    // Is redirecting disabled?
    if (redirectPort <= 0) {
      if (debug >= 2) log("  SSL redirect is disabled");
      hresponse.sendError(HttpServletResponse.SC_FORBIDDEN, hrequest.getRequestURI());
      return (false);
    }

    // Redirect to the corresponding SSL port
    String protocol = "https";
    String host = hrequest.getServerName();
    StringBuffer file = new StringBuffer(hrequest.getRequestURI());
    String requestedSessionId = hrequest.getRequestedSessionId();
    if ((requestedSessionId != null) && hrequest.isRequestedSessionIdFromURL()) {
      file.append(";jsessionid=");
      file.append(requestedSessionId);
    }
    String queryString = hrequest.getQueryString();
    if (queryString != null) {
      file.append('?');
      file.append(queryString);
    }
    URL url = null;
    try {
      url = new URL(protocol, host, redirectPort, file.toString());
      if (debug >= 2) log("  Redirecting to " + url.toString());
      hresponse.sendRedirect(url.toString());
      return (false);
    } catch (MalformedURLException e) {
      if (debug >= 2) log("  Cannot create new URL", e);
      hresponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, hrequest.getRequestURI());
      return (false);
    }
  }