Example #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());
  }
Example #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);
  }
Example #3
0
  /** Parse session id in URL. */
  protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {

    // If session tracking via cookies has been disabled for the current
    // context, don't go looking for a session ID in a cookie as a cookie
    // from a parent context with a session ID may be present which would
    // overwrite the valid session ID encoded in the URL
    Context context = (Context) request.getMappingData().context;
    if (context != null
        && !context
            .getServletContext()
            .getEffectiveSessionTrackingModes()
            .contains(SessionTrackingMode.COOKIE)) {
      return;
    }

    // Parse session id from cookies
    Cookies serverCookies = req.getCookies();
    int count = serverCookies.getCookieCount();
    if (count <= 0) {
      return;
    }

    String sessionCookieName = SessionConfig.getSessionCookieName(context);

    for (int i = 0; i < count; i++) {
      ServerCookie scookie = serverCookies.getCookie(i);
      if (scookie.getName().equals(sessionCookieName)) {
        // Override anything requested in the URL
        if (!request.isRequestedSessionIdFromCookie()) {
          // Accept only the first session id cookie
          convertMB(scookie.getValue());
          request.setRequestedSessionId(scookie.getValue().toString());
          request.setRequestedSessionCookie(true);
          request.setRequestedSessionURL(false);
          if (log.isDebugEnabled()) {
            log.debug(" Requested cookie session id is " + request.getRequestedSessionId());
          }
        } else {
          if (!request.isRequestedSessionIdValid()) {
            // Replace the session id until one is valid
            convertMB(scookie.getValue());
            request.setRequestedSessionId(scookie.getValue().toString());
          }
        }
      }
    }
  }
Example #4
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;
  }
  /**
   * 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);
  }