From f5f7cd30e333a9892e2ccdc5ca2f028120c149b1 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Sun, 27 Jan 2019 13:17:35 +0200 Subject: [PATCH 01/21] Expose a method 'GetBlobUriFromClientResourceManager' to get temporary blob uri for ingestion --- .../com/microsoft/azure/kusto/data/ClientImpl.java | 13 ++++++++++++- .../azure/kusto/data/ConnectionStringBuilder.java | 13 +++++++++++++ .../java/com/microsoft/azure/kusto/data/Utils.java | 10 ++-------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index 0ae038f9..a14d8a99 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -19,10 +19,21 @@ public class ClientImpl implements Client { private AadAuthenticationHelper aadAuthenticationHelper; private String clusterUrl; + private String originApplicationVersion; public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); + if(csb.originApplicationVersion() == null){ + String version = Utils.class.getPackage().getImplementationVersion(); + originApplicationVersion = "Kusto.Java.Client"; + if (StringUtils.isNotBlank(version)) { + originApplicationVersion += ":" + version; + } + } + else{ + originApplicationVersion = csb.originApplicationVersion(); + } } public Results execute(String command) throws DataServiceException, DataClientException { @@ -74,6 +85,6 @@ public Results execute(String database, String command, ClientRequestProperties throw new DataClientException(clusterEndpoint, String.format(clusterEndpoint, "Error in executing command: %s, in database: %s", command, database), e); } - return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue()); + return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue(), originApplicationVersion); } } \ No newline at end of file diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index 13f87b25..70eec716 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -15,6 +15,7 @@ public class ConnectionStringBuilder { private X509Certificate x509Certificate; private PrivateKey privateKey; private String aadAuthorityId; // AAD tenant Id (GUID) + private String originApplicationVersion; String getClusterUrl() { return clusterUri; } String getUserUsername() { return username; } @@ -22,6 +23,7 @@ public class ConnectionStringBuilder { String getApplicationClientId() { return applicationClientId; } String getApplicationKey() { return applicationKey; } String getAuthorityId() { return aadAuthorityId; } + String originApplicationVersion() { return originApplicationVersion; } X509Certificate getX509Certificate() { return x509Certificate; } PrivateKey getPrivateKey(){ return privateKey; } private ConnectionStringBuilder(String resourceUri) @@ -94,6 +96,17 @@ public static ConnectionStringBuilder createWithAadApplicationCredentials(String return createWithAadApplicationCredentials(resourceUri, applicationClientId, applicationKey, null); } + public static ConnectionStringBuilder createWithAadApplicationCredentials(String resourceUri, + String applicationClientId, + String applicationKey, + String authorityId, + String originApplicationVersion) + { + ConnectionStringBuilder csb = createWithAadApplicationCredentials(resourceUri, applicationClientId, applicationKey, authorityId); + csb.originApplicationVersion = originApplicationVersion; + return csb; + } + public static ConnectionStringBuilder createWithDeviceCodeCredentials(String resourceUri){ if (StringUtils.isEmpty(resourceUri)){ throw new IllegalArgumentException("resourceUri cannot be null or empty"); diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java index 2cd476fe..dafbc6a1 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java @@ -25,7 +25,7 @@ class Utils { - static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs) throws DataServiceException, DataClientException { + static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs, String originApplicationVersion) throws DataServiceException, DataClientException { HttpClient httpClient; if (timeoutMs != null) { @@ -50,13 +50,7 @@ static Results post(String url, String aadAccessToken, String payload, Integer t httpPost.addHeader("Accept-Encoding", "gzip,deflate"); httpPost.addHeader("Fed", "True"); - String version = Utils.class.getPackage().getImplementationVersion(); - String clientVersion = "Kusto.Java.Client"; - if (StringUtils.isNotBlank(version)) { - clientVersion += ":" + version; - } - - httpPost.addHeader("x-ms-client-version", clientVersion); + httpPost.addHeader("x-ms-client-version", originApplicationVersion); httpPost.addHeader("x-ms-client-request-id", String.format("KJC.execute;%s", java.util.UUID.randomUUID())); try { From cf9927271bca74b5e0d8a01f7f2ccf1d94347c06 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Sun, 27 Jan 2019 15:44:08 +0200 Subject: [PATCH 02/21] Expose a method 'GetBlobUriFromClientResourceManager' to get temporary blob uri for ingestion --- data/src/main/java/com/microsoft/azure/kusto/data/Utils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java index dafbc6a1..36929cca 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java @@ -25,7 +25,7 @@ class Utils { - static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs, String originApplicationVersion) throws DataServiceException, DataClientException { + static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs, String clientVersionForTracing) throws DataServiceException, DataClientException { HttpClient httpClient; if (timeoutMs != null) { @@ -50,7 +50,7 @@ static Results post(String url, String aadAccessToken, String payload, Integer t httpPost.addHeader("Accept-Encoding", "gzip,deflate"); httpPost.addHeader("Fed", "True"); - httpPost.addHeader("x-ms-client-version", originApplicationVersion); + httpPost.addHeader("x-ms-client-version", clientVersionForTracing); httpPost.addHeader("x-ms-client-request-id", String.format("KJC.execute;%s", java.util.UUID.randomUUID())); try { From 9fa9a3e8f2e899f5b1c8a6a298153298c224dfe2 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Mon, 28 Jan 2019 10:46:19 +0200 Subject: [PATCH 03/21] add origin application version to header --- .../microsoft/azure/kusto/data/ClientImpl.java | 12 ++++++------ .../kusto/data/ConnectionStringBuilder.java | 18 +++++------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index a14d8a99..5745e905 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -19,20 +19,20 @@ public class ClientImpl implements Client { private AadAuthenticationHelper aadAuthenticationHelper; private String clusterUrl; - private String originApplicationVersion; + private String clientVersionForTracing; public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); - if(csb.originApplicationVersion() == null){ + if(csb.clientVersionForTracing() == null){ String version = Utils.class.getPackage().getImplementationVersion(); - originApplicationVersion = "Kusto.Java.Client"; + clientVersionForTracing = "Kusto.Java.Client"; if (StringUtils.isNotBlank(version)) { - originApplicationVersion += ":" + version; + clientVersionForTracing += ":" + version; } } else{ - originApplicationVersion = csb.originApplicationVersion(); + clientVersionForTracing = csb.clientVersionForTracing(); } } @@ -85,6 +85,6 @@ public Results execute(String database, String command, ClientRequestProperties throw new DataClientException(clusterEndpoint, String.format(clusterEndpoint, "Error in executing command: %s, in database: %s", command, database), e); } - return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue(), originApplicationVersion); + return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue(), clientVersionForTracing); } } \ No newline at end of file diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index 70eec716..1da7bec5 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -15,7 +15,7 @@ public class ConnectionStringBuilder { private X509Certificate x509Certificate; private PrivateKey privateKey; private String aadAuthorityId; // AAD tenant Id (GUID) - private String originApplicationVersion; + private String clientVersionForTracing; String getClusterUrl() { return clusterUri; } String getUserUsername() { return username; } @@ -23,7 +23,7 @@ public class ConnectionStringBuilder { String getApplicationClientId() { return applicationClientId; } String getApplicationKey() { return applicationKey; } String getAuthorityId() { return aadAuthorityId; } - String originApplicationVersion() { return originApplicationVersion; } + String clientVersionForTracing() { return clientVersionForTracing; } X509Certificate getX509Certificate() { return x509Certificate; } PrivateKey getPrivateKey(){ return privateKey; } private ConnectionStringBuilder(String resourceUri) @@ -96,17 +96,6 @@ public static ConnectionStringBuilder createWithAadApplicationCredentials(String return createWithAadApplicationCredentials(resourceUri, applicationClientId, applicationKey, null); } - public static ConnectionStringBuilder createWithAadApplicationCredentials(String resourceUri, - String applicationClientId, - String applicationKey, - String authorityId, - String originApplicationVersion) - { - ConnectionStringBuilder csb = createWithAadApplicationCredentials(resourceUri, applicationClientId, applicationKey, authorityId); - csb.originApplicationVersion = originApplicationVersion; - return csb; - } - public static ConnectionStringBuilder createWithDeviceCodeCredentials(String resourceUri){ if (StringUtils.isEmpty(resourceUri)){ throw new IllegalArgumentException("resourceUri cannot be null or empty"); @@ -139,4 +128,7 @@ public static ConnectionStringBuilder createWithAadApplicationCertificate(String return csb; } + public void SetClientVersionForTracing(String clientVersionForTracing){ + this.clientVersionForTracing = clientVersionForTracing; + } } From adaa68f6ecc97d189729dd6b9c283cd22f848d04 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Mon, 28 Jan 2019 17:27:26 +0200 Subject: [PATCH 04/21] add origin application version to header --- .../java/com/microsoft/azure/kusto/data/ClientImpl.java | 6 +++--- .../microsoft/azure/kusto/data/ConnectionStringBuilder.java | 4 ++-- .../src/main/java/com/microsoft/azure/kusto/data/Utils.java | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index 5745e905..5f60f226 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -24,15 +24,15 @@ public class ClientImpl implements Client { public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); - if(csb.clientVersionForTracing() == null){ - String version = Utils.class.getPackage().getImplementationVersion(); + if(StringUtils.isNotBlank(csb.getClientVersionForTracing()) ){ clientVersionForTracing = "Kusto.Java.Client"; + String version = Utils.GetPackageVersion(); if (StringUtils.isNotBlank(version)) { clientVersionForTracing += ":" + version; } } else{ - clientVersionForTracing = csb.clientVersionForTracing(); + clientVersionForTracing = csb.getClientVersionForTracing(); } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index 1da7bec5..7c20f4ee 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -23,7 +23,7 @@ public class ConnectionStringBuilder { String getApplicationClientId() { return applicationClientId; } String getApplicationKey() { return applicationKey; } String getAuthorityId() { return aadAuthorityId; } - String clientVersionForTracing() { return clientVersionForTracing; } + String getClientVersionForTracing() { return clientVersionForTracing; } X509Certificate getX509Certificate() { return x509Certificate; } PrivateKey getPrivateKey(){ return privateKey; } private ConnectionStringBuilder(String resourceUri) @@ -128,7 +128,7 @@ public static ConnectionStringBuilder createWithAadApplicationCertificate(String return csb; } - public void SetClientVersionForTracing(String clientVersionForTracing){ + public void setClientVersionForTracing(String clientVersionForTracing){ this.clientVersionForTracing = clientVersionForTracing; } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java index 36929cca..d01dfcb1 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java @@ -105,4 +105,8 @@ static Results post(String url, String aadAccessToken, String payload, Integer t } return null; } + + static String GetPackageVersion(){ + return Utils.class.getPackage().getImplementationVersion(); + } } From 71b27c6c31079131a74eaeeb2333a71b3a854fb6 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Tue, 29 Jan 2019 15:22:59 +0200 Subject: [PATCH 05/21] add origin application version to header --- .../azure/kusto/data/ClientImpl.java | 15 ++- .../kusto/data/ConnectionStringBuilder.java | 96 ++++++++++++------- 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index 5f60f226..4c30dfbb 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -24,15 +24,14 @@ public class ClientImpl implements Client { public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); - if(StringUtils.isNotBlank(csb.getClientVersionForTracing()) ){ - clientVersionForTracing = "Kusto.Java.Client"; - String version = Utils.GetPackageVersion(); - if (StringUtils.isNotBlank(version)) { - clientVersionForTracing += ":" + version; - } + clientVersionForTracing = "Kusto.Java.Client"; + String version = Utils.GetPackageVersion(); + if (StringUtils.isNotBlank(version)) { + clientVersionForTracing += ":" + version; } - else{ - clientVersionForTracing = csb.getClientVersionForTracing(); + + if (StringUtils.isNotBlank(csb.getClientVersionForTracing())) { + clientVersionForTracing += "[" + csb.getClientVersionForTracing() + "]"; } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index 7c20f4ee..2512f86d 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -17,17 +17,43 @@ public class ConnectionStringBuilder { private String aadAuthorityId; // AAD tenant Id (GUID) private String clientVersionForTracing; - String getClusterUrl() { return clusterUri; } - String getUserUsername() { return username; } - String getUserPassword() { return password; } - String getApplicationClientId() { return applicationClientId; } - String getApplicationKey() { return applicationKey; } - String getAuthorityId() { return aadAuthorityId; } - String getClientVersionForTracing() { return clientVersionForTracing; } - X509Certificate getX509Certificate() { return x509Certificate; } - PrivateKey getPrivateKey(){ return privateKey; } - private ConnectionStringBuilder(String resourceUri) - { + String getClusterUrl() { + return clusterUri; + } + + String getUserUsername() { + return username; + } + + String getUserPassword() { + return password; + } + + String getApplicationClientId() { + return applicationClientId; + } + + String getApplicationKey() { + return applicationKey; + } + + String getAuthorityId() { + return aadAuthorityId; + } + + String getClientVersionForTracing() { + return clientVersionForTracing; + } + + X509Certificate getX509Certificate() { + return x509Certificate; + } + + PrivateKey getPrivateKey() { + return privateKey; + } + + private ConnectionStringBuilder(String resourceUri) { clusterUri = resourceUri; username = null; password = null; @@ -39,17 +65,16 @@ private ConnectionStringBuilder(String resourceUri) } public static ConnectionStringBuilder createWithAadUserCredentials(String resourceUri, - String username, - String password, - String authorityId) - { - if (StringUtils.isEmpty(resourceUri)){ + String username, + String password, + String authorityId) { + if (StringUtils.isEmpty(resourceUri)) { throw new IllegalArgumentException("resourceUri cannot be null or empty"); } - if (StringUtils.isEmpty(username)){ + if (StringUtils.isEmpty(username)) { throw new IllegalArgumentException("username cannot be null or empty"); } - if (StringUtils.isEmpty(password)){ + if (StringUtils.isEmpty(password)) { throw new IllegalArgumentException("password cannot be null or empty"); } ConnectionStringBuilder csb = new ConnectionStringBuilder(resourceUri); @@ -61,24 +86,22 @@ public static ConnectionStringBuilder createWithAadUserCredentials(String resour public static ConnectionStringBuilder createWithAadUserCredentials(String resourceUri, String username, - String password) - { + String password) { return createWithAadUserCredentials(resourceUri, username, password, null); } public static ConnectionStringBuilder createWithAadApplicationCredentials(String resourceUri, - String applicationClientId, - String applicationKey, - String authorityId) - { + String applicationClientId, + String applicationKey, + String authorityId) { - if (StringUtils.isEmpty(resourceUri)){ + if (StringUtils.isEmpty(resourceUri)) { throw new IllegalArgumentException("resourceUri cannot be null or empty"); } - if (StringUtils.isEmpty(applicationClientId)){ + if (StringUtils.isEmpty(applicationClientId)) { throw new IllegalArgumentException("applicationClientId cannot be null or empty"); } - if (StringUtils.isEmpty(applicationKey)){ + if (StringUtils.isEmpty(applicationKey)) { throw new IllegalArgumentException("applicationKey cannot be null or empty"); } @@ -91,13 +114,12 @@ public static ConnectionStringBuilder createWithAadApplicationCredentials(String public static ConnectionStringBuilder createWithAadApplicationCredentials(String resourceUri, String applicationClientId, - String applicationKey) - { + String applicationKey) { return createWithAadApplicationCredentials(resourceUri, applicationClientId, applicationKey, null); } - public static ConnectionStringBuilder createWithDeviceCodeCredentials(String resourceUri){ - if (StringUtils.isEmpty(resourceUri)){ + public static ConnectionStringBuilder createWithDeviceCodeCredentials(String resourceUri) { + if (StringUtils.isEmpty(resourceUri)) { throw new IllegalArgumentException("resourceUri cannot be null or empty"); } return new ConnectionStringBuilder(resourceUri); @@ -106,17 +128,17 @@ public static ConnectionStringBuilder createWithDeviceCodeCredentials(String res public static ConnectionStringBuilder createWithAadApplicationCertificate(String resourceUri, String applicationClientId, X509Certificate x509Certificate, - PrivateKey privateKey){ - if (StringUtils.isEmpty(resourceUri)){ + PrivateKey privateKey) { + if (StringUtils.isEmpty(resourceUri)) { throw new IllegalArgumentException("resourceUri cannot be null or empty"); } - if (StringUtils.isEmpty(applicationClientId)){ + if (StringUtils.isEmpty(applicationClientId)) { throw new IllegalArgumentException("applicationClientId cannot be null or empty"); } - if (x509Certificate == null){ + if (x509Certificate == null) { throw new IllegalArgumentException("certificate cannot be null"); } - if (privateKey == null){ + if (privateKey == null) { throw new IllegalArgumentException("privateKey cannot be null"); } @@ -128,7 +150,7 @@ public static ConnectionStringBuilder createWithAadApplicationCertificate(String return csb; } - public void setClientVersionForTracing(String clientVersionForTracing){ + public void setClientVersionForTracing(String clientVersionForTracing) { this.clientVersionForTracing = clientVersionForTracing; } } From b3e5c0a94e3f9e2fb9af6bb32abb91a0bf4d1215 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 30 Jan 2019 11:16:02 +0200 Subject: [PATCH 06/21] add origin application version to header --- .../java/com/microsoft/azure/kusto/data/ClientImpl.java | 4 +++- .../azure/kusto/data/ConnectionStringBuilder.java | 9 +++++++++ .../main/java/com/microsoft/azure/kusto/data/Utils.java | 8 +++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index 4c30dfbb..06bc6a9e 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -20,6 +20,7 @@ public class ClientImpl implements Client { private AadAuthenticationHelper aadAuthenticationHelper; private String clusterUrl; private String clientVersionForTracing; + private String applicationNameForTracing; public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); @@ -33,6 +34,7 @@ public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { if (StringUtils.isNotBlank(csb.getClientVersionForTracing())) { clientVersionForTracing += "[" + csb.getClientVersionForTracing() + "]"; } + applicationNameForTracing = csb.getApplicationNameForTracing(); } public Results execute(String command) throws DataServiceException, DataClientException { @@ -84,6 +86,6 @@ public Results execute(String database, String command, ClientRequestProperties throw new DataClientException(clusterEndpoint, String.format(clusterEndpoint, "Error in executing command: %s, in database: %s", command, database), e); } - return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue(), clientVersionForTracing); + return Utils.post(clusterEndpoint, aadAccessToken, jsonString, timeoutMs.intValue(), clientVersionForTracing, applicationNameForTracing); } } \ No newline at end of file diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index 2512f86d..da408153 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -16,6 +16,7 @@ public class ConnectionStringBuilder { private PrivateKey privateKey; private String aadAuthorityId; // AAD tenant Id (GUID) private String clientVersionForTracing; + private String applicationNameForTracing; String getClusterUrl() { return clusterUri; @@ -41,6 +42,10 @@ String getAuthorityId() { return aadAuthorityId; } + String getApplicationNameForTracing() { + return applicationNameForTracing; + } + String getClientVersionForTracing() { return clientVersionForTracing; } @@ -153,4 +158,8 @@ public static ConnectionStringBuilder createWithAadApplicationCertificate(String public void setClientVersionForTracing(String clientVersionForTracing) { this.clientVersionForTracing = clientVersionForTracing; } + + public void setApplicationNameForTracing(String applicationNameForTracing) { + this.applicationNameForTracing = applicationNameForTracing; + } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java index d01dfcb1..9c036ad7 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/Utils.java @@ -25,7 +25,7 @@ class Utils { - static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs, String clientVersionForTracing) throws DataServiceException, DataClientException { + static Results post(String url, String aadAccessToken, String payload, Integer timeoutMs, String clientVersionForTracing, String applicationNameForTracing) throws DataServiceException, DataClientException { HttpClient httpClient; if (timeoutMs != null) { @@ -42,7 +42,6 @@ static Results post(String url, String aadAccessToken, String payload, Integer t payload, ContentType.APPLICATION_JSON); - httpPost.setEntity(requestEntity); httpPost.addHeader("Authorization", String.format("Bearer %s", aadAccessToken)); @@ -52,6 +51,9 @@ static Results post(String url, String aadAccessToken, String payload, Integer t httpPost.addHeader("x-ms-client-version", clientVersionForTracing); httpPost.addHeader("x-ms-client-request-id", String.format("KJC.execute;%s", java.util.UUID.randomUUID())); + if (StringUtils.isNotBlank(applicationNameForTracing)) { + httpPost.addHeader("x-ms-app", applicationNameForTracing); + } try { //Execute and get the response. @@ -106,7 +108,7 @@ static Results post(String url, String aadAccessToken, String payload, Integer t return null; } - static String GetPackageVersion(){ + static String GetPackageVersion() { return Utils.class.getPackage().getImplementationVersion(); } } From 31971c03233cf2b7d337453a0ca3c880852c092d Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Thu, 31 Jan 2019 14:02:22 +0200 Subject: [PATCH 07/21] add origin application version to header --- .../kusto/data/ConnectionStringBuilder.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java index da408153..ff56f0fc 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ConnectionStringBuilder.java @@ -46,10 +46,18 @@ String getApplicationNameForTracing() { return applicationNameForTracing; } + public void setApplicationNameForTracing(String applicationNameForTracing) { + this.applicationNameForTracing = applicationNameForTracing; + } + String getClientVersionForTracing() { return clientVersionForTracing; } + public void setClientVersionForTracing(String clientVersionForTracing) { + this.clientVersionForTracing = clientVersionForTracing; + } + X509Certificate getX509Certificate() { return x509Certificate; } @@ -147,19 +155,10 @@ public static ConnectionStringBuilder createWithAadApplicationCertificate(String throw new IllegalArgumentException("privateKey cannot be null"); } - ConnectionStringBuilder csb = new ConnectionStringBuilder(resourceUri); csb.applicationClientId = applicationClientId; csb.x509Certificate = x509Certificate; csb.privateKey = privateKey; return csb; } - - public void setClientVersionForTracing(String clientVersionForTracing) { - this.clientVersionForTracing = clientVersionForTracing; - } - - public void setApplicationNameForTracing(String applicationNameForTracing) { - this.applicationNameForTracing = applicationNameForTracing; - } -} +} \ No newline at end of file From 0d4f87bafeba2669e9d814fca083570e99d8ace9 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Tue, 12 Feb 2019 16:36:35 +0200 Subject: [PATCH 08/21] cache last AuthenticationResult --- .../kusto/data/AadAuthenticationHelper.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 77aa4ac7..7b614fd3 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -14,6 +14,7 @@ import java.net.URISyntaxException; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.Date; import java.util.concurrent.*; public class AadAuthenticationHelper { @@ -29,6 +30,7 @@ public class AadAuthenticationHelper { private X509Certificate x509Certificate; private PrivateKey privateKey; private AuthenticationType authenticationType; + private AuthenticationResult lastAuthenticationResult; private enum AuthenticationType { AAD_USERNAME_PASSWORD, @@ -62,23 +64,30 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } String acquireAccessToken() throws DataServiceException { + if(lastAuthenticationResult != null && lastAuthenticationResult.getExpiresOnDate().after(new Date())){ + return lastAuthenticationResult.getAccessToken(); + } + try { switch (authenticationType) { case AAD_APPLICATION_KEY: - return acquireAadApplicationAccessToken().getAccessToken(); + lastAuthenticationResult = acquireAadApplicationAccessToken(); + return lastAuthenticationResult.getAccessToken(); case AAD_USERNAME_PASSWORD: - return acquireAadUserAccessToken().getAccessToken(); + lastAuthenticationResult = acquireAadUserAccessToken(); + return lastAuthenticationResult.getAccessToken(); case AAD_DEVICE_LOGIN: - return acquireAccessTokenUsingDeviceCodeFlow().getAccessToken(); + lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); + return lastAuthenticationResult.getAccessToken(); case AAD_APPLICATION_CERTIFICATE: - return acquireWithClientCertificate().getAccessToken(); + lastAuthenticationResult = acquireWithClientCertificate(); + return lastAuthenticationResult.getAccessToken(); default: throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); } } catch (Exception e) { throw new DataServiceException(e.getMessage()); } - } private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException { @@ -131,8 +140,8 @@ private AuthenticationResult acquireAadApplicationAccessToken() throws DataServi } private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exception { - AuthenticationContext context = null; - AuthenticationResult result = null; + AuthenticationContext context; + AuthenticationResult result; ExecutorService service = null; try { service = Executors.newSingleThreadExecutor(); From 4ea820d561539fbc1157ca875f529e599d962aba Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 13 Feb 2019 11:33:49 +0200 Subject: [PATCH 09/21] cache last AuthenticationResult --- .../kusto/data/AadAuthenticationHelper.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 7b614fd3..0b673364 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -21,6 +21,7 @@ public class AadAuthenticationHelper { private final static String DEFAULT_AAD_TENANT = "common"; private final static String CLIENT_ID = "db662dc1-0cfe-4e1c-a843-19a68e65be58"; + private final static long ONE_MINUTE_IN_MILLIS = 60000; private ClientCredential clientCredential; private String userUsername; @@ -64,30 +65,29 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } String acquireAccessToken() throws DataServiceException { - if(lastAuthenticationResult != null && lastAuthenticationResult.getExpiresOnDate().after(new Date())){ - return lastAuthenticationResult.getAccessToken(); - } - - try { - switch (authenticationType) { - case AAD_APPLICATION_KEY: - lastAuthenticationResult = acquireAadApplicationAccessToken(); - return lastAuthenticationResult.getAccessToken(); - case AAD_USERNAME_PASSWORD: - lastAuthenticationResult = acquireAadUserAccessToken(); - return lastAuthenticationResult.getAccessToken(); - case AAD_DEVICE_LOGIN: - lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); - return lastAuthenticationResult.getAccessToken(); - case AAD_APPLICATION_CERTIFICATE: - lastAuthenticationResult = acquireWithClientCertificate(); - return lastAuthenticationResult.getAccessToken(); - default: - throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + if(lastAuthenticationResult == null || lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { + try { + switch (authenticationType) { + case AAD_APPLICATION_KEY: + lastAuthenticationResult = acquireAadApplicationAccessToken(); + break; + case AAD_USERNAME_PASSWORD: + lastAuthenticationResult = acquireAadUserAccessToken(); + break; + case AAD_DEVICE_LOGIN: + lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); + break; + case AAD_APPLICATION_CERTIFICATE: + lastAuthenticationResult = acquireWithClientCertificate(); + break; + default: + throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + } + } catch (Exception e) { + throw new DataServiceException(e.getMessage()); } - } catch (Exception e) { - throw new DataServiceException(e.getMessage()); } + return lastAuthenticationResult.getAccessToken(); } private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException { From 6d9142b3b392116cfea7bd5b2081d16fe431d9cc Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 13 Feb 2019 11:52:06 +0200 Subject: [PATCH 10/21] cache last AuthenticationResult --- .../kusto/data/AadAuthenticationHelper.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 0b673364..9cbe7aba 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -64,8 +64,8 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS aadAuthorityUri = String.format("https://login.microsoftonline.com/%s", aadAuthorityId); } - String acquireAccessToken() throws DataServiceException { - if(lastAuthenticationResult == null || lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { + String acquireAccessToken() throws DataServiceException { + if (lastAuthenticationResult == null || lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { try { switch (authenticationType) { case AAD_APPLICATION_KEY: @@ -145,7 +145,7 @@ private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exce ExecutorService service = null; try { service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext( aadAuthorityUri, true, service); + context = new AuthenticationContext(aadAuthorityUri, true, service); Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); DeviceCode deviceCode = future.get(); System.out.println(deviceCode.getMessage()); @@ -167,23 +167,23 @@ private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exce } private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCode, AuthenticationContext context) - throws InterruptedException{ + throws InterruptedException { int timeout = 15 * 1000; AuthenticationResult result = null; - while (timeout > 0){ - try{ + while (timeout > 0) { + try { Future futureResult = context.acquireTokenByDeviceCode(deviceCode, null); return futureResult.get(); } catch (ExecutionException e) { - Thread.sleep(1000); - timeout -= 1000; + Thread.sleep(1000); + timeout -= 1000; } } return result; } AuthenticationResult acquireWithClientCertificate() - throws IOException, InterruptedException, ExecutionException, ServiceUnavailableException{ + throws IOException, InterruptedException, ExecutionException, ServiceUnavailableException { AuthenticationContext context; AuthenticationResult result; From 67dfc2bc9f1ee7d40feca47fd3502a1e74e6a172 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 13 Feb 2019 18:37:21 +0200 Subject: [PATCH 11/21] cache last AuthenticationResult --- .../kusto/data/AadAuthenticationHelper.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 9cbe7aba..05f0dc0d 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -65,7 +65,7 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } String acquireAccessToken() throws DataServiceException { - if (lastAuthenticationResult == null || lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { + if (lastAuthenticationResult == null || lastAuthenticationResult.getRefreshToken() == null) { try { switch (authenticationType) { case AAD_APPLICATION_KEY: @@ -87,6 +87,26 @@ String acquireAccessToken() throws DataServiceException { throw new DataServiceException(e.getMessage()); } } + else if(lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { + try { + ExecutorService service = Executors.newSingleThreadExecutor(); + AuthenticationContext context = new AuthenticationContext(aadAuthorityUri, true, service); + switch (authenticationType) { + case AAD_APPLICATION_KEY: + case AAD_APPLICATION_CERTIFICATE: + lastAuthenticationResult = context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), clientCredential, null).get(); + break; + case AAD_USERNAME_PASSWORD: + case AAD_DEVICE_LOGIN: + lastAuthenticationResult = context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), CLIENT_ID, clusterUrl, null).get(); + break; + default: + throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + } + } catch (Exception e) { + throw new DataServiceException(e.getMessage()); + } + } return lastAuthenticationResult.getAccessToken(); } From 9038de6f1525dc5ba393ff0d7567d698db3069d4 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Thu, 14 Feb 2019 11:59:37 +0200 Subject: [PATCH 12/21] cache last AuthenticationResult --- .../kusto/data/AadAuthenticationHelper.java | 3 +-- .../kusto/data/AadAuthenticationHelperTest.java | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 05f0dc0d..cef7a470 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -86,8 +86,7 @@ String acquireAccessToken() throws DataServiceException { } catch (Exception e) { throw new DataServiceException(e.getMessage()); } - } - else if(lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { + } else if (lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { try { ExecutorService service = Executors.newSingleThreadExecutor(); AuthenticationContext context = new AuthenticationContext(aadAuthorityUri, true, service); diff --git a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java index 9ea407e7..3c9b10ae 100644 --- a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java +++ b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java @@ -26,9 +26,17 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.concurrent.ExecutionException; +import org.junit.jupiter.api.BeforeEach; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; public class AadAuthenticationHelperTest { + private AadAuthenticationHelper aadAuthenticationHelper = spy(AadAuthenticationHelper.class); + + @Test @DisplayName("validate auth with certificate throws exception when missing or invalid parameters") void acquireWithClientCertificateNullKey() throws CertificateException, OperatorCreationException, @@ -47,7 +55,6 @@ void acquireWithClientCertificateNullKey() throws CertificateException, Operator Assertions.assertThrows(ExecutionException.class, () -> aadAuthenticationHelper.acquireWithClientCertificate()); - } static KeyCert readPem(String path, String password) @@ -83,4 +90,12 @@ static KeyCert readPem(String path, String password) return keycert; } + @Test + @DisplayName("validate auth with cached token") + void useCachedTokenAndRefreshWhenNeeded(){ + //if less than minute - he will refresh + //try override + doReturn(ingestionResultMock).when(ingestClientSpy).ingestFromFile(any(), any()); + + } } From dc9ba42386f795bde62241628b47c74db6b8d414 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Thu, 14 Feb 2019 16:09:15 +0200 Subject: [PATCH 13/21] cache access token --- .../kusto/data/AadAuthenticationHelper.java | 134 ++++++++---------- .../data/AadAuthenticationHelperTest.java | 47 ++++-- 2 files changed, 99 insertions(+), 82 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index cef7a470..78c23c01 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -21,7 +21,7 @@ public class AadAuthenticationHelper { private final static String DEFAULT_AAD_TENANT = "common"; private final static String CLIENT_ID = "db662dc1-0cfe-4e1c-a843-19a68e65be58"; - private final static long ONE_MINUTE_IN_MILLIS = 60000; + public final static long ONE_MINUTE_IN_MILLIS = 60000; private ClientCredential clientCredential; private String userUsername; @@ -32,6 +32,8 @@ public class AadAuthenticationHelper { private PrivateKey privateKey; private AuthenticationType authenticationType; private AuthenticationResult lastAuthenticationResult; + ExecutorService service = Executors.newSingleThreadExecutor(); + AuthenticationContext context; private enum AuthenticationType { AAD_USERNAME_PASSWORD, @@ -53,7 +55,7 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } else if (csb.getX509Certificate() != null && csb.getPrivateKey() != null) { x509Certificate = csb.getX509Certificate(); privateKey = csb.getPrivateKey(); - clientCredential = new ClientCredential(csb.getApplicationClientId(), null); + clientCredential = new ClientCredential(csb.getApplicationClientId(), "null"); authenticationType = AuthenticationType.AAD_APPLICATION_CERTIFICATE; } else { authenticationType = AuthenticationType.AAD_DEVICE_LOGIN; @@ -65,7 +67,9 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } String acquireAccessToken() throws DataServiceException { - if (lastAuthenticationResult == null || lastAuthenticationResult.getRefreshToken() == null) { + boolean isAccessTokenExpired; + if (lastAuthenticationResult == null || ((isAccessTokenExpired = lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute())) + && lastAuthenticationResult.getRefreshToken() == null)) { try { switch (authenticationType) { case AAD_APPLICATION_KEY: @@ -86,47 +90,27 @@ String acquireAccessToken() throws DataServiceException { } catch (Exception e) { throw new DataServiceException(e.getMessage()); } - } else if (lastAuthenticationResult.getExpiresOnDate().before(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS))) { - try { - ExecutorService service = Executors.newSingleThreadExecutor(); - AuthenticationContext context = new AuthenticationContext(aadAuthorityUri, true, service); - switch (authenticationType) { - case AAD_APPLICATION_KEY: - case AAD_APPLICATION_CERTIFICATE: - lastAuthenticationResult = context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), clientCredential, null).get(); - break; - case AAD_USERNAME_PASSWORD: - case AAD_DEVICE_LOGIN: - lastAuthenticationResult = context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), CLIENT_ID, clusterUrl, null).get(); - break; - default: - throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); - } - } catch (Exception e) { - throw new DataServiceException(e.getMessage()); - } + } else if (lastAuthenticationResult.getRefreshToken() != null && isAccessTokenExpired){ + lastAuthenticationResult = refreshToken(); } + return lastAuthenticationResult.getAccessToken(); } - private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException { - AuthenticationContext context; + private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException, MalformedURLException { + if(context == null){ + context = new AuthenticationContext(aadAuthorityUri, true, service); + } + AuthenticationResult result; ExecutorService service = null; try { - service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext(aadAuthorityUri, true, service); - Future future = context.acquireToken( clusterUrl, CLIENT_ID, userUsername, userPassword, null); result = future.get(); - } catch (InterruptedException | ExecutionException | MalformedURLException e) { + } catch (InterruptedException | ExecutionException e) { throw new DataClientException(clusterUrl, "Error in acquiring UserAccessToken", e); - } finally { - if (service != null) { - service.shutdown(); - } } if (result == null) { @@ -135,21 +119,17 @@ private AuthenticationResult acquireAadUserAccessToken() throws DataServiceExcep return result; } - private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException { - AuthenticationContext context; + private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException, MalformedURLException { + if(context == null){ + context = new AuthenticationContext(aadAuthorityUri, true, service); + } + AuthenticationResult result; - ExecutorService service = null; try { - service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext(aadAuthorityUri, true, service); Future future = context.acquireToken(clusterUrl, clientCredential, null); result = future.get(); - } catch (InterruptedException | ExecutionException | MalformedURLException e) { + } catch (InterruptedException | ExecutionException e) { throw new DataClientException(clusterUrl, "Error in acquiring ApplicationAccessToken", e); - } finally { - if (service != null) { - service.shutdown(); - } } if (result == null) { @@ -159,26 +139,19 @@ private AuthenticationResult acquireAadApplicationAccessToken() throws DataServi } private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exception { - AuthenticationContext context; - AuthenticationResult result; - ExecutorService service = null; - try { - service = Executors.newSingleThreadExecutor(); + if(context == null){ context = new AuthenticationContext(aadAuthorityUri, true, service); - Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); - DeviceCode deviceCode = future.get(); - System.out.println(deviceCode.getMessage()); - if (Desktop.isDesktopSupported()) { - Desktop.getDesktop().browse(new URI(deviceCode.getVerificationUrl())); - } - result = waitAndAcquireTokenByDeviceCode(deviceCode, context); - + } - } finally { - if (service != null) { - service.shutdown(); - } + AuthenticationResult result; + Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); + DeviceCode deviceCode = future.get(); + System.out.println(deviceCode.getMessage()); + if (Desktop.isDesktopSupported()) { + Desktop.getDesktop().browse(new URI(deviceCode.getVerificationUrl())); } + result = waitAndAcquireTokenByDeviceCode(deviceCode, context); + if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } @@ -203,27 +176,40 @@ private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCo AuthenticationResult acquireWithClientCertificate() throws IOException, InterruptedException, ExecutionException, ServiceUnavailableException { - - AuthenticationContext context; + if(context == null){ + context = new AuthenticationContext(aadAuthorityUri, true, service); + } AuthenticationResult result; - ExecutorService service = null; - try { - service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext(aadAuthorityUri, false, service); - AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(clientCredential.getClientId(), - privateKey, x509Certificate); - // pass null value for optional callback function and acquire access token - result = context.acquireToken(clusterUrl, asymmetricKeyCredential, null).get(); - } finally { - if (service != null) { - service.shutdown(); - } - } + AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(clientCredential.getClientId(), + privateKey, x509Certificate); + // pass null value for optional callback function and acquire access token + result = context.acquireToken(clusterUrl, asymmetricKeyCredential, null).get(); + if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } return result; } + AuthenticationResult refreshToken() throws DataServiceException { + try { + switch (authenticationType) { + case AAD_APPLICATION_KEY: + case AAD_APPLICATION_CERTIFICATE: + return context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), clientCredential, null).get(); + case AAD_USERNAME_PASSWORD: + case AAD_DEVICE_LOGIN: + return context.acquireTokenByRefreshToken(lastAuthenticationResult.getRefreshToken(), CLIENT_ID, clusterUrl, null).get(); + default: + throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + } + } catch (Exception e) { + throw new DataServiceException(e.getMessage()); + } + } + + Date dateInAMinute(){ + return new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS); + } } diff --git a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java index 3c9b10ae..5809cf02 100644 --- a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java +++ b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java @@ -1,6 +1,9 @@ package com.microsoft.azure.kusto.data; +import com.microsoft.aad.adal4j.AuthenticationResult; +import com.microsoft.aad.adal4j.UserInfo; +import com.microsoft.azure.kusto.data.exceptions.DataServiceException; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -25,16 +28,19 @@ import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Date; import java.util.concurrent.ExecutionException; -import org.junit.jupiter.api.BeforeEach; -import static org.mockito.ArgumentMatchers.any; +import javax.naming.ServiceUnavailableException; + +import static com.microsoft.azure.kusto.data.AadAuthenticationHelper.ONE_MINUTE_IN_MILLIS; +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; public class AadAuthenticationHelperTest { - private AadAuthenticationHelper aadAuthenticationHelper = spy(AadAuthenticationHelper.class); @Test @@ -91,11 +97,36 @@ static KeyCert readPem(String path, String password) } @Test - @DisplayName("validate auth with cached token") - void useCachedTokenAndRefreshWhenNeeded(){ - //if less than minute - he will refresh - //try override - doReturn(ingestionResultMock).when(ingestClientSpy).ingestFromFile(any(), any()); + @DisplayName("validate cached token. Refresh if needed. Call regularly if no refresh token") + void useCachedTokenAndRefreshWhenNeeded() throws InterruptedException, ExecutionException, ServiceUnavailableException, IOException, DataServiceException, URISyntaxException, CertificateException, OperatorCreationException, PKCSException { + String certFilePath = Paths.get("src","test","resources", "cert.cer").toString(); + String privateKeyPath = Paths.get("src","test","resources","key.pem").toString(); + + X509Certificate x509Certificate = readPem(certFilePath, "basic").getCertificate(); + PrivateKey privateKey = readPem(privateKeyPath, "basic").getKey(); + + ConnectionStringBuilder csb = ConnectionStringBuilder + .createWithAadApplicationCertificate("resource.uri", "client-id", x509Certificate, privateKey); + + AadAuthenticationHelper aadAuthenticationHelperSpy = spy(new AadAuthenticationHelper(csb)); + + AuthenticationResult authenticationResult = new AuthenticationResult("testType", "firstToken","refreshToken",0,"id", mock(UserInfo.class),false); + AuthenticationResult authenticationResultFromRefresh = new AuthenticationResult("testType", "fromRefresh",null,90,"id", mock(UserInfo.class),false); + AuthenticationResult authenticationResultNullRefreshTokenResult = new AuthenticationResult("testType", "nullRefreshResult",null,0,"id", mock(UserInfo.class),false); + + doReturn(authenticationResultFromRefresh).when(aadAuthenticationHelperSpy).refreshToken(); + doReturn(authenticationResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); + + assertEquals("firstToken", aadAuthenticationHelperSpy.acquireAccessToken()); + assertEquals("fromRefresh", aadAuthenticationHelperSpy.acquireAccessToken()); + assertEquals("fromRefresh", aadAuthenticationHelperSpy.acquireAccessToken()); + + // If no refresh token - it will authenticate again, + doReturn(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS * 2)).when(aadAuthenticationHelperSpy).dateInAMinute(); + doReturn(authenticationResultNullRefreshTokenResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); + + assertEquals("nullRefreshResult", aadAuthenticationHelperSpy.acquireAccessToken()); + // Null refreshToken } } From ab6135c16126467bc803e43089978b8007fe251b Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Mon, 18 Feb 2019 14:55:20 +0200 Subject: [PATCH 14/21] cache access token --- .../kusto/data/AadAuthenticationHelper.java | 74 +++++++++++-------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 78c23c01..b655a164 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -16,6 +16,8 @@ import java.security.cert.X509Certificate; import java.util.Date; import java.util.concurrent.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public class AadAuthenticationHelper { @@ -32,8 +34,9 @@ public class AadAuthenticationHelper { private PrivateKey privateKey; private AuthenticationType authenticationType; private AuthenticationResult lastAuthenticationResult; - ExecutorService service = Executors.newSingleThreadExecutor(); - AuthenticationContext context; + private ExecutorService service = Executors.newSingleThreadExecutor(); + private AuthenticationContext context; + private Lock lastAuthenticationResultLock = new ReentrantLock(); private enum AuthenticationType { AAD_USERNAME_PASSWORD, @@ -69,36 +72,45 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS String acquireAccessToken() throws DataServiceException { boolean isAccessTokenExpired; if (lastAuthenticationResult == null || ((isAccessTokenExpired = lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute())) - && lastAuthenticationResult.getRefreshToken() == null)) { - try { - switch (authenticationType) { - case AAD_APPLICATION_KEY: - lastAuthenticationResult = acquireAadApplicationAccessToken(); - break; - case AAD_USERNAME_PASSWORD: - lastAuthenticationResult = acquireAadUserAccessToken(); - break; - case AAD_DEVICE_LOGIN: - lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); - break; - case AAD_APPLICATION_CERTIFICATE: - lastAuthenticationResult = acquireWithClientCertificate(); - break; - default: - throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + && lastAuthenticationResult.getRefreshToken() == null)) { + lastAuthenticationResultLock.lock(); + if (lastAuthenticationResult == null || (lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute()) + && lastAuthenticationResult.getRefreshToken() == null)) { + try { + switch (authenticationType) { + case AAD_APPLICATION_KEY: + lastAuthenticationResult = acquireAadApplicationAccessToken(); + break; + case AAD_USERNAME_PASSWORD: + lastAuthenticationResult = acquireAadUserAccessToken(); + break; + case AAD_DEVICE_LOGIN: + lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); + break; + case AAD_APPLICATION_CERTIFICATE: + lastAuthenticationResult = acquireWithClientCertificate(); + break; + default: + throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + } + } catch (Exception e) { + throw new DataServiceException(e.getMessage()); } - } catch (Exception e) { - throw new DataServiceException(e.getMessage()); } - } else if (lastAuthenticationResult.getRefreshToken() != null && isAccessTokenExpired){ - lastAuthenticationResult = refreshToken(); + lastAuthenticationResultLock.unlock(); + } else if (lastAuthenticationResult.getRefreshToken() != null && isAccessTokenExpired) { + lastAuthenticationResultLock.lock(); + if (lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute())) { + lastAuthenticationResult = refreshToken(); + } + lastAuthenticationResultLock.unlock(); } return lastAuthenticationResult.getAccessToken(); } private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException, MalformedURLException { - if(context == null){ + if (context == null) { context = new AuthenticationContext(aadAuthorityUri, true, service); } @@ -120,7 +132,7 @@ private AuthenticationResult acquireAadUserAccessToken() throws DataServiceExcep } private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException, MalformedURLException { - if(context == null){ + if (context == null) { context = new AuthenticationContext(aadAuthorityUri, true, service); } @@ -139,18 +151,18 @@ private AuthenticationResult acquireAadApplicationAccessToken() throws DataServi } private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exception { - if(context == null){ + if (context == null) { context = new AuthenticationContext(aadAuthorityUri, true, service); } AuthenticationResult result; Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); DeviceCode deviceCode = future.get(); - System.out.println(deviceCode.getMessage()); + System.out.println(deviceCode.getMessage() + " " + Thread.currentThread()); if (Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI(deviceCode.getVerificationUrl())); } - result = waitAndAcquireTokenByDeviceCode(deviceCode, context); + result = waitAndAcquireTokenByDeviceCode(deviceCode); if (result == null) { throw new ServiceUnavailableException("authentication result was null"); @@ -158,7 +170,7 @@ private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exce return result; } - private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCode, AuthenticationContext context) + private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCode) throws InterruptedException { int timeout = 15 * 1000; AuthenticationResult result = null; @@ -176,7 +188,7 @@ private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCo AuthenticationResult acquireWithClientCertificate() throws IOException, InterruptedException, ExecutionException, ServiceUnavailableException { - if(context == null){ + if (context == null) { context = new AuthenticationContext(aadAuthorityUri, true, service); } AuthenticationResult result; @@ -209,7 +221,7 @@ AuthenticationResult refreshToken() throws DataServiceException { } } - Date dateInAMinute(){ + Date dateInAMinute() { return new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS); } } From e0774281b411c4b4345f243886d8be53101da334 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Mon, 18 Feb 2019 18:15:25 +0200 Subject: [PATCH 15/21] cache access token --- .../kusto/data/AadAuthenticationHelper.java | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index b655a164..ac7fae2e 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -37,6 +37,7 @@ public class AadAuthenticationHelper { private ExecutorService service = Executors.newSingleThreadExecutor(); private AuthenticationContext context; private Lock lastAuthenticationResultLock = new ReentrantLock(); + private String applicationClientId; private enum AuthenticationType { AAD_USERNAME_PASSWORD, @@ -58,7 +59,7 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } else if (csb.getX509Certificate() != null && csb.getPrivateKey() != null) { x509Certificate = csb.getX509Certificate(); privateKey = csb.getPrivateKey(); - clientCredential = new ClientCredential(csb.getApplicationClientId(), "null"); + applicationClientId = csb.getApplicationClientId(); authenticationType = AuthenticationType.AAD_APPLICATION_CERTIFICATE; } else { authenticationType = AuthenticationType.AAD_DEVICE_LOGIN; @@ -70,40 +71,20 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS } String acquireAccessToken() throws DataServiceException { - boolean isAccessTokenExpired; - if (lastAuthenticationResult == null || ((isAccessTokenExpired = lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute())) - && lastAuthenticationResult.getRefreshToken() == null)) { - lastAuthenticationResultLock.lock(); - if (lastAuthenticationResult == null || (lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute()) - && lastAuthenticationResult.getRefreshToken() == null)) { - try { - switch (authenticationType) { - case AAD_APPLICATION_KEY: - lastAuthenticationResult = acquireAadApplicationAccessToken(); - break; - case AAD_USERNAME_PASSWORD: - lastAuthenticationResult = acquireAadUserAccessToken(); - break; - case AAD_DEVICE_LOGIN: - lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); - break; - case AAD_APPLICATION_CERTIFICATE: - lastAuthenticationResult = acquireWithClientCertificate(); - break; - default: - throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + if (lastAuthenticationResult == null) { + aquireTokenByType(); + } else { + if (isTokenExpired()) { + if (lastAuthenticationResult.getRefreshToken() == null) { + aquireTokenByType(); + } else { + lastAuthenticationResultLock.lock(); + if (isTokenExpired()) { + lastAuthenticationResult = refreshToken(); } - } catch (Exception e) { - throw new DataServiceException(e.getMessage()); + lastAuthenticationResultLock.unlock(); } } - lastAuthenticationResultLock.unlock(); - } else if (lastAuthenticationResult.getRefreshToken() != null && isAccessTokenExpired) { - lastAuthenticationResultLock.lock(); - if (lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute())) { - lastAuthenticationResult = refreshToken(); - } - lastAuthenticationResultLock.unlock(); } return lastAuthenticationResult.getAccessToken(); @@ -115,7 +96,6 @@ private AuthenticationResult acquireAadUserAccessToken() throws DataServiceExcep } AuthenticationResult result; - ExecutorService service = null; try { Future future = context.acquireToken( clusterUrl, CLIENT_ID, userUsername, userPassword, @@ -193,7 +173,7 @@ AuthenticationResult acquireWithClientCertificate() } AuthenticationResult result; - AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(clientCredential.getClientId(), + AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(applicationClientId, privateKey, x509Certificate); // pass null value for optional callback function and acquire access token result = context.acquireToken(clusterUrl, asymmetricKeyCredential, null).get(); @@ -204,6 +184,37 @@ AuthenticationResult acquireWithClientCertificate() return result; } + private void aquireTokenByType() throws DataServiceException { + lastAuthenticationResultLock.lock(); + if(lastAuthenticationResult == null || isTokenExpired()) { + try { + switch (authenticationType) { + case AAD_APPLICATION_KEY: + lastAuthenticationResult = acquireAadApplicationAccessToken(); + break; + case AAD_USERNAME_PASSWORD: + lastAuthenticationResult = acquireAadUserAccessToken(); + break; + case AAD_DEVICE_LOGIN: + lastAuthenticationResult = acquireAccessTokenUsingDeviceCodeFlow(); + break; + case AAD_APPLICATION_CERTIFICATE: + lastAuthenticationResult = acquireWithClientCertificate(); + break; + default: + throw new DataServiceException("Authentication type: " + authenticationType.name() + " is invalid"); + } + } catch (Exception e) { + throw new DataServiceException(e.getMessage()); + } + } + lastAuthenticationResultLock.unlock(); + } + + private boolean isTokenExpired(){ + return lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute()); + } + AuthenticationResult refreshToken() throws DataServiceException { try { switch (authenticationType) { From 82732ad550ba073b6a35c01a8e6851893f570f9b Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Tue, 19 Feb 2019 15:37:02 +0200 Subject: [PATCH 16/21] cache access token --- .../kusto/data/AadAuthenticationHelper.java | 36 ++++++------------- .../azure/kusto/data/ClientFactory.java | 3 +- .../azure/kusto/data/ClientImpl.java | 3 +- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index ac7fae2e..622123fa 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -29,12 +29,10 @@ public class AadAuthenticationHelper { private String userUsername; private String userPassword; private String clusterUrl; - private String aadAuthorityUri; private X509Certificate x509Certificate; private PrivateKey privateKey; private AuthenticationType authenticationType; private AuthenticationResult lastAuthenticationResult; - private ExecutorService service = Executors.newSingleThreadExecutor(); private AuthenticationContext context; private Lock lastAuthenticationResultLock = new ReentrantLock(); private String applicationClientId; @@ -46,7 +44,8 @@ private enum AuthenticationType { AAD_APPLICATION_CERTIFICATE } - public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException { + public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { + URI clusterUri = new URI(csb.getClusterUrl()); clusterUrl = String.format("%s://%s", clusterUri.getScheme(), clusterUri.getHost()); if (StringUtils.isNotEmpty(csb.getApplicationClientId()) && StringUtils.isNotEmpty(csb.getApplicationKey())) { @@ -67,16 +66,18 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS // Set the AAD Authority URI String aadAuthorityId = (csb.getAuthorityId() == null ? DEFAULT_AAD_TENANT : csb.getAuthorityId()); - aadAuthorityUri = String.format("https://login.microsoftonline.com/%s", aadAuthorityId); + String aadAuthorityUri = String.format("https://login.microsoftonline.com/%s", aadAuthorityId); + ExecutorService service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, true, service); } String acquireAccessToken() throws DataServiceException { if (lastAuthenticationResult == null) { - aquireTokenByType(); + acquireToken(); } else { if (isTokenExpired()) { if (lastAuthenticationResult.getRefreshToken() == null) { - aquireTokenByType(); + acquireToken(); } else { lastAuthenticationResultLock.lock(); if (isTokenExpired()) { @@ -90,11 +91,7 @@ String acquireAccessToken() throws DataServiceException { return lastAuthenticationResult.getAccessToken(); } - private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException, MalformedURLException { - if (context == null) { - context = new AuthenticationContext(aadAuthorityUri, true, service); - } - + private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException { AuthenticationResult result; try { Future future = context.acquireToken( @@ -111,11 +108,7 @@ private AuthenticationResult acquireAadUserAccessToken() throws DataServiceExcep return result; } - private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException, MalformedURLException { - if (context == null) { - context = new AuthenticationContext(aadAuthorityUri, true, service); - } - + private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException { AuthenticationResult result; try { Future future = context.acquireToken(clusterUrl, clientCredential, null); @@ -131,10 +124,6 @@ private AuthenticationResult acquireAadApplicationAccessToken() throws DataServi } private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exception { - if (context == null) { - context = new AuthenticationContext(aadAuthorityUri, true, service); - } - AuthenticationResult result; Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); DeviceCode deviceCode = future.get(); @@ -167,10 +156,7 @@ private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCo } AuthenticationResult acquireWithClientCertificate() - throws IOException, InterruptedException, ExecutionException, ServiceUnavailableException { - if (context == null) { - context = new AuthenticationContext(aadAuthorityUri, true, service); - } + throws InterruptedException, ExecutionException, ServiceUnavailableException { AuthenticationResult result; AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(applicationClientId, @@ -184,7 +170,7 @@ AuthenticationResult acquireWithClientCertificate() return result; } - private void aquireTokenByType() throws DataServiceException { + private void acquireToken() throws DataServiceException { lastAuthenticationResultLock.lock(); if(lastAuthenticationResult == null || isTokenExpired()) { try { diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java index 9ce0741e..2bccd042 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java @@ -1,10 +1,11 @@ package com.microsoft.azure.kusto.data; +import java.net.MalformedURLException; import java.net.URISyntaxException; public class ClientFactory { - public static Client createClient(ConnectionStringBuilder csb) throws URISyntaxException { + public static Client createClient(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { return new ClientImpl(csb); } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index 06bc6a9e..e358b23c 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -6,6 +6,7 @@ import org.json.JSONException; import org.json.JSONObject; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; @@ -22,7 +23,7 @@ public class ClientImpl implements Client { private String clientVersionForTracing; private String applicationNameForTracing; - public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { + public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); clientVersionForTracing = "Kusto.Java.Client"; From 7014fa8dd0074d43db8d58b7274454c52dd30c4c Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Tue, 19 Feb 2019 16:43:55 +0200 Subject: [PATCH 17/21] cache access token --- .../com/microsoft/azure/kusto/ingest/IngestClientFactory.java | 3 ++- .../com/microsoft/azure/kusto/ingest/IngestClientImpl.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientFactory.java b/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientFactory.java index 787f9edf..2fbc1e08 100644 --- a/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientFactory.java +++ b/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientFactory.java @@ -2,11 +2,12 @@ import com.microsoft.azure.kusto.data.ConnectionStringBuilder; +import java.net.MalformedURLException; import java.net.URISyntaxException; public class IngestClientFactory { - public static IngestClient createClient(ConnectionStringBuilder csb) throws URISyntaxException { + public static IngestClient createClient(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { return new IngestClientImpl(csb); } } diff --git a/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientImpl.java b/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientImpl.java index 9a53af53..3c638e71 100644 --- a/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientImpl.java +++ b/ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientImpl.java @@ -19,6 +19,7 @@ import java.io.*; import java.lang.invoke.MethodHandles; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -41,7 +42,7 @@ class IngestClientImpl implements IngestClient { private final ResourceManager resourceManager; private AzureStorageHelper azureStorageHelper; - IngestClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { + IngestClientImpl(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { log.info("Creating a new IngestClient"); Client client = ClientFactory.createClient(csb); this.resourceManager = new ResourceManager(client); From c039c2ecdcc728848e921f567dd8799fbea6a7ac Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Tue, 19 Feb 2019 17:34:13 +0200 Subject: [PATCH 18/21] cache access token --- .../kusto/data/AadAuthenticationHelper.java | 95 ++++++++++++++----- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 622123fa..275f8735 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -8,7 +8,6 @@ import javax.naming.ServiceUnavailableException; import java.awt.*; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -29,11 +28,11 @@ public class AadAuthenticationHelper { private String userUsername; private String userPassword; private String clusterUrl; + private String aadAuthorityUri; private X509Certificate x509Certificate; private PrivateKey privateKey; private AuthenticationType authenticationType; private AuthenticationResult lastAuthenticationResult; - private AuthenticationContext context; private Lock lastAuthenticationResultLock = new ReentrantLock(); private String applicationClientId; @@ -44,7 +43,7 @@ private enum AuthenticationType { AAD_APPLICATION_CERTIFICATE } - public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { + public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException { URI clusterUri = new URI(csb.getClusterUrl()); clusterUrl = String.format("%s://%s", clusterUri.getScheme(), clusterUri.getHost()); @@ -66,9 +65,7 @@ public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URIS // Set the AAD Authority URI String aadAuthorityId = (csb.getAuthorityId() == null ? DEFAULT_AAD_TENANT : csb.getAuthorityId()); - String aadAuthorityUri = String.format("https://login.microsoftonline.com/%s", aadAuthorityId); - ExecutorService service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext(aadAuthorityUri, true, service); + aadAuthorityUri = String.format("https://login.microsoftonline.com/%s", aadAuthorityId); } String acquireAccessToken() throws DataServiceException { @@ -92,14 +89,23 @@ String acquireAccessToken() throws DataServiceException { } private AuthenticationResult acquireAadUserAccessToken() throws DataServiceException, DataClientException { + AuthenticationContext context; AuthenticationResult result; + ExecutorService service = null; try { + service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, true, service); + Future future = context.acquireToken( clusterUrl, CLIENT_ID, userUsername, userPassword, null); result = future.get(); - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException | ExecutionException | MalformedURLException e) { throw new DataClientException(clusterUrl, "Error in acquiring UserAccessToken", e); + } finally { + if (service != null) { + service.shutdown(); + } } if (result == null) { @@ -109,12 +115,20 @@ private AuthenticationResult acquireAadUserAccessToken() throws DataServiceExcep } private AuthenticationResult acquireAadApplicationAccessToken() throws DataServiceException, DataClientException { + AuthenticationContext context; AuthenticationResult result; + ExecutorService service = null; try { + service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, true, service); Future future = context.acquireToken(clusterUrl, clientCredential, null); result = future.get(); - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException | ExecutionException | MalformedURLException e) { throw new DataClientException(clusterUrl, "Error in acquiring ApplicationAccessToken", e); + } finally { + if (service != null) { + service.shutdown(); + } } if (result == null) { @@ -124,22 +138,33 @@ private AuthenticationResult acquireAadApplicationAccessToken() throws DataServi } private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exception { - AuthenticationResult result; - Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); - DeviceCode deviceCode = future.get(); - System.out.println(deviceCode.getMessage() + " " + Thread.currentThread()); - if (Desktop.isDesktopSupported()) { - Desktop.getDesktop().browse(new URI(deviceCode.getVerificationUrl())); - } - result = waitAndAcquireTokenByDeviceCode(deviceCode); + AuthenticationContext context = null; + AuthenticationResult result = null; + ExecutorService service = null; + try { + service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, true, service); + Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); + DeviceCode deviceCode = future.get(); + System.out.println(deviceCode.getMessage()); + if (Desktop.isDesktopSupported()) { + Desktop.getDesktop().browse(new URI(deviceCode.getVerificationUrl())); + } + result = waitAndAcquireTokenByDeviceCode(deviceCode, context); + + } finally { + if (service != null) { + service.shutdown(); + } + } if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } return result; } - private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCode) + private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCode, AuthenticationContext context) throws InterruptedException { int timeout = 15 * 1000; AuthenticationResult result = null; @@ -157,12 +182,25 @@ private AuthenticationResult waitAndAcquireTokenByDeviceCode(DeviceCode deviceCo AuthenticationResult acquireWithClientCertificate() throws InterruptedException, ExecutionException, ServiceUnavailableException { - AuthenticationResult result; - AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(applicationClientId, - privateKey, x509Certificate); - // pass null value for optional callback function and acquire access token - result = context.acquireToken(clusterUrl, asymmetricKeyCredential, null).get(); + AuthenticationContext context; + AuthenticationResult result = null; + ExecutorService service = null; + + try { + service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, false, service); + AsymmetricKeyCredential asymmetricKeyCredential = AsymmetricKeyCredential.create(applicationClientId, + privateKey, x509Certificate); + // pass null value for optional callback function and acquire access token + result = context.acquireToken(clusterUrl, asymmetricKeyCredential, null).get(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } finally { + if (service != null) { + service.shutdown(); + } + } if (result == null) { throw new ServiceUnavailableException("authentication result was null"); @@ -172,7 +210,7 @@ AuthenticationResult acquireWithClientCertificate() private void acquireToken() throws DataServiceException { lastAuthenticationResultLock.lock(); - if(lastAuthenticationResult == null || isTokenExpired()) { + if (lastAuthenticationResult == null || isTokenExpired()) { try { switch (authenticationType) { case AAD_APPLICATION_KEY: @@ -197,12 +235,17 @@ private void acquireToken() throws DataServiceException { lastAuthenticationResultLock.unlock(); } - private boolean isTokenExpired(){ + private boolean isTokenExpired() { return lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute()); } AuthenticationResult refreshToken() throws DataServiceException { + AuthenticationContext context; + ExecutorService service = null; + try { + service = Executors.newSingleThreadExecutor(); + context = new AuthenticationContext(aadAuthorityUri, false, service); switch (authenticationType) { case AAD_APPLICATION_KEY: case AAD_APPLICATION_CERTIFICATE: @@ -215,6 +258,10 @@ AuthenticationResult refreshToken() throws DataServiceException { } } catch (Exception e) { throw new DataServiceException(e.getMessage()); + } finally { + if (service != null) { + service.shutdown(); + } } } From ff3ff9919e2ac392b18bdf1a3140b61c2b03afa6 Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 20 Feb 2019 10:31:37 +0200 Subject: [PATCH 19/21] cache access token --- .../azure/kusto/data/AadAuthenticationHelper.java | 12 ++++++------ .../kusto/data/AadAuthenticationHelperTest.java | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 275f8735..987e4402 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -18,11 +18,11 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -public class AadAuthenticationHelper { +class AadAuthenticationHelper { private final static String DEFAULT_AAD_TENANT = "common"; private final static String CLIENT_ID = "db662dc1-0cfe-4e1c-a843-19a68e65be58"; - public final static long ONE_MINUTE_IN_MILLIS = 60000; + final static long MIN_ACCESS_TOKEN_VALIDITY_IN_MILLISECS = 60000; private ClientCredential clientCredential; private String userUsername; @@ -43,7 +43,7 @@ private enum AuthenticationType { AAD_APPLICATION_CERTIFICATE } - public AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException { + AadAuthenticationHelper(@NotNull ConnectionStringBuilder csb) throws URISyntaxException { URI clusterUri = new URI(csb.getClusterUrl()); clusterUrl = String.format("%s://%s", clusterUri.getScheme(), clusterUri.getHost()); @@ -78,7 +78,7 @@ String acquireAccessToken() throws DataServiceException { } else { lastAuthenticationResultLock.lock(); if (isTokenExpired()) { - lastAuthenticationResult = refreshToken(); + lastAuthenticationResult = acquireAccessTokenByRefreshToken(); } lastAuthenticationResultLock.unlock(); } @@ -239,7 +239,7 @@ private boolean isTokenExpired() { return lastAuthenticationResult.getExpiresOnDate().before(dateInAMinute()); } - AuthenticationResult refreshToken() throws DataServiceException { + AuthenticationResult acquireAccessTokenByRefreshToken() throws DataServiceException { AuthenticationContext context; ExecutorService service = null; @@ -266,6 +266,6 @@ AuthenticationResult refreshToken() throws DataServiceException { } Date dateInAMinute() { - return new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS); + return new Date(System.currentTimeMillis() + MIN_ACCESS_TOKEN_VALIDITY_IN_MILLISECS); } } diff --git a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java index 5809cf02..49816573 100644 --- a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java +++ b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java @@ -33,7 +33,7 @@ import javax.naming.ServiceUnavailableException; -import static com.microsoft.azure.kusto.data.AadAuthenticationHelper.ONE_MINUTE_IN_MILLIS; +import static com.microsoft.azure.kusto.data.AadAuthenticationHelper.MIN_ACCESS_TOKEN_VALIDITY_IN_MILLISECS; import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.doReturn; @@ -114,7 +114,7 @@ void useCachedTokenAndRefreshWhenNeeded() throws InterruptedException, Execution AuthenticationResult authenticationResultFromRefresh = new AuthenticationResult("testType", "fromRefresh",null,90,"id", mock(UserInfo.class),false); AuthenticationResult authenticationResultNullRefreshTokenResult = new AuthenticationResult("testType", "nullRefreshResult",null,0,"id", mock(UserInfo.class),false); - doReturn(authenticationResultFromRefresh).when(aadAuthenticationHelperSpy).refreshToken(); + doReturn(authenticationResultFromRefresh).when(aadAuthenticationHelperSpy).acquireAccessTokenByRefreshToken(); doReturn(authenticationResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); assertEquals("firstToken", aadAuthenticationHelperSpy.acquireAccessToken()); @@ -122,7 +122,7 @@ void useCachedTokenAndRefreshWhenNeeded() throws InterruptedException, Execution assertEquals("fromRefresh", aadAuthenticationHelperSpy.acquireAccessToken()); // If no refresh token - it will authenticate again, - doReturn(new Date(System.currentTimeMillis() + ONE_MINUTE_IN_MILLIS * 2)).when(aadAuthenticationHelperSpy).dateInAMinute(); + doReturn(new Date(System.currentTimeMillis() + MIN_ACCESS_TOKEN_VALIDITY_IN_MILLISECS * 2)).when(aadAuthenticationHelperSpy).dateInAMinute(); doReturn(authenticationResultNullRefreshTokenResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); assertEquals("nullRefreshResult", aadAuthenticationHelperSpy.acquireAccessToken()); From 59967f0ce3dd542c52be593d5274cc99498eadab Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 20 Feb 2019 10:53:22 +0200 Subject: [PATCH 20/21] Merge branch 'dev' of https://github.com/Azure/azure-kusto-java into cache-lastAuthenticationResult # Conflicts: # data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java # ingest/src/main/java/com/microsoft/azure/kusto/ingest/IngestClientImpl.java --- .../java/com/microsoft/azure/kusto/data/ClientFactory.java | 3 +-- .../main/java/com/microsoft/azure/kusto/data/ClientImpl.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java index 2bccd042..9ce0741e 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientFactory.java @@ -1,11 +1,10 @@ package com.microsoft.azure.kusto.data; -import java.net.MalformedURLException; import java.net.URISyntaxException; public class ClientFactory { - public static Client createClient(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { + public static Client createClient(ConnectionStringBuilder csb) throws URISyntaxException { return new ClientImpl(csb); } } diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index e358b23c..da190c8a 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -23,7 +23,7 @@ public class ClientImpl implements Client { private String clientVersionForTracing; private String applicationNameForTracing; - public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException, MalformedURLException { + public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException { clusterUrl = csb.getClusterUrl(); aadAuthenticationHelper = new AadAuthenticationHelper(csb); clientVersionForTracing = "Kusto.Java.Client"; From 04c81d785dcf7e811ce5efeadf2f05fca13eb72b Mon Sep 17 00:00:00 2001 From: Ohad Bitton Date: Wed, 20 Feb 2019 15:44:38 +0200 Subject: [PATCH 21/21] last changes --- .../kusto/data/AadAuthenticationHelper.java | 22 ++++++++---------- .../azure/kusto/data/ClientImpl.java | 1 - .../data/AadAuthenticationHelperTest.java | 23 ++++++++++--------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java index 94a5b62f..f35386b5 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/AadAuthenticationHelper.java @@ -74,23 +74,21 @@ private enum AuthenticationType { } String acquireAccessToken() throws DataServiceException { - if(authenticationType == AuthenticationType.AAD_ACCESS_TOKEN){ + if (authenticationType == AuthenticationType.AAD_ACCESS_TOKEN) { return accessToken; } if (lastAuthenticationResult == null) { acquireToken(); - } else { - if (isTokenExpired()) { - if (lastAuthenticationResult.getRefreshToken() == null) { - acquireToken(); - } else { - lastAuthenticationResultLock.lock(); - if (isTokenExpired()) { - lastAuthenticationResult = acquireAccessTokenByRefreshToken(); - } - lastAuthenticationResultLock.unlock(); + } else if (isTokenExpired()) { + if (lastAuthenticationResult.getRefreshToken() == null) { + acquireToken(); + } else { + lastAuthenticationResultLock.lock(); + if (isTokenExpired()) { + lastAuthenticationResult = acquireAccessTokenByRefreshToken(); } + lastAuthenticationResultLock.unlock(); } } @@ -152,7 +150,7 @@ private AuthenticationResult acquireAccessTokenUsingDeviceCodeFlow() throws Exce ExecutorService service = null; try { service = Executors.newSingleThreadExecutor(); - context = new AuthenticationContext( aadAuthorityUri, true, service); + context = new AuthenticationContext(aadAuthorityUri, true, service); Future future = context.acquireDeviceCode(CLIENT_ID, clusterUrl, null); DeviceCode deviceCode = future.get(); System.out.println(deviceCode.getMessage()); diff --git a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java index da190c8a..06bc6a9e 100644 --- a/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java +++ b/data/src/main/java/com/microsoft/azure/kusto/data/ClientImpl.java @@ -6,7 +6,6 @@ import org.json.JSONException; import org.json.JSONObject; -import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; diff --git a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java index 49816573..bb1a791c 100644 --- a/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java +++ b/data/src/test/java/com/microsoft/azure/kusto/data/AadAuthenticationHelperTest.java @@ -42,14 +42,13 @@ public class AadAuthenticationHelperTest { - @Test @DisplayName("validate auth with certificate throws exception when missing or invalid parameters") void acquireWithClientCertificateNullKey() throws CertificateException, OperatorCreationException, PKCSException, IOException, URISyntaxException { - String certFilePath = Paths.get("src","test","resources", "cert.cer").toString(); - String privateKeyPath = Paths.get("src","test","resources","key.pem").toString(); + String certFilePath = Paths.get("src", "test", "resources", "cert.cer").toString(); + String privateKeyPath = Paths.get("src", "test", "resources", "key.pem").toString(); X509Certificate x509Certificate = readPem(certFilePath, "basic").getCertificate(); PrivateKey privateKey = readPem(privateKeyPath, "basic").getKey(); @@ -99,8 +98,8 @@ static KeyCert readPem(String path, String password) @Test @DisplayName("validate cached token. Refresh if needed. Call regularly if no refresh token") void useCachedTokenAndRefreshWhenNeeded() throws InterruptedException, ExecutionException, ServiceUnavailableException, IOException, DataServiceException, URISyntaxException, CertificateException, OperatorCreationException, PKCSException { - String certFilePath = Paths.get("src","test","resources", "cert.cer").toString(); - String privateKeyPath = Paths.get("src","test","resources","key.pem").toString(); + String certFilePath = Paths.get("src", "test", "resources", "cert.cer").toString(); + String privateKeyPath = Paths.get("src", "test", "resources", "key.pem").toString(); X509Certificate x509Certificate = readPem(certFilePath, "basic").getCertificate(); PrivateKey privateKey = readPem(privateKeyPath, "basic").getKey(); @@ -110,23 +109,25 @@ void useCachedTokenAndRefreshWhenNeeded() throws InterruptedException, Execution AadAuthenticationHelper aadAuthenticationHelperSpy = spy(new AadAuthenticationHelper(csb)); - AuthenticationResult authenticationResult = new AuthenticationResult("testType", "firstToken","refreshToken",0,"id", mock(UserInfo.class),false); - AuthenticationResult authenticationResultFromRefresh = new AuthenticationResult("testType", "fromRefresh",null,90,"id", mock(UserInfo.class),false); - AuthenticationResult authenticationResultNullRefreshTokenResult = new AuthenticationResult("testType", "nullRefreshResult",null,0,"id", mock(UserInfo.class),false); + AuthenticationResult authenticationResult = new AuthenticationResult("testType", "firstToken", "refreshToken", 0, "id", mock(UserInfo.class), false); + AuthenticationResult authenticationResultFromRefresh = new AuthenticationResult("testType", "fromRefresh", null, 90, "id", mock(UserInfo.class), false); + AuthenticationResult authenticationResultNullRefreshTokenResult = new AuthenticationResult("testType", "nullRefreshResult", null, 0, "id", mock(UserInfo.class), false); doReturn(authenticationResultFromRefresh).when(aadAuthenticationHelperSpy).acquireAccessTokenByRefreshToken(); doReturn(authenticationResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); assertEquals("firstToken", aadAuthenticationHelperSpy.acquireAccessToken()); + + // Token was passed as expired - expected to be refreshed assertEquals("fromRefresh", aadAuthenticationHelperSpy.acquireAccessToken()); + + // Token is still valid - expected to return the same assertEquals("fromRefresh", aadAuthenticationHelperSpy.acquireAccessToken()); - // If no refresh token - it will authenticate again, doReturn(new Date(System.currentTimeMillis() + MIN_ACCESS_TOKEN_VALIDITY_IN_MILLISECS * 2)).when(aadAuthenticationHelperSpy).dateInAMinute(); doReturn(authenticationResultNullRefreshTokenResult).when(aadAuthenticationHelperSpy).acquireWithClientCertificate(); + // Null refresh token + token is now expired- expected to authenticate again and reacquire token assertEquals("nullRefreshResult", aadAuthenticationHelperSpy.acquireAccessToken()); - // Null refreshToken - } }