Exemplo n.º 1
0
  /**
   * Return the specified URL with the specified session identifier suitably encoded.
   *
   * @param url URL to be encoded with the session id
   * @param sessionId Session id to be included in the encoded URL
   */
  protected String toEncoded(String url, String sessionId) {

    if ((url == null) || (sessionId == null)) {
      return (url);
    }

    String path = url;
    String query = "";
    String anchor = "";
    int question = url.indexOf('?');
    if (question >= 0) {
      path = url.substring(0, question);
      query = url.substring(question);
    }
    int pound = path.indexOf('#');
    if (pound >= 0) {
      anchor = path.substring(pound);
      path = path.substring(0, pound);
    }
    StringBuilder sb = new StringBuilder(path);
    if (sb.length() > 0) { // jsessionid can't be first.
      sb.append(";");
      sb.append(SessionConfig.getSessionUriParamName(request.getContext()));
      sb.append("=");
      sb.append(sessionId);
    }
    sb.append(anchor);
    sb.append(query);
    return (sb.toString());
  }
Exemplo n.º 2
0
  private boolean doIsEncodeable(Request hreq, Session session, String location) {
    // Is this a valid absolute URL?
    URL url = null;
    try {
      url = new URL(location);
    } catch (MalformedURLException e) {
      return (false);
    }

    // Does this URL match down to (and including) the context path?
    if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) {
      return (false);
    }
    if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) {
      return (false);
    }
    int serverPort = hreq.getServerPort();
    if (serverPort == -1) {
      if ("https".equals(hreq.getScheme())) {
        serverPort = 443;
      } else {
        serverPort = 80;
      }
    }
    int urlPort = url.getPort();
    if (urlPort == -1) {
      if ("https".equals(url.getProtocol())) {
        urlPort = 443;
      } else {
        urlPort = 80;
      }
    }
    if (serverPort != urlPort) {
      return (false);
    }

    String contextPath = getContext().getPath();
    if (contextPath != null) {
      String file = url.getFile();
      if ((file == null) || !file.startsWith(contextPath)) {
        return (false);
      }
      String tok =
          ";"
              + SessionConfig.getSessionUriParamName(request.getContext())
              + "="
              + session.getIdInternal();
      if (file.indexOf(tok, contextPath.length()) >= 0) {
        return (false);
      }
    }

    // This URL belongs to our web application, so it is encodeable
    return (true);
  }
Exemplo n.º 3
0
  private void doConnectorAuthenticationAuthorization(
      org.apache.coyote.Request req, Request request) {
    // Set the remote principal
    String username = req.getRemoteUser().toString();
    if (username != null) {
      if (log.isDebugEnabled()) {
        log.debug(sm.getString("coyoteAdapter.authenticate", username));
      }
      if (req.getRemoteUserNeedsAuthorization()) {
        Authenticator authenticator = request.getContext().getAuthenticator();
        if (authenticator == null) {
          // No security constraints configured for the application so
          // no need to authorize the user. Use the CoyotePrincipal to
          // provide the authenticated user.
          request.setUserPrincipal(new CoyotePrincipal(username));
        } else if (!(authenticator instanceof AuthenticatorBase)) {
          if (log.isDebugEnabled()) {
            log.debug(sm.getString("coyoteAdapter.authorize", username));
          }
          // Custom authenticator that may not trigger authorization.
          // Do the authorization here to make sure it is done.
          request.setUserPrincipal(request.getContext().getRealm().authenticate(username));
        }
        // If the Authenticator is an instance of AuthenticatorBase then
        // it will check req.getRemoteUserNeedsAuthorization() and
        // trigger authorization as necessary. It will also cache the
        // result preventing excessive calls to the Realm.
      } else {
        // The connector isn't configured for authorization. Create a
        // user without any roles using the supplied user name.
        request.setUserPrincipal(new CoyotePrincipal(username));
      }
    }

    // Set the authorization type
    String authtype = req.getAuthType().toString();
    if (authtype != null) {
      request.setAuthType(authtype);
    }
  }
Exemplo n.º 4
0
 public Context getContext(String path) {
   if (!path.startsWith("/")) {
     return null; // according to spec, null is returned
     // if we can't  return a servlet, so it's more probable
     // servlets will check for null than IllegalArgument
   }
   // Return null if cross context lookups are not allowed
   if (!crossContext) return null;
   // absolute path
   Request lr = contextM.createRequest(path);
   if (vhost != null) lr.setServerName(vhost);
   getContextManager().processRequest(lr);
   return lr.getContext();
 }
Exemplo n.º 5
0
  /** Parse additional request parameters. */
  protected boolean postParseRequest(
      org.apache.coyote.Request req,
      Request request,
      org.apache.coyote.Response res,
      Response response)
      throws Exception {

    // XXX the processor may have set a correct scheme and port prior to this point,
    // in ajp13 protocols dont make sense to get the port from the connector...
    // otherwise, use connector configuration
    if (!req.scheme().isNull()) {
      // use processor specified scheme to determine secure state
      request.setSecure(req.scheme().equals("https"));
    } else {
      // use connector scheme and secure configuration, (defaults to
      // "http" and false respectively)
      req.scheme().setString(connector.getScheme());
      request.setSecure(connector.getSecure());
    }

    // FIXME: the code below doesnt belongs to here,
    // this is only have sense
    // in Http11, not in ajp13..
    // At this point the Host header has been processed.
    // Override if the proxyPort/proxyHost are set
    String proxyName = connector.getProxyName();
    int proxyPort = connector.getProxyPort();
    if (proxyPort != 0) {
      req.setServerPort(proxyPort);
    }
    if (proxyName != null) {
      req.serverName().setString(proxyName);
    }

    // Copy the raw URI to the decodedURI
    MessageBytes decodedURI = req.decodedURI();
    decodedURI.duplicate(req.requestURI());

    // Parse the path parameters. This will:
    //   - strip out the path parameters
    //   - convert the decodedURI to bytes
    parsePathParameters(req, request);

    // URI decoding
    // %xx decoding of the URL
    try {
      req.getURLDecoder().convert(decodedURI, false);
    } catch (IOException ioe) {
      res.setStatus(400);
      res.setMessage("Invalid URI: " + ioe.getMessage());
      connector.getService().getContainer().logAccess(request, response, 0, true);
      return false;
    }
    // Normalization
    if (!normalize(req.decodedURI())) {
      res.setStatus(400);
      res.setMessage("Invalid URI");
      connector.getService().getContainer().logAccess(request, response, 0, true);
      return false;
    }
    // Character decoding
    convertURI(decodedURI, request);
    // Check that the URI is still normalized
    if (!checkNormalize(req.decodedURI())) {
      res.setStatus(400);
      res.setMessage("Invalid URI character encoding");
      connector.getService().getContainer().logAccess(request, response, 0, true);
      return false;
    }

    // Request mapping.
    MessageBytes serverName;
    if (connector.getUseIPVHosts()) {
      serverName = req.localName();
      if (serverName.isNull()) {
        // well, they did ask for it
        res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
      }
    } else {
      serverName = req.serverName();
    }
    if (request.isAsyncStarted()) {
      // TODO SERVLET3 - async
      // reset mapping data, should prolly be done elsewhere
      request.getMappingData().recycle();
    }

    // Version for the second mapping loop and
    // Context that we expect to get for that version
    String version = null;
    Context versionContext = null;
    boolean mapRequired = true;

    while (mapRequired) {
      // This will map the the latest version by default
      connector.getMapper().map(serverName, decodedURI, version, request.getMappingData());
      request.setContext((Context) request.getMappingData().context);
      request.setWrapper((Wrapper) request.getMappingData().wrapper);

      // If there is no context at this point, it is likely no ROOT context
      // has been deployed
      if (request.getContext() == null) {
        res.setStatus(404);
        res.setMessage("Not found");
        // No context, so use host
        Host host = request.getHost();
        // Make sure there is a host (might not be during shutdown)
        if (host != null) {
          host.logAccess(request, response, 0, true);
        }
        return false;
      }

      // Now we have the context, we can parse the session ID from the URL
      // (if any). Need to do this before we redirect in case we need to
      // include the session id in the redirect
      String sessionID;
      if (request
          .getServletContext()
          .getEffectiveSessionTrackingModes()
          .contains(SessionTrackingMode.URL)) {

        // Get the session ID if there was one
        sessionID =
            request.getPathParameter(SessionConfig.getSessionUriParamName(request.getContext()));
        if (sessionID != null) {
          request.setRequestedSessionId(sessionID);
          request.setRequestedSessionURL(true);
        }
      }

      // Look for session ID in cookies and SSL session
      parseSessionCookiesId(req, request);
      parseSessionSslId(request);

      sessionID = request.getRequestedSessionId();

      mapRequired = false;
      if (version != null && request.getContext() == versionContext) {
        // We got the version that we asked for. That is it.
      } else {
        version = null;
        versionContext = null;

        Object[] contexts = request.getMappingData().contexts;
        // Single contextVersion means no need to remap
        // No session ID means no possibility of remap
        if (contexts != null && sessionID != null) {
          // Find the context associated with the session
          for (int i = (contexts.length); i > 0; i--) {
            Context ctxt = (Context) contexts[i - 1];
            if (ctxt.getManager().findSession(sessionID) != null) {
              // We found a context. Is it the one that has
              // already been mapped?
              if (!ctxt.equals(request.getMappingData().context)) {
                // Set version so second time through mapping
                // the correct context is found
                version = ctxt.getWebappVersion();
                versionContext = ctxt;
                // Reset mapping
                request.getMappingData().recycle();
                mapRequired = true;
              }
              break;
            }
          }
        }
      }

      if (!mapRequired && request.getContext().getPaused()) {
        // Found a matching context but it is paused. Mapping data will
        // be wrong since some Wrappers may not be registered at this
        // point.
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          // Should never happen
        }
        // Reset mapping
        request.getMappingData().recycle();
        mapRequired = true;
      }
    }

    // Possible redirect
    MessageBytes redirectPathMB = request.getMappingData().redirectPath;
    if (!redirectPathMB.isNull()) {
      String redirectPath = urlEncoder.encode(redirectPathMB.toString());
      String query = request.getQueryString();
      if (request.isRequestedSessionIdFromURL()) {
        // This is not optimal, but as this is not very common, it
        // shouldn't matter
        redirectPath =
            redirectPath
                + ";"
                + SessionConfig.getSessionUriParamName(request.getContext())
                + "="
                + request.getRequestedSessionId();
      }
      if (query != null) {
        // This is not optimal, but as this is not very common, it
        // shouldn't matter
        redirectPath = redirectPath + "?" + query;
      }
      response.sendRedirect(redirectPath);
      request.getContext().logAccess(request, response, 0, true);
      return false;
    }

    // Filter trace method
    if (!connector.getAllowTrace() && req.method().equalsIgnoreCase("TRACE")) {
      Wrapper wrapper = request.getWrapper();
      String header = null;
      if (wrapper != null) {
        String[] methods = wrapper.getServletMethods();
        if (methods != null) {
          for (int i = 0; i < methods.length; i++) {
            if ("TRACE".equals(methods[i])) {
              continue;
            }
            if (header == null) {
              header = methods[i];
            } else {
              header += ", " + methods[i];
            }
          }
        }
      }
      res.setStatus(405);
      res.addHeader("Allow", header);
      res.setMessage("TRACE method is not allowed");
      request.getContext().logAccess(request, response, 0, true);
      return false;
    }

    doConnectorAuthenticationAuthorization(req, request);

    return true;
  }
Exemplo n.º 6
0
  @Override
  public void sendError(int code, String message) throws IOException {
    if (isIncluding()) return;

    if (isCommitted()) LOG.warn("Committed before " + code + " " + message);

    resetBuffer();
    _characterEncoding = null;
    setHeader(HttpHeader.EXPIRES, null);
    setHeader(HttpHeader.LAST_MODIFIED, null);
    setHeader(HttpHeader.CACHE_CONTROL, null);
    setHeader(HttpHeader.CONTENT_TYPE, null);
    setHeader(HttpHeader.CONTENT_LENGTH, null);

    _outputType = OutputType.NONE;
    setStatus(code);
    _reason = message;

    Request request = _channel.getRequest();
    Throwable cause = (Throwable) request.getAttribute(Dispatcher.ERROR_EXCEPTION);
    if (message == null) message = cause == null ? HttpStatus.getMessage(code) : cause.toString();

    // If we are allowed to have a body
    if (code != SC_NO_CONTENT
        && code != SC_NOT_MODIFIED
        && code != SC_PARTIAL_CONTENT
        && code >= SC_OK) {

      ErrorHandler error_handler = null;
      ContextHandler.Context context = request.getContext();
      if (context != null) error_handler = context.getContextHandler().getErrorHandler();
      if (error_handler == null) error_handler = _channel.getServer().getBean(ErrorHandler.class);
      if (error_handler != null) {
        request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code));
        request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
        request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
        request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, request.getServletName());
        error_handler.handle(null, _channel.getRequest(), _channel.getRequest(), this);
      } else {
        setHeader(HttpHeader.CACHE_CONTROL, "must-revalidate,no-cache,no-store");
        setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString());
        ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(2048);
        if (message != null) {
          message = StringUtil.replace(message, "&", "&amp;");
          message = StringUtil.replace(message, "<", "&lt;");
          message = StringUtil.replace(message, ">", "&gt;");
        }
        String uri = request.getRequestURI();
        if (uri != null) {
          uri = StringUtil.replace(uri, "&", "&amp;");
          uri = StringUtil.replace(uri, "<", "&lt;");
          uri = StringUtil.replace(uri, ">", "&gt;");
        }

        writer.write(
            "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
        writer.write("<title>Error ");
        writer.write(Integer.toString(code));
        writer.write(' ');
        if (message == null) writer.write(message);
        writer.write("</title>\n</head>\n<body>\n<h2>HTTP ERROR: ");
        writer.write(Integer.toString(code));
        writer.write("</h2>\n<p>Problem accessing ");
        writer.write(uri);
        writer.write(". Reason:\n<pre>    ");
        writer.write(message);
        writer.write("</pre>");
        writer.write("</p>\n<hr /><i><small>Powered by Jetty://</small></i>");
        writer.write("\n</body>\n</html>\n");

        writer.flush();
        setContentLength(writer.size());
        writer.writeTo(getOutputStream());
        writer.destroy();
      }
    } else if (code != SC_PARTIAL_CONTENT) {
      // TODO work out why this is required?
      _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_TYPE);
      _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_LENGTH);
      _characterEncoding = null;
      _mimeType = null;
    }

    complete();
  }