Skip to content
Advertisement

PKIX path building failed in OAuth Authentication in Java

I am trying to Authenticate in discogs:

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

on the Point 2: SEND A GET REQUEST TO THE DISCOGS REQUEST TOKEN URL, I get this:

oauth_token=tnMYYwCBsvoecGyBsANXyVKQtICTdDnnzRPeGUfa
oauth_token_secret=xwHpnTRYNJIpdkkTJLMsfXECdHgXeQUrDjzmktPw
oauth_callback_confirmed=true

on the POINT 3: REDIRECT YOUR USER TO THE DISCOGS AUTHORIZE PAGE,

I’ve created this piece of code:

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();

}

But I got this error:

but I get this error:

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)

Advertisement

Answer

The error provided indicates that your application is unable to establish a SSL secure communication with the remote server, discogs.com, because it is unable to find a valid certificate for that server among the ones configured to trust.

Under the hood, HttpURLConnection will use Java Secure Socket Extension for establishing secure SSL communications.

In order to solve the problem you have several options, mainly:

  • Run your application with the javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword system properties pointing to a keystore and respectively password that contains your server certificates.
  • Include the server certificate in a trusted, default, keystore, one of:
    • <java-home>/lib/security/jssecacerts
    • <java-home>/lib/security/cacerts

No matter the chosen mechanism, be sure that the desired keystore contains all the necessary certificates to trust the remote server, not only the SSL certificate itself, but all the certificates in the certificate chain.

openssl provides an useful command that allows you to obtain all the certificates used in the SSL connection. In this case, it will provide the following information, among other:

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
---

In this case, it seems that the server is using a self-signed certificate to identify itself. You new to configure Java to trust that certificate.

Copy and paste the certificate text outputted in the command, including —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—–, and save to a new file, discogs.pem, for example.

In order to be imported in a Java keystore, it should be converted to DER format first. You can do that with openssl as well:

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

Then, import the certificate in a keystore. As indicated, you can import it in the default JVM kystore, or in a new one. Let’s consider the later case and create a new keystore named, for example, discogs:

keytool -import -keystore discogs -file discogs.der

Provide a password of your convenience, let’s assume changeme for example.

Now, run the application with the above-mentioned system properties:

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

If necessary, in order to troubleshoot the problem, you can use the javax.net.debug system property with an appropriate value, all or ssl:

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

Please, consider review this related SO question, it may be of help.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement