I am using Microsoft Reporting API to get Azure AD Logon Activity. When i request access token,I am getting SSL handshake exception sometime. Sometime working fine without an issue
Url to get access token : //login.microsoftonline.com/test.onmicrooft.com/oauth2/token?api-version=1.0
Stacktrace
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:992)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at
sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1282)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1257)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at
sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at java.lang.Thread.run(Thread.java:745)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: Caused by: java.io.EOFException: SSL peer shut down incorrectly|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.security.ssl.InputRecord.read(InputRecord.java:505)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)|
[10:03:48:293]|[12-23-2020]|[SYSERR]|[INFO]|[931]: ... 14 more|
- Remove From My Forums
Question
Hi,
Are there any issues with Azure Blob Storage in Australia East region?
One of our clients has lost the ability to connect to the storage account over the weekend? The issue is related to TLS protocol version.
Azure Status page showing everything ok.
Henryk
Answers
- Proposed as answer by Adam Smith (Azure) Tuesday, January 30, 2018 4:42 PM
- Marked as answer by HenrykA Thursday, February 1, 2018 9:42 AM
All replies
As far as we know, there has been no changes on their end.
They first lost connectivity on their CERT system around Friday evening and the same thing happened on PROD on Monday morning.
Henryk
- Proposed as answer by Adam Smith (Azure) Tuesday, January 30, 2018 4:42 PM
- Marked as answer by HenrykA Thursday, February 1, 2018 9:42 AM
SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine. In this post, we will learn about fixing this if you are using Apache HttpClient library to create HttpClient to connect to SSL/TLS secured URLs. The exception logs will look like this. I have
already posted code fix to bypass SSL matching in earlier post.
Unfortunately, that fix works in TLS and TLS 1.1 protocols. It doesn’t work in TLS 1.2 protocol. So ultimately, you need to fix the certificate issue anyway. There is ‘no code only’ fix for this.
Now there are two ways, you can utilize the imported certificate from server. Either add certificate to the JDK cacerts store; or pass certificate information in JVM aruguments.
1) Import certificate to JDK cacert store
- Import the certificate from server.
- Use given command to add the certificate to JDK store. (Remove new line characters).keytool -import -noprompt -trustcacerts -alias MAVEN-ROOT -file C:/Users/Lokesh/keys/cert/maven.cer -keystore "C:/Program Files (x86)/Java/jdk8/jre/lib/security/cacerts" -storepass changeit
Now create HTTP client as given:
public HttpClient createTlsV2HttpClient() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", f) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry); CloseableHttpClient client = HttpClients .custom() .setSSLSocketFactory(f) .setConnectionManager(cm) .build(); return client; }Notice the code : SSLContext.getInstance("TLSv1.2"). This code picks up the certificates added to JDK cacert store. So make a note of it.
2) Pass certificate information in JVM aruguments
- Import the certicate from server.
- Add JVM arguments while starting the server. Change the parameter values as per your application.-Djavax.net.ssl.keyStore="C:/Users/Lokesh\keys\maven.jks" -Djavax.net.ssl.keyStorePassword="test" -Djavax.net.ssl.trustStore="C:/Users/Lokesh\keys\maven.jks" -Djavax.net.ssl.trustStorePassword="test"
Now create HTTP client as given:
public HttpClient createTlsV2HttpClient() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException { SSLContext sslContext = SSLContexts.createSystemDefault(); SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", f) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry); CloseableHttpClient client = HttpClients .custom() .setSSLSocketFactory(f) .setConnectionManager(cm) .build(); return client; }Notice the code : SSLContext.createSystemDefault(). This code picks up the certificates passed as JVM arguments. Again, make a note of it.
Summary
- Use SSLContext.getInstance("TLSv1.2") when certificate is added to JDK cacert store.
- Use SSLContext.createSystemDefault() when SSL info is passed as JVM argument.
Drop me your questions in comments section.
Happy Learning !!