繁体   English   中英

OAuth 中的 PKIX 路径构建失败 Java 中的身份验证

[英]PKIX path building failed in OAuth Authentication in Java

我正在尝试在 discogs 中进行身份验证:

https://www.discogs.com/developers/#page:authentication,header:authentication-oauth-flow

关于第 2 点:向 DISCOGS 请求令牌 URL 发送 GET 请求,我明白了:

oauth_token=tnMYYwCBsvoecGyBsANXyVKQtICTdDnnzRPeGUfa
oauth_token_secret=xwHpnTRYNJIpdkkTJLMsfXECdHgXeQUrDjzmktPw
oauth_callback_confirmed=true

关于第 3 点:将您的用户重定向到 DISCOGS 授权页面,

我创建了这段代码:

private static void redirectUserToAuthorizePage(String consumerKey) throws IOException {

    String yourUrl = "https://discogs.com/oauth/authorize?oauth_token=" + consumerKey;
    URL url = new URL(yourUrl);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setDoOutput(true);
    conn.setRequestMethod("GET");

    int statusCode = conn.getResponseCode();
    System.out.println("Status Code: " + statusCode);

    conn.disconnect();

}

但我得到了这个错误:

但我收到此错误:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)

提供的错误表明您的应用程序无法与远程服务器discogs.com建立 SSL 安全通信,因为它无法在配置为信任的服务器中找到该服务器的有效证书。

在后台, HttpURLConnection将使用Java 安全套接字扩展来建立安全的 SSL 通信。

为了解决这个问题,你有几个选择,主要是:

  • 使用指向包含服务器证书的密钥库和密码的javax.net.ssl.trustStorejavax.net.ssl.trustStorePassword系统属性运行您的应用程序。
  • 将服务器证书包含在受信任的默认密钥库中,其中之一是:
    • <java-home>/lib/security/jssecacerts
    • <java-home>/lib/security/cacerts

无论选择何种机制,请确保所需的密钥库包含信任远程服务器所需的所有证书,不仅是 SSL 证书本身,还包括证书链中的所有证书。

openssl提供了一个有用的命令,允许您获取 SSL 连接中使用的所有证书。 在这种情况下,它将提供以下信息,其中包括:

depth=0 O = Acme Co, CN = Kubernetes Ingress Controller Fake Certificate
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = Acme Co, CN = Kubernetes Ingress Controller Fake Certificate
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
   i:/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
-----BEGIN CERTIFICATE-----
MIIDcDCCAligAwIBAgIRALyiewLACTbxSO/mUgPt2z8wDQYJKoZIhvcNAQELBQAw
SzEQMA4GA1UEChMHQWNtZSBDbzE3MDUGA1UEAxMuS3ViZXJuZXRlcyBJbmdyZXNz
IENvbnRyb2xsZXIgRmFrZSBDZXJ0aWZpY2F0ZTAeFw0yMTAzMTYyMjQ5MDVaFw0y
MjAzMTYyMjQ5MDVaMEsxEDAOBgNVBAoTB0FjbWUgQ28xNzA1BgNVBAMTLkt1YmVy
bmV0ZXMgSW5ncmVzcyBDb250cm9sbGVyIEZha2UgQ2VydGlmaWNhdGUwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDxBj7SvSJpus5+2s4HLhheJhmKEmcV
MTFIVf3xRDfGpVFeYKAc/o8oB3/OXrqr16kuv2g+bE2d59qVri1uTXX/CRHM6G0E
St/gEdUsGiO1e3VueYGkdgr//s7idEMD0tBHp9ITiR0XUFK75YdWCT6H24fetNzp
bOSMImEeSQsRexKqwcCvM6l4rNshJQ1BVD7NOYPBO9BJuEKU0wCd8yDF20Ig6Qwh
D8B6kRIfNIR1jaQbXGwsvowx4ZHtE4ETd5ftPvKFLfjTMRNFOenJMOeA9te3f2vA
f4jm8furOytI7+sQhZqstxbwPV9OI96rilq4P+ZjP3CW9bfubdyE8ccHAgMBAAGj
TzBNMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMB
Af8EAjAAMBgGA1UdEQQRMA+CDWluZ3Jlc3MubG9jYWwwDQYJKoZIhvcNAQELBQAD
ggEBADFd9W49IsGKTm6WBSsSPLuKn1NFlQmfuRljcZyB01seN7N8fvX4OG/fD+/A
g1nogwDbTl3g1AAyiU6iCKerZevolS2akLdbKwxg/olFRjgwdTN5668Dbz4o3MVY
21AJJ9qO14Oxdu5x+3VhMnsuQdcOzdpwVPmNWIOGQMPD+sOZ8d1hqFp6+3gFQpIL
4kEs2RhjZqwySYoQmBnURx8kbyrs3s/sH06v+CzJwVomf7amOaywJ/VuxmkF9JPp
pxxmlHfbSzlWZGRC4K0ij1+91r6EALVUGgonQGY3FsN2+JTTfg8J9FGqvjb7F+BO
PMPqU/pmCW5h8ej8eyNflagzLFE=
-----END CERTIFICATE-----
---
Server certificate
subject=/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
issuer=/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
---

在这种情况下,服务器似乎正在使用自签名证书来标识自己。 您新配置 Java 以信任该证书。

复制并粘贴命令中输出的证书文本,包括—–BEGIN CERTIFICATE—–—–END CERTIFICATE—– ,并保存到一个新文件,例如discogs.pem

为了在 Java 密钥库中导入,应首先将其转换为 DER 格式。 您也可以使用openssl来做到这一点:

openssl x509 -outform der -in discogs.pem -out discogs.der

然后,将证书导入密钥库。 如图所示,您可以将其导入默认的 JVM kystore 或新的。 让我们考虑后一种情况并创建一个名为discogs的新密钥库:

keytool -import -keystore discogs -file discogs.der

提供您方便的密码,我们假设changeme为例。

现在,使用上述系统属性运行应用程序:

java -Djavax.net.ssl.trustStore=discogs \
     -Djavax.net.ssl.trustStorePassword=changeme \
     your.Application

如有必要,为了解决问题,您可以使用具有适当值的javax.net.debug系统属性allssl

java -Djavax.net.debug=ssl \
     -Djavax.net.ssl.trustStore=discogs \
     -Djavax.net.ssl.trustStorePassword=password \
     your.Application

请考虑查看这个相关的 SO question ,它可能会有所帮助。

暂无
暂无

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

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