/**
   * Generate a unique token. The token is generated according to the following pattern. NOnceToken
   * = Base64 ( MD5 ( client-IP ":" time-stamp ":" private-key ) ).
   *
   * @param request HTTP Servlet request
   */
  protected String generateNonce(Request request) {

    long currentTime = System.currentTimeMillis();

    synchronized (lastTimestampLock) {
      if (currentTime > lastTimestamp) {
        lastTimestamp = currentTime;
      } else {
        currentTime = ++lastTimestamp;
      }
    }

    String ipTimeKey = request.getRemoteAddr() + ":" + currentTime + ":" + getKey();

    byte[] buffer =
        ConcurrentMessageDigest.digestMD5(ipTimeKey.getBytes(StandardCharsets.ISO_8859_1));
    String nonce = currentTime + ":" + MD5Encoder.encode(buffer);

    NonceInfo info = new NonceInfo(currentTime, getNonceCountWindowSize());
    synchronized (nonces) {
      nonces.put(nonce, info);
    }

    return nonce;
  }
Example #2
0
  /**
   * Log the interesting request parameters, invoke the next Valve in the sequence, and log the
   * interesting response parameters.
   *
   * @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
   */
  public void invoke(Request request, Response response) throws IOException, ServletException {

    Log log = container.getLogger();

    // Log pre-service information
    log.info("REQUEST URI       =" + request.getRequestURI());
    log.info("          authType=" + request.getAuthType());
    log.info(" characterEncoding=" + request.getCharacterEncoding());
    log.info("     contentLength=" + request.getContentLength());
    log.info("       contentType=" + request.getContentType());
    log.info("       contextPath=" + request.getContextPath());
    Cookie cookies[] = request.getCookies();
    if (cookies != null) {
      for (int i = 0; i < cookies.length; i++)
        log.info("            cookie=" + cookies[i].getName() + "=" + cookies[i].getValue());
    }
    Enumeration hnames = request.getHeaderNames();
    while (hnames.hasMoreElements()) {
      String hname = (String) hnames.nextElement();
      Enumeration hvalues = request.getHeaders(hname);
      while (hvalues.hasMoreElements()) {
        String hvalue = (String) hvalues.nextElement();
        log.info("            header=" + hname + "=" + hvalue);
      }
    }
    log.info("            locale=" + request.getLocale());
    log.info("            method=" + request.getMethod());
    Enumeration pnames = request.getParameterNames();
    while (pnames.hasMoreElements()) {
      String pname = (String) pnames.nextElement();
      String pvalues[] = request.getParameterValues(pname);
      StringBuffer result = new StringBuffer(pname);
      result.append('=');
      for (int i = 0; i < pvalues.length; i++) {
        if (i > 0) result.append(", ");
        result.append(pvalues[i]);
      }
      log.info("         parameter=" + result.toString());
    }
    log.info("          pathInfo=" + request.getPathInfo());
    log.info("          protocol=" + request.getProtocol());
    log.info("       queryString=" + request.getQueryString());
    log.info("        remoteAddr=" + request.getRemoteAddr());
    log.info("        remoteHost=" + request.getRemoteHost());
    log.info("        remoteUser="******"requestedSessionId=" + request.getRequestedSessionId());
    log.info("            scheme=" + request.getScheme());
    log.info("        serverName=" + request.getServerName());
    log.info("        serverPort=" + request.getServerPort());
    log.info("       servletPath=" + request.getServletPath());
    log.info("          isSecure=" + request.isSecure());
    log.info("---------------------------------------------------------------");

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

    // Log post-service information
    log.info("---------------------------------------------------------------");
    log.info("          authType=" + request.getAuthType());
    log.info("     contentLength=" + response.getContentLength());
    log.info("       contentType=" + response.getContentType());
    Cookie rcookies[] = response.getCookies();
    for (int i = 0; i < rcookies.length; i++) {
      log.info(
          "            cookie="
              + rcookies[i].getName()
              + "="
              + rcookies[i].getValue()
              + "; domain="
              + rcookies[i].getDomain()
              + "; path="
              + rcookies[i].getPath());
    }
    String rhnames[] = response.getHeaderNames();
    for (int i = 0; i < rhnames.length; i++) {
      String rhvalues[] = response.getHeaderValues(rhnames[i]);
      for (int j = 0; j < rhvalues.length; j++)
        log.info("            header=" + rhnames[i] + "=" + rhvalues[j]);
    }
    log.info("           message=" + response.getMessage());
    log.info("        remoteUser="******"            status=" + response.getStatus());
    log.info("===============================================================");
  }
    public boolean validate(Request request) {
      if ((userName == null)
          || (realmName == null)
          || (nonce == null)
          || (uri == null)
          || (response == null)) {
        return false;
      }

      // Validate the URI - should match the request line sent by client
      if (validateUri) {
        String uriQuery;
        String query = request.getQueryString();
        if (query == null) {
          uriQuery = request.getRequestURI();
        } else {
          uriQuery = request.getRequestURI() + "?" + query;
        }
        if (!uri.equals(uriQuery)) {
          // Some clients (older Android) use an absolute URI for
          // DIGEST but a relative URI in the request line.
          // request. 2.3.5 < fixed Android version <= 4.0.3
          String host = request.getHeader("host");
          String scheme = request.getScheme();
          if (host != null && !uriQuery.startsWith(scheme)) {
            StringBuilder absolute = new StringBuilder();
            absolute.append(scheme);
            absolute.append("://");
            absolute.append(host);
            absolute.append(uriQuery);
            if (!uri.equals(absolute.toString())) {
              return false;
            }
          } else {
            return false;
          }
        }
      }

      // Validate the Realm name
      String lcRealm = getRealmName(request.getContext());
      if (!lcRealm.equals(realmName)) {
        return false;
      }

      // Validate the opaque string
      if (!opaque.equals(opaqueReceived)) {
        return false;
      }

      // Validate nonce
      int i = nonce.indexOf(":");
      if (i < 0 || (i + 1) == nonce.length()) {
        return false;
      }
      long nonceTime;
      try {
        nonceTime = Long.parseLong(nonce.substring(0, i));
      } catch (NumberFormatException nfe) {
        return false;
      }
      String md5clientIpTimeKey = nonce.substring(i + 1);
      long currentTime = System.currentTimeMillis();
      if ((currentTime - nonceTime) > nonceValidity) {
        nonceStale = true;
        synchronized (nonces) {
          nonces.remove(nonce);
        }
      }
      String serverIpTimeKey = request.getRemoteAddr() + ":" + nonceTime + ":" + key;
      byte[] buffer =
          ConcurrentMessageDigest.digestMD5(serverIpTimeKey.getBytes(StandardCharsets.ISO_8859_1));
      String md5ServerIpTimeKey = MD5Encoder.encode(buffer);
      if (!md5ServerIpTimeKey.equals(md5clientIpTimeKey)) {
        return false;
      }

      // Validate qop
      if (qop != null && !QOP.equals(qop)) {
        return false;
      }

      // Validate cnonce and nc
      // Check if presence of nc and Cnonce is consistent with presence of qop
      if (qop == null) {
        if (cnonce != null || nc != null) {
          return false;
        }
      } else {
        if (cnonce == null || nc == null) {
          return false;
        }
        // RFC 2617 says nc must be 8 digits long. Older Android clients
        // use 6. 2.3.5 < fixed Android version <= 4.0.3
        if (nc.length() < 6 || nc.length() > 8) {
          return false;
        }
        long count;
        try {
          count = Long.parseLong(nc, 16);
        } catch (NumberFormatException nfe) {
          return false;
        }
        NonceInfo info;
        synchronized (nonces) {
          info = nonces.get(nonce);
        }
        if (info == null) {
          // Nonce is valid but not in cache. It must have dropped out
          // of the cache - force a re-authentication
          nonceStale = true;
        } else {
          if (!info.nonceCountValid(count)) {
            return false;
          }
        }
      }
      return true;
    }