简体   繁体   English

如何在 JAVA 中使用基于 SHA-256 算法的 Digest 认证实现登录

[英]How to implement login using SHA-256 algorithm based Digest authentication in JAVA

I'm trying to implement a Digest authentication based login using SHA-256 algorithm in java, but not getting much help.我正在尝试在 java 中使用 SHA-256 算法实现基于摘要身份验证的登录,但没有得到太多帮助。 I'm able to login using POSTMAN and getting HTTP status code 200, but not sure how POSTMAN has used the SHA-256 here, Postman request config snapshot and My implementation below, which throws SSLHandshakeException. I'm able to login using POSTMAN and getting HTTP status code 200, but not sure how POSTMAN has used the SHA-256 here, Postman request config snapshot and My implementation below, which throws SSLHandshakeException. 在此处输入图像描述

Here's my code using which I'm getting Handshake failure:这是我遇到握手失败的代码:

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.*;

import junit.framework.Assert;

public class DigestTest {

    private static final String URL = "https://10.0.1.190/API/Web/Login";
    private static final String USER = "admin";
    private static final String PASSWORD = "testing123456";


    public static void main(String[] args) throws Exception {

        new DigestTest().run();
    }

    public void run() throws Exception {
        System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");

        HttpPost httpPost = new HttpPost(URL);

        HttpHost target
                = new HttpHost(httpPost.getURI().getHost(), 443, "https");
        CredentialsProvider credsProvider = new BasicCredentialsProvider();

        UsernamePasswordCredentials credentials
                = new UsernamePasswordCredentials(USER, PASSWORD);
        credsProvider.setCredentials(
                new AuthScope(target.getHostName(), target.getPort()),
                credentials);

        CookieStore cookieStore = new BasicCookieStore();

        CloseableHttpClient httpclient
                = HttpClients.custom().setDefaultCookieStore(cookieStore)
                        .setDefaultCredentialsProvider(credsProvider).build();

        try {

            DigestScheme digestAuth = new DigestScheme();

            digestAuth.overrideParamter("qop", "auth");
            digestAuth.overrideParamter("nc", "0");
            digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce());
            digestAuth.overrideParamter("algorithm", "SHA-256");

            AuthCache authCache = new BasicAuthCache();
            authCache.put(target, digestAuth);

            HttpClientContext localContext = HttpClientContext.create();
            localContext.setAuthCache(authCache);

            CloseableHttpResponse response;

            response = httpclient.execute(target, httpPost, localContext);
            Map<String, String> wwwAuth = Arrays
                    .stream(response.getHeaders("WWW-Authenticate")[0]
                            .getElements())
                    .collect(Collectors.toMap(HeaderElement::getName,
                            HeaderElement::getValue));

            // the first call ALWAYS fails with a 401
//            Assert.assertEquals(response.getStatusLine().getStatusCode(), 401);

            digestAuth.overrideParamter("opaque", wwwAuth.get("opaque"));
            digestAuth.overrideParamter("nonce", wwwAuth.get("nonce"));
            digestAuth.overrideParamter("realm", wwwAuth.get("Digest realm"));
            Header authenticate = digestAuth.authenticate(credentials, httpPost,
                    localContext);
            httpPost.addHeader(authenticate);

            response = httpclient.execute(target, httpPost, localContext);

            // the 2nd call is the real deal
//            Assert.assertEquals(response.getStatusLine().getStatusCode(), 200);

            //System.out.println(IOUtils
              //      .toString(response.getEntity().getContent(), "utf-8"));
            System.out.println(response.getEntity().getContent().toString());

        } catch(Exception e){
            System.out.println("Exception : \n"+e);
        } finally {
            httpclient.close();
        }
    }

}

I'm getting the exception below:我收到以下异常:

Exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure异常:javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure

Please help with the code rectification.请帮助代码更正。

In postman you can export your request to a code snippet (see https://learning.postman.com/docs/sending-requests/generate-code-snippets/ how).在 postman 中,您可以将请求导出到代码片段(请参阅https://learning.postman.com/docs/sending-requests/generate-code-sniphow )。

In your case, the java snippet using the OkHttp client will be:在您的情况下,使用OkHttp客户端的 java 片段将是:

OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "{}");
Request request = new Request.Builder()
  .url("https://test.it/uri")
  .method("POST", body)
  .addHeader("Authorization", 
             "Digest username=\"username\", realm=\"test\", nonce=\"nonce\", uri=\"/uri\", 
             algorithm=\"SHA-256\", 
             response=\"6d46e1187d1e79c88241d4ae0e57eda1cd572dfb027ce9eded02aea499f15695\""
  )
  .addHeader("Content-Type", "text/plain")
  .build();
Response response = client.newCall(request).execute();

(Notice that you need to replace the username , realm , nonce and uri with your actual values.) . (请注意,您需要将usernamerealmnonceuri替换为您的实际值。)

To compute the response value, you can see the formula (for MD5) in https://en.wikipedia.org/wiki/Digest_access_authentication .要计算response值,您可以在https://en.wikipedia.org/wiki/Digest_access_authentication中查看公式(用于 MD5)。

In the code above the computation with SHA256 instead of MD5 is the following:在上面的代码中,使用 SHA256 而不是 MD5 的计算如下:

HA1 = SHA256(username:realm:password) = SHA256(username:test:password) = 338c3ad443d25c378fdcdb90df9f81d42161278b8f1f03276a2d14f0803165f2
HA2 = SHA256(method:digestURI) = SHA256(POST:/uri) = fc51c21830fc2b6ffe97afe3290df89e7c2b1e287d6e373ad4282ce7fe912650
response = SHA256(HA1:nonce:HA2) = SHA256(338c3ad443d25c378fdcdb90df9f81d42161278b8f1f03276a2d14f0803165f2:nonce:fc51c21830fc2b6ffe97afe3290df89e7c2b1e287d6e373ad4282ce7fe912650)
= 6d46e1187d1e79c88241d4ae0e57eda1cd572dfb027ce9eded02aea499f15695

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM