public void challenge(HttpServletRequest req, HttpServletResponse resp) {

    boolean stale = false;

    if (this.maintainState) {

      String authHeader = req.getHeader("Authorization");
      if (authHeader != null) {

        String headerFields = authHeader.substring("Digest: ".length() - 1);

        String nonce = HttpUtil.extractHeaderField(headerFields, "nonce");
        String opaque = HttpUtil.extractHeaderField(headerFields, "opaque");
        if (nonce != null && opaque != null) {
          StateEntry entry = (StateEntry) this.stateMap.remove(nonce + ":" + opaque);
          if (entry != null) {
            stale = entry.isStale();
          }
        }
      }
    }

    String nonce = generateNonce();
    String opaque = generateOpaque();

    // FIXME: Why is getRealm() deprecated?
    String challengeHeader = "Digest realm=\"" + this.principalStore.getRealm() + "\"";
    challengeHeader += ", nonce=\"" + nonce + "\"";
    challengeHeader += ", opaque=\"" + opaque + "\"";
    challengeHeader += ", stale=" + stale;
    challengeHeader += ", algorithm=MD5";
    challengeHeader += ", qop=auth";

    if (this.maintainState) {

      Date timestamp = new Date();
      StateEntry entry = new StateEntry(null, timestamp, nonce, 1, opaque);
      this.stateMap.put(nonce + ":" + opaque, entry);
    }

    try {
      resp.setHeader("WWW-Authenticate", challengeHeader);
      resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    } catch (IOException e) {
      throw new AuthenticationProcessingException(
          "Unable to present authentication challenge to user", e);
    }
  }
  public boolean isRecognizedAuthenticationRequest(HttpServletRequest req) {

    String authHeader = req.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Digest ")) {
      return false;
    }

    String headerFields = authHeader.substring("Digest: ".length() - 1);
    String username = HttpUtil.extractHeaderField(headerFields, "username");
    if (username == null) {
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Unable to extract field 'username' from header: " + authHeader);
      }
      return false;
    }

    Principal principal = null;

    try {
      principal = principalFactory.getPrincipal(username, Principal.Type.USER);
    } catch (InvalidPrincipalException e) {
      return false;
    }

    if (this.excludedPrincipals != null
        && this.excludedPrincipals.contains(principal.getQualifiedName())) {
      return false;
    }

    if (this.recognizedDomains == null || this.recognizedDomains.contains(principal.getDomain()))
      return true;

    return false;
  }
  public AuthResult authenticate(HttpServletRequest request) throws AuthenticationException {

    String authHeader = request.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Digest ")) {
      throw new InvalidAuthenticationRequestException(
          "Authorization header either missing or does not start with 'Digest'");
    }

    if (this.logger.isDebugEnabled()) {
      this.logger.debug("Authentication header: " + authHeader);
    }

    String headerFields = authHeader.substring("Digest: ".length() - 1);

    String uri = HttpUtil.extractHeaderField(headerFields, "uri");

    String response = HttpUtil.extractHeaderField(headerFields, "response");
    String nc = HttpUtil.extractHeaderField(headerFields, "nc");
    String nonce = HttpUtil.extractHeaderField(headerFields, "nonce");
    String cnonce = HttpUtil.extractHeaderField(headerFields, "cnonce");
    String qop = HttpUtil.extractHeaderField(headerFields, "qop");
    String username = HttpUtil.extractHeaderField(headerFields, "username");
    String opaque = HttpUtil.extractHeaderField(headerFields, "opaque");

    if (response == null) {
      throw new InvalidAuthenticationRequestException(
          "Missing authentication header field 'response'");
    }
    if (username == null) {
      throw new InvalidAuthenticationRequestException(
          "Missing authentication header field 'username'");
    }

    if (this.logger.isDebugEnabled()) {
      this.logger.debug(
          "Authentication fields: uri = '"
              + uri
              + "', "
              + "response = '"
              + response
              + "', "
              + "nc = '"
              + nc
              + "', cnonce = '"
              + cnonce
              + "', "
              + "qop = '"
              + qop
              + "', username = '******'");
    }

    return doAuthenticate(request, uri, response, nc, nonce, cnonce, qop, username, opaque);
  }
  public boolean postAuthentication(HttpServletRequest req, HttpServletResponse resp) {

    String authHeader = req.getHeader("Authorization");
    if (authHeader == null) {
      return false;
    }

    String headerFields = authHeader.substring("Digest: ".length() - 1);

    String nonce = HttpUtil.extractHeaderField(headerFields, "nonce");
    String opaque = HttpUtil.extractHeaderField(headerFields, "opaque");
    if (nonce == null || opaque == null) {
      return false;
    }

    Principal principal = SecurityContext.getSecurityContext().getPrincipal();
    if (principal == null) {
      return false;
    }

    if (this.maintainState) {

      StateEntry entry = (StateEntry) this.stateMap.remove(nonce + ":" + opaque);
      if (entry == null) {
        return false;
      }
      Date timestamp = new Date();
      String nextNonce = this.generateNonce();
      entry.setUsername(principal.getQualifiedName());
      entry.setNonce(nextNonce);
      entry.setTimestamp(timestamp);
      entry.setNonceCount(entry.getNonceCount() + 1);
      entry.setStale(false);

      this.stateMap.put(nextNonce + ":" + opaque, entry);
      resp.addHeader("Authentication-Info", "nextnonce=" + nextNonce);
    }

    return false;
  }