Search in sources :

Example 1 with BasicNameValuePair

use of com.burgstaller.okhttp.digest.fromhttpclient.BasicNameValuePair in project okhttp-digest by rburgst.

the class DigestAuthenticator method createDigestHeader.

/**
 * Creates digest-response header as defined in RFC2617.
 *
 * @param credentials User credentials
 * @return The digest-response as String.
 */
// @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("LSC_LITERAL_STRING_COMPARISON")
private synchronized NameValuePair createDigestHeader(final Credentials credentials, final Request request, final Map<String, String> parameters) throws AuthenticationException {
    final String uri = parameters.get("uri");
    final String realm = parameters.get("realm");
    final String nonce = parameters.get("nonce");
    final String opaque = parameters.get("opaque");
    final String method = parameters.get("methodname");
    String algorithm = parameters.get("algorithm");
    // If an algorithm is not specified, default to MD5.
    if (algorithm == null) {
        algorithm = "MD5";
    }
    final Set<String> qopset = new HashSet<>(8);
    int qop = QOP_UNKNOWN;
    final String qoplist = parameters.get("qop");
    if (qoplist != null) {
        final StringTokenizer tok = new StringTokenizer(qoplist, ",");
        while (tok.hasMoreTokens()) {
            final String variant = tok.nextToken().trim();
            qopset.add(variant.toLowerCase(Locale.US));
        }
        if (request.body() != null && qopset.contains("auth-int")) {
            qop = QOP_AUTH_INT;
        } else if (qopset.contains("auth")) {
            qop = QOP_AUTH;
        }
    } else {
        qop = QOP_MISSING;
    }
    if (qop == QOP_UNKNOWN) {
        throw new AuthenticationException("None of the qop methods is supported: " + qoplist);
    }
    String charset = parameters.get("charset");
    if (charset == null) {
        charset = "ISO-8859-1";
    }
    String digAlg = algorithm;
    if ("MD5-sess".equalsIgnoreCase(digAlg)) {
        digAlg = "MD5";
    }
    final MessageDigest digester;
    try {
        digester = createMessageDigest(digAlg);
    } catch (final UnsupportedDigestAlgorithmException ex) {
        throw new AuthenticationException("Unsuppported digest algorithm: " + digAlg, ex);
    }
    final String uname = credentials.getUserName();
    final String pwd = credentials.getPassword();
    if (nonce.equals(this.lastNonce)) {
        nounceCount++;
    } else {
        nounceCount = 1;
        cnonce = null;
        lastNonce = nonce;
    }
    final StringBuilder sb = new StringBuilder(256);
    final Formatter formatter = new Formatter(sb, Locale.US);
    formatter.format("%08x", nounceCount);
    formatter.close();
    final String nc = sb.toString();
    if (cnonce == null) {
        cnonce = createCnonce();
    }
    a1 = null;
    a2 = null;
    // 3.2.2.2: Calculating digest
    if ("MD5-sess".equalsIgnoreCase(algorithm)) {
        // H( unq(username-value) ":" unq(realm-value) ":" passwd )
        // ":" unq(nonce-value)
        // ":" unq(cnonce-value)
        // calculated one per session
        sb.setLength(0);
        sb.append(uname).append(':').append(realm).append(':').append(pwd);
        final String checksum = encode(digester.digest(getBytes(sb.toString(), charset)));
        sb.setLength(0);
        sb.append(checksum).append(':').append(nonce).append(':').append(cnonce);
        a1 = sb.toString();
    } else {
        // unq(username-value) ":" unq(realm-value) ":" passwd
        sb.setLength(0);
        sb.append(uname).append(':').append(realm).append(':').append(pwd);
        a1 = sb.toString();
    }
    final String hasha1 = encode(digester.digest(getBytes(a1, charset)));
    if (qop == QOP_AUTH) {
        // Method ":" digest-uri-value
        a2 = method + ':' + uri;
    } else if (qop == QOP_AUTH_INT) {
        // Method ":" digest-uri-value ":" H(entity-body)
        RequestBody entity = request.body();
        if (entity != null) {
            // If the entity is not repeatable, try falling back onto QOP_AUTH
            if (qopset.contains("auth")) {
                qop = QOP_AUTH;
                a2 = method + ':' + uri;
            } else {
                throw new AuthenticationException("Qop auth-int cannot be used with " + "a non-repeatable entity");
            }
        } else {
            // code straight from
            // https://github.com/apache/httpclient/blob/4.3.x/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java#L363
            // not sure if this will actually work with an empty body.
            final HttpEntityDigester entityDigester = new HttpEntityDigester(digester);
            try {
                entityDigester.close();
            } catch (final IOException ex) {
                throw new AuthenticationException("I/O error reading entity content", ex);
            }
            a2 = method + ':' + uri + ':' + encode(entityDigester.getDigest());
        }
    } else {
        a2 = method + ':' + uri;
    }
    final String hasha2 = encode(digester.digest(getBytes(a2, charset)));
    // 3.2.2.1
    final String digestValue;
    if (qop == QOP_MISSING) {
        sb.setLength(0);
        sb.append(hasha1).append(':').append(nonce).append(':').append(hasha2);
        digestValue = sb.toString();
    } else {
        sb.setLength(0);
        sb.append(hasha1).append(':').append(nonce).append(':').append(nc).append(':').append(cnonce).append(':').append(qop == QOP_AUTH_INT ? "auth-int" : "auth").append(':').append(hasha2);
        digestValue = sb.toString();
    }
    final String digest = encode(digester.digest(getAsciiBytes(digestValue)));
    final StringBuilder buffer = new StringBuilder(128);
    final String headerKey;
    if (isProxy()) {
        headerKey = PROXY_AUTH_RESP;
    } else {
        headerKey = WWW_AUTH_RESP;
    }
    buffer.append("Digest ");
    final List<NameValuePair> params = new ArrayList<>(20);
    params.add(new BasicNameValuePair("username", uname));
    params.add(new BasicNameValuePair("realm", realm));
    params.add(new BasicNameValuePair("nonce", nonce));
    params.add(new BasicNameValuePair("uri", uri));
    params.add(new BasicNameValuePair("response", digest));
    if (qop != QOP_MISSING) {
        params.add(new BasicNameValuePair("qop", qop == QOP_AUTH_INT ? "auth-int" : "auth"));
        params.add(new BasicNameValuePair("nc", nc));
        params.add(new BasicNameValuePair("cnonce", cnonce));
    }
    // algorithm cannot be null here
    params.add(new BasicNameValuePair("algorithm", algorithm));
    if (opaque != null) {
        params.add(new BasicNameValuePair("opaque", opaque));
    }
    for (int i = 0; i < params.size(); i++) {
        final NameValuePair param = params.get(i);
        if (i > 0) {
            buffer.append(", ");
        }
        final String name = param.getName();
        final boolean noQuotes = ("nc".equals(name) || "qop".equals(name) || "algorithm".equals(name));
        BasicHeaderValueFormatter.DEFAULT.formatNameValuePair(buffer, param, !noQuotes);
    }
    return new BasicNameValuePair(headerKey, buffer.toString());
}
Also used : NameValuePair(com.burgstaller.okhttp.digest.fromhttpclient.NameValuePair) BasicNameValuePair(com.burgstaller.okhttp.digest.fromhttpclient.BasicNameValuePair) HttpEntityDigester(com.burgstaller.okhttp.digest.fromhttpclient.HttpEntityDigester) Formatter(java.util.Formatter) BasicHeaderValueFormatter(com.burgstaller.okhttp.digest.fromhttpclient.BasicHeaderValueFormatter) ArrayList(java.util.ArrayList) IOException(java.io.IOException) StringTokenizer(java.util.StringTokenizer) UnsupportedDigestAlgorithmException(com.burgstaller.okhttp.digest.fromhttpclient.UnsupportedDigestAlgorithmException) BasicNameValuePair(com.burgstaller.okhttp.digest.fromhttpclient.BasicNameValuePair) MessageDigest(java.security.MessageDigest) HashSet(java.util.HashSet) RequestBody(okhttp3.RequestBody)

Aggregations

BasicHeaderValueFormatter (com.burgstaller.okhttp.digest.fromhttpclient.BasicHeaderValueFormatter)1 BasicNameValuePair (com.burgstaller.okhttp.digest.fromhttpclient.BasicNameValuePair)1 HttpEntityDigester (com.burgstaller.okhttp.digest.fromhttpclient.HttpEntityDigester)1 NameValuePair (com.burgstaller.okhttp.digest.fromhttpclient.NameValuePair)1 UnsupportedDigestAlgorithmException (com.burgstaller.okhttp.digest.fromhttpclient.UnsupportedDigestAlgorithmException)1 IOException (java.io.IOException)1 MessageDigest (java.security.MessageDigest)1 ArrayList (java.util.ArrayList)1 Formatter (java.util.Formatter)1 HashSet (java.util.HashSet)1 StringTokenizer (java.util.StringTokenizer)1 RequestBody (okhttp3.RequestBody)1