使用Java&amp ;;摘要验证Apache客户端:始终401未经授权 [英] Digest auth with Java & Apache client : Always 401 Unauthorized

查看:714
本文介绍了使用Java&amp ;;摘要验证Apache客户端:始终401未经授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用HTTP客户端实现摘要身份验证,但目前无效。

I'm trying to implement digest auth with an HTTP client, but this does not work at the moment.

有人可以检查此代码是否正确吗?出于测试目的,我使用 http://httpbin.org/ ,但我得到的只是 HTTP /1.1 401未经授权

Can someone check if this code is correct? For testing purpose I use http://httpbin.org/, but all I get is HTTP/1.1 401 Unauthorized.

以下是示例代码:

private static void doDigestAuth() throws ClientProtocolException,
    IOException,
    AuthenticationException,
    MalformedChallengeException
{

    HttpHost target = new HttpHost("httpbin.org", 80, "http");
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(new AuthScope(target.getHostName(), target.getPort()), new UsernamePasswordCredentials(
        "user", "passwd"));
    CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
    try {

        HttpGet httpget = new HttpGet("http://httpbin.org/digest-auth/auth/user/passwd");

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();
        // Generate DIGEST scheme object, initialize it and add it to the local
        // auth cache
        DigestScheme digestAuth = new DigestScheme();

        // Suppose we already know the realm name
        digestAuth.overrideParamter("realm", "me@kennethreitz.com");
        // // Suppose we already know the expected nonce value
        // digestAuth.overrideParamter("nonce", Long.toString(new SecureRandom().nextLong(), 36));
        // qop-value = "auth" | "auth-int" | token
        digestAuth.overrideParamter("qop", "auth");
        authCache.put(target, digestAuth);

        // Add AuthCache to the execution context
        HttpClientContext context = HttpClientContext.create();
        context.setCredentialsProvider(credsProvider);
        // context.setAuthSchemeRegistry(authRegistry);
        context.setAuthCache(authCache);

        System.out.println("Executing request " + httpget.getRequestLine() + " to target " + target);
        for (int i = 0; i < 3; i++) {
            CloseableHttpResponse response = httpclient.execute(httpget, context);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                HttpEntity entity = response.getEntity();
                InputStream instream = entity.getContent();
                // Header contentCncoding = entity .getContentEncoding();
                String contentString = IOUtils.toString(instream, null);
                System.out.println("ContentString:" + contentString);
                AuthState proxyAuthState = context.getProxyAuthState();
                System.out.println("Proxy auth state: " + proxyAuthState.getState());
                System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
                System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
                AuthState targetAuthState = context.getTargetAuthState();
                System.out.println("Target auth state: " + targetAuthState.getState());
                System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
                System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
                EntityUtils.consume(response.getEntity());
            }
            finally {
                response.close();
            }
        }
    }
    finally {
        httpclient.close();
    }

}


推荐答案

@heaphach建议这是一个cookie问题。有线日志(显示日志类别 org.apache.http.wire 设置为调试)显示:

< < Set-Cookie:fake = fake_value [\ r] [\ n]

但是HttpClient永远不会选择这个
并且不会在第二个GET请求包含带有摘要响应的完整授权标头。
因此,服务器只是忽略了摘要响应。

It was a cookie problem as @heaphach suggested. The wire-log (shown with log category org.apache.http.wire set to debug) shows:
<< "Set-Cookie: fake=fake_value[\r][\n]"
but the HttpClient never picks this up and does not use it in the second GET request containing the full "Authorization" header with the digest-response. As a consequence, the server just ignores the digest response.

我更新了示例代码(也称为抢先DIGEST认证示例
,代码如下所示(从HTTP状态管理中复制教程),服务器响应200 OK。

After I updated the example code (also known as the Preemptive DIGEST authentication example) with the code shown below (copied from the HTTP state management tutorial), the server responded "200 OK".

CookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("fake", "fake_value");
cookie.setDomain("httpbin.org");
cookie.setPath("/");
cookieStore.addCookie(cookie);
CloseableHttpClient httpclient = HttpClients.custom()
        .setDefaultCookieStore(cookieStore)
        .setDefaultCredentialsProvider(credsProvider)
        .build();

我还遇到了要点包含一些代码来计算nonce
所以你可以使用

digestAuth.overrideParamter(nonce ,calculateNonce());

org.apache.http.impl.auth.HttpAuthenticator 不再显示错误消息在挑战中缺少nonce。

I also came across a gist containing some code to calculate a "nonce" so you can use
digestAuth.overrideParamter("nonce", calculateNonce());
and org.apache.http.impl.auth.HttpAuthenticator no longer shows the error message "missing nonce in challenge".

public static synchronized String calculateNonce() {

    Date d = new Date();
    SimpleDateFormat f = new SimpleDateFormat("yyyy:MM:dd:hh:mm:ss");
    String fmtDate = f.format(d);
    Random rand = new Random(100000);
    Integer randomInt = rand.nextInt();
    return org.apache.commons.codec.digest.DigestUtils.md5Hex(fmtDate + randomInt.toString());
}

这篇关于使用Java&amp ;;摘要验证Apache客户端:始终401未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆