@Override
  public void sendError(int sc) throws IOException {

    if (isCommitted())
      throw new IllegalStateException(sm.getString("coyoteResponse.sendError.ise"));

    response.setAppCommitted(true);

    response.sendError(sc);
  }
Пример #2
0
  /**
   * Invoke the next Valve in the sequence. When the invoke returns, check the response state, and
   * output an error report is necessary.
   *
   * @param request The servlet request to be processed
   * @param response The servlet response to be created
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet error occurs
   */
  @Override
  public void invoke(Request request, Response response) throws IOException, ServletException {

    // Perform the request
    getNext().invoke(request, response);

    if (response.isCommitted()) {
      return;
    }

    Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

    if (request.isAsyncStarted() && response.getStatus() < 400 && throwable == null) {
      return;
    }

    if (throwable != null) {

      // The response is an error
      response.setError();

      // Reset the response (if possible)
      try {
        response.reset();
      } catch (IllegalStateException e) {
        // Ignore
      }

      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }

    response.setSuspended(false);

    try {
      report(request, response, throwable);
    } catch (Throwable tt) {
      ExceptionUtils.handleThrowable(tt);
    }

    if (request.isAsyncStarted()) {
      request.getAsyncContext().complete();
    }
  }
 /**
  * Reject the request that was denied by this valve.
  *
  * @param request The servlet request to be processed
  * @param response The servlet response to be processed
  * @exception IOException if an input/output error occurs
  * @exception ServletException if a servlet error occurs
  */
 protected void denyRequest(Request request, Response response)
     throws IOException, ServletException {
   response.sendError(denyStatus);
 }
Пример #4
0
 /**
  * Send an error response with the specified status and a default message.
  *
  * @param status HTTP status code to send
  * @exception IllegalStateException if this response has already been committed
  * @exception IOException if an input/output error occurs
  */
 @Override
 public void sendError(int status) throws IOException {
   sendError(status, null);
 }
  /**
   * Select the appropriate child Context to process this request, based on the specified request
   * URI. If no matching Context can be found, return an appropriate HTTP error.
   *
   * @param request Request to be processed
   * @param response Response to be produced
   * @exception IOException if an input/output error occurred
   * @exception ServletException if a servlet error occurred
   */
  @Override
  public final void invoke(Request request, Response response)
      throws IOException, ServletException {

    /*
     * xujb:
     * 和Engine一样,调用下层的context,让它来做一些处理
     * 自身也处理了一些的逻辑
     *
     * */

    // Select the Context to be used for this Request
    Context context = request.getContext();
    if (context == null) {
      response.sendError(
          HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext"));
      return;
    }

    // Bind the context CL to the current thread
    if (context.getLoader() != null) {
      // Not started - it should check for availability first
      // This should eventually move to Engine, it's generic.
      if (Globals.IS_SECURITY_ENABLED) {
        PrivilegedAction<Void> pa = new PrivilegedSetTccl(context.getLoader().getClassLoader());
        AccessController.doPrivileged(pa);
      } else {
        Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
      }
    }
    if (request.isAsyncSupported()) {
      request.setAsyncSupported(context.getPipeline().isAsyncSupported());
    }

    boolean asyncAtStart = request.isAsync();
    boolean asyncDispatching = request.isAsyncDispatching();
    if (asyncAtStart || context.fireRequestInitEvent(request)) {

      // Ask this Context to process this request. Requests that are in
      // async mode and are not being dispatched to this resource must be
      // in error and have been routed here to check for application
      // defined error pages.
      try {
        if (!asyncAtStart || asyncDispatching) {
          context.getPipeline().getFirst().invoke(request, response);
        } else {
          // Make sure this request/response is here because an error
          // report is required.
          if (!response.isErrorReportRequired()) {
            throw new IllegalStateException(sm.getString("standardHost.asyncStateError"));
          }
        }
      } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        // If a new error occurred while trying to report a previous
        // error simply log the new error and allow the original error
        // to be reported.
        if (response.isErrorReportRequired()) {
          container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
        } else {
          request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
          throwable(request, response, t);
        }
      }

      // Now that the request/response pair is back under container
      // control lift the suspension so that the error handling can
      // complete and/or the container can flush any remaining data
      response.setSuspended(false);

      Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

      // Protect against NPEs if the context was destroyed during a
      // long running request.
      if (!context.getState().isAvailable()) {
        return;
      }

      // Look for (and render if found) an application level error page
      if (response.isErrorReportRequired()) {
        if (t != null) {
          throwable(request, response, t);
        } else {
          status(request, response);
        }
      }

      if (!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) {
        context.fireRequestDestroyEvent(request);
      }
    }

    // Access a session (if present) to update last accessed time, based on a
    // strict interpretation of the specification
    if (ACCESS_SESSION) {
      request.getSession(false);
    }

    // Restore the context classloader
    if (Globals.IS_SECURITY_ENABLED) {
      PrivilegedAction<Void> pa = new PrivilegedSetTccl(StandardHostValve.class.getClassLoader());
      AccessController.doPrivileged(pa);
    } else {
      Thread.currentThread().setContextClassLoader(StandardHostValve.class.getClassLoader());
    }
  }
  /**
   * 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 constraints Security constraint being checked
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean hasUserDataPermission(
      Request request, Response response, SecurityConstraint[] constraints) throws IOException {

    // Is there a relevant user data constraint?
    if (constraints == null || constraints.length == 0) {
      if (log.isDebugEnabled()) log.debug("  No applicable security constraint defined");
      return (true);
    }
    for (int i = 0; i < constraints.length; i++) {
      SecurityConstraint constraint = constraints[i];
      String userConstraint = constraint.getUserConstraint();
      if (userConstraint == null) {
        if (log.isDebugEnabled()) log.debug("  No applicable user data constraint defined");
        return (true);
      }
      if (userConstraint.equals(Constants.NONE_TRANSPORT)) {
        if (log.isDebugEnabled()) log.debug("  User data constraint has no restrictions");
        return (true);
      }
    }
    // Validate the request against the user data constraint
    if (request.getRequest().isSecure()) {
      if (log.isDebugEnabled()) log.debug("  User data constraint already satisfied");
      return (true);
    }
    // Initialize variables we need to determine the appropriate action
    int redirectPort = request.getConnector().getRedirectPort();

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

    // Redirect to the corresponding SSL port
    StringBuilder file = new StringBuilder();
    String protocol = "https";
    String host = request.getServerName();
    // Protocol
    file.append(protocol).append("://").append(host);
    // Host with port
    if (redirectPort != 443) {
      file.append(":").append(redirectPort);
    }
    // URI
    file.append(request.getRequestURI());
    String requestedSessionId = request.getRequestedSessionId();
    if ((requestedSessionId != null) && request.isRequestedSessionIdFromURL()) {
      file.append(";");
      file.append(SessionConfig.getSessionUriParamName(request.getContext()));
      file.append("=");
      file.append(requestedSessionId);
    }
    String queryString = request.getQueryString();
    if (queryString != null) {
      file.append('?');
      file.append(queryString);
    }
    if (log.isDebugEnabled()) log.debug("  Redirecting to " + file.toString());
    response.sendRedirect(file.toString());
    return (false);
  }
  /**
   * 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 constraints Security constraint we are enforcing
   * @param context The Context to which client of this class is attached.
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean hasResourcePermission(
      Request request, Response response, SecurityConstraint[] constraints, Context context)
      throws IOException {

    if (constraints == null || constraints.length == 0) 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.getRequestPathMB().toString();
      String loginPage = config.getLoginPage();
      if (loginPage.equals(requestURI)) {
        if (log.isDebugEnabled()) log.debug(" Allow access to login page " + loginPage);
        return (true);
      }
      String errorPage = config.getErrorPage();
      if (errorPage.equals(requestURI)) {
        if (log.isDebugEnabled()) log.debug(" Allow access to error page " + errorPage);
        return (true);
      }
      if (requestURI.endsWith(Constants.FORM_ACTION)) {
        if (log.isDebugEnabled()) log.debug(" Allow access to username/password submission");
        return (true);
      }
    }

    // Which user principal have we already authenticated?
    Principal principal = request.getPrincipal();
    boolean status = false;
    boolean denyfromall = false;
    for (int i = 0; i < constraints.length; i++) {
      SecurityConstraint constraint = constraints[i];

      String roles[];
      if (constraint.getAllRoles()) {
        // * means all roles defined in web.xml
        roles = request.getContext().findSecurityRoles();
      } else {
        roles = constraint.findAuthRoles();
      }

      if (roles == null) roles = new String[0];

      if (log.isDebugEnabled()) log.debug("  Checking roles " + principal);

      if (roles.length == 0 && !constraint.getAllRoles()) {
        if (constraint.getAuthConstraint()) {
          if (log.isDebugEnabled()) log.debug("No roles");
          status = false; // No listed roles means no access at all
          denyfromall = true;
          break;
        }

        if (log.isDebugEnabled()) log.debug("Passing all access");
        status = true;
      } else if (principal == null) {
        if (log.isDebugEnabled()) log.debug("  No user authenticated, cannot grant access");
      } else {
        for (int j = 0; j < roles.length; j++) {
          if (hasRole(null, principal, roles[j])) {
            status = true;
            if (log.isDebugEnabled()) log.debug("Role found:  " + roles[j]);
          } else if (log.isDebugEnabled()) log.debug("No role found:  " + roles[j]);
        }
      }
    }

    if (!denyfromall && allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) {
      if (log.isDebugEnabled()) {
        log.debug("Checking for all roles mode: " + allRolesMode);
      }
      // Check for an all roles(role-name="*")
      for (int i = 0; i < constraints.length; i++) {
        SecurityConstraint constraint = constraints[i];
        String roles[];
        // If the all roles mode exists, sets
        if (constraint.getAllRoles()) {
          if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) {
            if (log.isDebugEnabled()) {
              log.debug("Granting access for role-name=*, auth-only");
            }
            status = true;
            break;
          }

          // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles
          roles = request.getContext().findSecurityRoles();
          if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) {
            if (log.isDebugEnabled()) {
              log.debug("Granting access for role-name=*, strict auth-only");
            }
            status = true;
            break;
          }
        }
      }
    }

    // Return a "Forbidden" message denying access to this resource
    if (!status) {
      response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("realmBase.forbidden"));
    }
    return status;
  }