package org.pac4j.http.client.direct;

import org.pac4j.core.client.DirectClient;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.authenticator.Authenticator;
import org.pac4j.core.exception.http.UnauthorizedAction;
import org.pac4j.core.profile.creator.ProfileCreator;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.http.credentials.CredentialUtil;
import org.pac4j.http.credentials.DigestCredentials;
import org.pac4j.http.credentials.extractor.DigestAuthExtractor;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>This class is the client to authenticate users directly through HTTP digest auth.</p>
 * <p>Add the <code>commons-codec</code> dependency to use this class.</p>
 *
 * @author Mircea Carasel
 * @since 1.9.0
 */
public class DirectDigestAuthClient extends DirectClient<DigestCredentials> {

    private String realm = "pac4jRealm";

    public DirectDigestAuthClient() {
    }

    public DirectDigestAuthClient(final Authenticator digestAuthenticator) {
        defaultAuthenticator(digestAuthenticator);
    }

    public DirectDigestAuthClient(final Authenticator digestAuthenticator,
                                 final ProfileCreator profileCreator) {
        defaultAuthenticator(digestAuthenticator);
        defaultProfileCreator(profileCreator);
    }

    @Override
    protected void clientInit() {
        defaultCredentialsExtractor(new DigestAuthExtractor());
    }

    /** Per RFC 2617
     * If a server receives a request for an access-protected object, and an
     * acceptable Authorization header is not sent, the server responds with
     * a "401 Unauthorized" status code, and a WWW-Authenticate header
     */
    @Override
    protected DigestCredentials retrieveCredentials(final WebContext context) {
        DigestCredentials credentials = super.retrieveCredentials(context);
        if (credentials == null) {
            String nonce = calculateNonce();
            context.setResponseHeader(HttpConstants.AUTHENTICATE_HEADER, "Digest realm=\"" + realm + "\", qop=\"auth\", nonce=\""
                + nonce + "\"");
            throw UnauthorizedAction.INSTANCE;
        }
        return credentials;
    }

    /**
     * A server-specified data string which should be uniquely generated each time a 401 response is made (RFC 2617)
     * Based on current time including nanoseconds
     */
    private String calculateNonce() {
        LocalDateTime time = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy:MM:dd:HH:mm:ss.SSS");
        String fmtTime = formatter.format(time);
        return CredentialUtil.encryptMD5(fmtTime + CommonHelper.randomString(10));
    }

    public String getRealm() {
        return realm;
    }

    public void setRealm(final String realm) {
        this.realm = realm;
    }

    @Override
    public String toString() {
        return CommonHelper.toNiceString(this.getClass(), "name", getName(), "realm", this.realm, "extractor", getCredentialsExtractor(),
                "authenticator", getAuthenticator(), "profileCreator", getProfileCreator());
    }
}

@@ -229,65 +229,8 @@
 or;%0A
-import org.pac4j.core.exception.http.UnauthorizedAction;%0A
 impo
@@ -1817,110 +1817,52 @@
     
-DigestCredentials credentials = super.retrieveCredentials(context);%0A        if (credentials == null) %7B
+// set the www-authenticate in case of error
 %0A   
@@ -1862,27 +1862,29 @@
 ror%0A        
-   
+final
  String nonc
@@ -1901,28 +1901,24 @@
 ateNonce();%0A
-    
         cont
@@ -2043,20 +2043,16 @@
         
-    
 + nonce 
@@ -2060,24 +2060,25 @@
  %22%5C%22%22);%0A
+%0A
         
     thro
@@ -2073,73 +2073,30 @@
     
-    throw UnauthorizedAction.INSTANCE;%0A        %7D%0A        return c
+return super.retrieveC
 rede
@@ -2101,16 +2101,25 @@
 dentials
+(context)
 ;%0A    %7D%0A

fix the behavior of DirectDigestAuthClient