From e928bd040f6b36596537a0fd8fcd0b9c6e99f8a6 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Fri, 26 Jun 2020 17:43:11 -0700 Subject: [PATCH 01/12] Upgrade msal extensions to 0.2.0 --- eng/versioning/external_dependencies.txt | 2 +- sdk/identity/azure-identity/pom.xml | 31 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/eng/versioning/external_dependencies.txt b/eng/versioning/external_dependencies.txt index 4609f9a6eac6..ca70dff13f19 100644 --- a/eng/versioning/external_dependencies.txt +++ b/eng/versioning/external_dependencies.txt @@ -111,7 +111,7 @@ com.microsoft.azure:azure-mgmt-resources;1.3.0 com.microsoft.azure:azure-mgmt-search;1.24.1 com.microsoft.azure:azure-mgmt-storage;1.3.0 com.microsoft.azure:azure-storage;8.0.0 -com.microsoft.azure:msal4j;0.5.0-preview +com.microsoft.azure:msal4j;1.6.1 com.sun.activation:jakarta.activation;1.2.1 io.opentelemetry:opentelemetry-api;0.2.4 io.opentelemetry:opentelemetry-sdk;0.2.4 diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index ebb2c286141a..6557d9e3db52 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -70,7 +70,8 @@ com.microsoft.azure msal4j - 0.5.0-preview + 1.6.1 + com.nimbusds @@ -119,4 +120,32 @@ test +<<<<<<< HEAD +======= + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M3 + + + + + com.azure:* + com.microsoft.azure:msal4j:[1.6.1] + com.microsoft.azure:msal4j-persistence-extension:[0.2.0] + com.nimbusds:oauth2-oidc-sdk:[6.14] + net.java.dev.jna:jna-platform:[5.4.0] + org.linguafranca.pwdb:KeePassJava2:[2.1.4] + org.nanohttpd:nanohttpd:[2.3.1] + + + + + + + +>>>>>>> 1b6e594763... Upgrade msal extensions to 0.2.0 From c01ba8b0860ff5f84385fa08b14ce99c244e44d3 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Sat, 27 Jun 2020 16:15:44 -0700 Subject: [PATCH 02/12] Bump msal version everywhere --- sdk/eventhubs/microsoft-azure-eventhubs/pom.xml | 2 +- sdk/spring/azure-spring-boot-starter-active-directory/pom.xml | 4 ++-- sdk/spring/azure-spring-boot/pom.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/eventhubs/microsoft-azure-eventhubs/pom.xml b/sdk/eventhubs/microsoft-azure-eventhubs/pom.xml index 585745111cd6..c8bbb53d00fb 100644 --- a/sdk/eventhubs/microsoft-azure-eventhubs/pom.xml +++ b/sdk/eventhubs/microsoft-azure-eventhubs/pom.xml @@ -76,7 +76,7 @@ com.microsoft.azure msal4j - 0.5.0-preview + 1.6.1 test diff --git a/sdk/spring/azure-spring-boot-starter-active-directory/pom.xml b/sdk/spring/azure-spring-boot-starter-active-directory/pom.xml index 22852e82eb4e..424f564150c9 100644 --- a/sdk/spring/azure-spring-boot-starter-active-directory/pom.xml +++ b/sdk/spring/azure-spring-boot-starter-active-directory/pom.xml @@ -58,7 +58,7 @@ com.microsoft.azure msal4j - 0.5.0-preview + 1.6.1 com.nimbusds @@ -84,7 +84,7 @@ com.microsoft.azure:azure-spring-boot:[2.3.3-beta.1] --> com.fasterxml.jackson.core:jackson-databind:[2.10.1] - com.microsoft.azure:msal4j:[0.5.0-preview] + com.microsoft.azure:msal4j:[1.6.1] com.nimbusds:nimbus-jose-jwt:[7.9] org.springframework:spring-web:[5.2.6.RELEASE] org.springframework.boot:spring-boot-starter:[2.3.0.RELEASE] diff --git a/sdk/spring/azure-spring-boot/pom.xml b/sdk/spring/azure-spring-boot/pom.xml index 18f0dc0f75d0..fce3c692d4ce 100644 --- a/sdk/spring/azure-spring-boot/pom.xml +++ b/sdk/spring/azure-spring-boot/pom.xml @@ -159,7 +159,7 @@ com.microsoft.azure msal4j - 0.5.0-preview + 1.6.1 true @@ -268,7 +268,7 @@ com.google.code.findbugs:jsr305:[3.0.2] net.minidev:json-smart:[2.3] com.microsoft.azure:azure-servicebus-jms:[0.0.2] - com.microsoft.azure:msal4j:[0.5.0-preview] + com.microsoft.azure:msal4j:[1.6.1] com.microsoft.azure:spring-data-cosmosdb:[2.3.0] com.microsoft.spring.data.gremlin:spring-data-gremlin:[2.2.3] com.nimbusds:nimbus-jose-jwt:[7.9] From 96af9209e4fcbf4057b31185be15c23850b58d9a Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 11:55:22 -0700 Subject: [PATCH 03/12] Address readme feedback --- sdk/identity/azure-identity/README.md | 34 +++++++-------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/sdk/identity/azure-identity/README.md b/sdk/identity/azure-identity/README.md index b45f08c3a943..16571578c405 100644 --- a/sdk/identity/azure-identity/README.md +++ b/sdk/identity/azure-identity/README.md @@ -11,32 +11,8 @@ The Azure Identity library provides Azure Active Directory token authentication [Source code][source] | [API reference documentation][javadoc] | [Azure Active Directory documentation][aad_doc] -## Table of contents -- [Getting started](#getting-started) - - [Adding the package to your project](#adding-the-package-to-your-project) - - [Prerequisites](#prerequisites) - - [Creating a Service Principal with the Azure CLI](#creating-a-service-principal-with-the-azure-cli) - - [Enable applications for device code flow](#enable-applications-for-device-code-flow) - - [Enable applications for interactive browser oauth 2 flow](#enable-applications-for-interactive-browser-oauth-2-flow) - - [Enable applications for oauth 2 auth code flow](#enable-applications-for-oauth-2-auth-code-flow) - - [Enable applications for shared token cache credential](#enable-applications-for-shared-token-cache-credential) - - [Key concepts](#key-concepts) - - [Credentials](#credentials) - - [DefaultAzureCredential](#defaultazurecredential) - - [Environment variables](#environment-variables) -- [Examples](#examples) - - [Authenticating with `DefaultAzureCredential`](#authenticating-with-defaultazurecredential) - - [Authenticating a service principal with a client secret](#authenticating-a-service-principal-with-a-client-secret) - - [Authenticating a user account with device code flow](#authenticating-a-user-account-with-device-code-flow) - - [Authenticating a user account with username and password](#authenticating-a-user-account-with-username-and-password) - - [Authenticating a user account with auth code flow](#authenticating-a-user-account-with-auth-code-flow) - - [Chaining credentials](#chaining-credentials) -- [Troubleshooting](#troubleshooting) -- [Next steps](#next-steps) -- [Contributing](#contributing) - ## Getting started -### Adding the package to your project +### Include the package Maven dependency for Azure Secret Client library. Add it to your project's pom file. @@ -148,6 +124,14 @@ principal authentication with these environment variables: ## Examples +### Table of contents + - [Authenticating with `DefaultAzureCredential`](#authenticating-with-defaultazurecredential) + - [Authenticating a service principal with a client secret](#authenticating-a-service-principal-with-a-client-secret) + - [Authenticating a user account with device code flow](#authenticating-a-user-account-with-device-code-flow) + - [Authenticating a user account with username and password](#authenticating-a-user-account-with-username-and-password) + - [Authenticating a user account with auth code flow](#authenticating-a-user-account-with-auth-code-flow) + - [Chaining credentials](#chaining-credentials) + ### Authenticating with `DefaultAzureCredential` This example demonstrates authenticating the `SecretClient` from the [azure-security-keyvault-secrets][secrets_client_library] client library using the `DefaultAzureCredential`. There's also [a compilable sample](../../keyvault/azure-security-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/IdentitySamples.java) to create a Key Vault secret client you can copy-paste. From 88cdb9333b9b45006d74413b98fcb0a49dfbd008 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 15:20:11 -0700 Subject: [PATCH 04/12] Bump identity version to 1.0.9 --- eng/jacoco-test-coverage/pom.xml | 2 +- eng/versioning/version_client.txt | 4 ++-- sdk/e2e/pom.xml | 2 +- sdk/identity/azure-identity/pom.xml | 32 ++-------------------------- sdk/spring/azure-spring-boot/pom.xml | 2 +- 5 files changed, 7 insertions(+), 35 deletions(-) diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index b86c61b38567..9c830791f2a5 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -134,7 +134,7 @@ com.azure azure-identity - 1.1.0-beta.1 + 1.0.9 com.azure diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index b6a33f9866fb..54135372cbb5 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -26,7 +26,7 @@ com.azure:azure-data-schemaregistry;1.0.0-beta.2;1.0.0-beta.3 com.azure:azure-data-schemaregistry-avro;1.0.0-beta.2;1.0.0-beta.3 com.azure:azure-data-tables;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-e2e;1.0.0-beta.1;1.0.0-beta.1 -com.azure:azure-identity;1.0.8;1.1.0-beta.1 +com.azure:azure-identity;1.0.8;1.0.9 com.azure:azure-messaging-eventhubs;5.1.1;5.2.0-beta.1 com.azure:azure-messaging-eventhubs-checkpointstore-blob;1.1.1;1.2.0-beta.1 com.azure:azure-messaging-servicebus;7.0.0-beta.3;7.0.0-beta.4 @@ -66,7 +66,7 @@ com.microsoft.azure:spring-data-cosmosdb;2.3.0;2.3.1-beta.1 # Format; # unreleased_:;dependency-version # note: The unreleased dependencies will not be manipulated with the automatic PR creation code. - +unreleased_com.azure:azure-identity;1.0.9 unreleased_com.azure:azure-messaging-servicebus;7.0.0-beta.4 # Released Beta dependencies: Copy the entry from above, prepend "beta_", remove the current diff --git a/sdk/e2e/pom.xml b/sdk/e2e/pom.xml index b9b34b1049dc..e35512e985e1 100644 --- a/sdk/e2e/pom.xml +++ b/sdk/e2e/pom.xml @@ -33,7 +33,7 @@ com.azure azure-identity - 1.1.0-beta.1 + 1.0.9 com.azure diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index 6557d9e3db52..3380967235f4 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -6,7 +6,7 @@ com.azure azure-identity - 1.1.0-beta.1 + 1.0.9 Microsoft Azure client library for Identity This module contains client library for Microsoft Azure Identity. @@ -48,7 +48,7 @@ com.azure:* - com.microsoft.azure:msal4j:[0.5.0-preview] + com.microsoft.azure:msal4j:[1.6.1] com.nimbusds:oauth2-oidc-sdk:[6.14] net.java.dev.jna:jna-platform:[5.4.0] org.nanohttpd:nanohttpd:[2.3.1] @@ -120,32 +120,4 @@ test -<<<<<<< HEAD -======= - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.0.0-M3 - - - - - com.azure:* - com.microsoft.azure:msal4j:[1.6.1] - com.microsoft.azure:msal4j-persistence-extension:[0.2.0] - com.nimbusds:oauth2-oidc-sdk:[6.14] - net.java.dev.jna:jna-platform:[5.4.0] - org.linguafranca.pwdb:KeePassJava2:[2.1.4] - org.nanohttpd:nanohttpd:[2.3.1] - - - - - - - ->>>>>>> 1b6e594763... Upgrade msal extensions to 0.2.0 diff --git a/sdk/spring/azure-spring-boot/pom.xml b/sdk/spring/azure-spring-boot/pom.xml index fce3c692d4ce..7db70abf6c89 100644 --- a/sdk/spring/azure-spring-boot/pom.xml +++ b/sdk/spring/azure-spring-boot/pom.xml @@ -166,7 +166,7 @@ com.azure azure-identity - 1.0.8 + 1.0.9 From c4f92a5e3140b90bd3f460b26f5244003631c9e4 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 15:32:08 -0700 Subject: [PATCH 05/12] Increment package version after release of com.azure azure-identity (#12871) (#13217) Co-authored-by: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> --- eng/jacoco-test-coverage/pom.xml | 2 +- eng/versioning/version_client.txt | 2 +- sdk/appconfiguration/azure-data-appconfiguration/pom.xml | 2 +- sdk/e2e/pom.xml | 2 +- .../azure-messaging-eventhubs-checkpointstore-blob/pom.xml | 2 +- sdk/eventhubs/azure-messaging-eventhubs/pom.xml | 2 +- sdk/formrecognizer/azure-ai-formrecognizer/pom.xml | 2 +- sdk/identity/azure-identity/CHANGELOG.md | 3 +++ sdk/identity/azure-identity/pom.xml | 2 +- sdk/keyvault/azure-security-keyvault-certificates/pom.xml | 2 +- sdk/keyvault/azure-security-keyvault-keys/pom.xml | 2 +- sdk/keyvault/azure-security-keyvault-secrets/pom.xml | 2 +- sdk/servicebus/azure-messaging-servicebus/pom.xml | 2 +- sdk/spring/azure-spring-boot/pom.xml | 2 +- sdk/storage/azure-storage-blob-batch/pom.xml | 2 +- sdk/storage/azure-storage-blob-changefeed/pom.xml | 2 +- sdk/storage/azure-storage-blob-cryptography/pom.xml | 2 +- sdk/storage/azure-storage-blob/pom.xml | 2 +- sdk/storage/azure-storage-common/pom.xml | 2 +- sdk/storage/azure-storage-file-datalake/pom.xml | 2 +- sdk/storage/azure-storage-queue/pom.xml | 2 +- sdk/textanalytics/azure-ai-textanalytics/pom.xml | 2 +- 22 files changed, 24 insertions(+), 21 deletions(-) diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index 0a2e9faedae2..b86c61b38567 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -134,7 +134,7 @@ com.azure azure-identity - 1.0.8 + 1.1.0-beta.1 com.azure diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 02fc7cb3aef0..b6a33f9866fb 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -26,7 +26,7 @@ com.azure:azure-data-schemaregistry;1.0.0-beta.2;1.0.0-beta.3 com.azure:azure-data-schemaregistry-avro;1.0.0-beta.2;1.0.0-beta.3 com.azure:azure-data-tables;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-e2e;1.0.0-beta.1;1.0.0-beta.1 -com.azure:azure-identity;1.0.7;1.0.8 +com.azure:azure-identity;1.0.8;1.1.0-beta.1 com.azure:azure-messaging-eventhubs;5.1.1;5.2.0-beta.1 com.azure:azure-messaging-eventhubs-checkpointstore-blob;1.1.1;1.2.0-beta.1 com.azure:azure-messaging-servicebus;7.0.0-beta.3;7.0.0-beta.4 diff --git a/sdk/appconfiguration/azure-data-appconfiguration/pom.xml b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml index be05c61b3990..d2e314817ee9 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/pom.xml +++ b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml @@ -90,7 +90,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/e2e/pom.xml b/sdk/e2e/pom.xml index 5f0915a3d036..b9b34b1049dc 100644 --- a/sdk/e2e/pom.xml +++ b/sdk/e2e/pom.xml @@ -33,7 +33,7 @@ com.azure azure-identity - 1.0.8 + 1.1.0-beta.1 com.azure diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/pom.xml b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/pom.xml index 859cdcb77784..6ee4b3c6c99a 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/pom.xml +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/pom.xml @@ -52,7 +52,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml index c9200f744bac..7d0f5adbebb5 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml +++ b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml @@ -49,7 +49,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/pom.xml b/sdk/formrecognizer/azure-ai-formrecognizer/pom.xml index a6b6d4f43755..b66a00efe533 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/pom.xml +++ b/sdk/formrecognizer/azure-ai-formrecognizer/pom.xml @@ -78,7 +78,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 4dcd1afc0c46..e18eca60e91c 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,5 +1,8 @@ # Release History +## 1.1.0-beta.1 (Unreleased) + + ## 1.0.8 (2020-07-06) - Upgraded `azure-core` dependency to 1.6.0 diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index b2d78cf34f53..ebb2c286141a 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -6,7 +6,7 @@ com.azure azure-identity - 1.0.8 + 1.1.0-beta.1 Microsoft Azure client library for Identity This module contains client library for Microsoft Azure Identity. diff --git a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml index 91e062ccab1c..023eedb9f8f1 100644 --- a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml @@ -98,7 +98,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/keyvault/azure-security-keyvault-keys/pom.xml b/sdk/keyvault/azure-security-keyvault-keys/pom.xml index 598fcabd84ef..06ebf5db2f63 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-keys/pom.xml @@ -105,7 +105,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/keyvault/azure-security-keyvault-secrets/pom.xml b/sdk/keyvault/azure-security-keyvault-secrets/pom.xml index 7ae99e90d3b2..d6df31c331af 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-secrets/pom.xml @@ -105,7 +105,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/servicebus/azure-messaging-servicebus/pom.xml b/sdk/servicebus/azure-messaging-servicebus/pom.xml index d89741dde4f1..96e672011dd6 100644 --- a/sdk/servicebus/azure-messaging-servicebus/pom.xml +++ b/sdk/servicebus/azure-messaging-servicebus/pom.xml @@ -71,7 +71,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/spring/azure-spring-boot/pom.xml b/sdk/spring/azure-spring-boot/pom.xml index 58fe6861eedf..18f0dc0f75d0 100644 --- a/sdk/spring/azure-spring-boot/pom.xml +++ b/sdk/spring/azure-spring-boot/pom.xml @@ -166,7 +166,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 diff --git a/sdk/storage/azure-storage-blob-batch/pom.xml b/sdk/storage/azure-storage-blob-batch/pom.xml index 9834337dc64c..d7e99ec5192c 100644 --- a/sdk/storage/azure-storage-blob-batch/pom.xml +++ b/sdk/storage/azure-storage-blob-batch/pom.xml @@ -87,7 +87,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-blob-changefeed/pom.xml b/sdk/storage/azure-storage-blob-changefeed/pom.xml index 7cfe14796bbb..bfc94e8ecc89 100644 --- a/sdk/storage/azure-storage-blob-changefeed/pom.xml +++ b/sdk/storage/azure-storage-blob-changefeed/pom.xml @@ -87,7 +87,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-blob-cryptography/pom.xml b/sdk/storage/azure-storage-blob-cryptography/pom.xml index cf6cc2e0eb7d..d8bc4ca17c52 100644 --- a/sdk/storage/azure-storage-blob-cryptography/pom.xml +++ b/sdk/storage/azure-storage-blob-cryptography/pom.xml @@ -95,7 +95,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-blob/pom.xml b/sdk/storage/azure-storage-blob/pom.xml index 90a19dbf5006..9c5827fe38b6 100644 --- a/sdk/storage/azure-storage-blob/pom.xml +++ b/sdk/storage/azure-storage-blob/pom.xml @@ -92,7 +92,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-common/pom.xml b/sdk/storage/azure-storage-common/pom.xml index a3503e01608c..51a09380c754 100644 --- a/sdk/storage/azure-storage-common/pom.xml +++ b/sdk/storage/azure-storage-common/pom.xml @@ -68,7 +68,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-file-datalake/pom.xml b/sdk/storage/azure-storage-file-datalake/pom.xml index 588d783e1202..a2eec8ff6284 100644 --- a/sdk/storage/azure-storage-file-datalake/pom.xml +++ b/sdk/storage/azure-storage-file-datalake/pom.xml @@ -83,7 +83,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/storage/azure-storage-queue/pom.xml b/sdk/storage/azure-storage-queue/pom.xml index 2d7394845351..cd814256e79f 100644 --- a/sdk/storage/azure-storage-queue/pom.xml +++ b/sdk/storage/azure-storage-queue/pom.xml @@ -71,7 +71,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test diff --git a/sdk/textanalytics/azure-ai-textanalytics/pom.xml b/sdk/textanalytics/azure-ai-textanalytics/pom.xml index e4fe82eec1f4..215b304ea488 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/pom.xml +++ b/sdk/textanalytics/azure-ai-textanalytics/pom.xml @@ -88,7 +88,7 @@ com.azure azure-identity - 1.0.7 + 1.0.8 test From 61f5591b9235cc57fb9667c86768a66ea7807275 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 15:44:01 -0700 Subject: [PATCH 06/12] Fix merge error --- sdk/identity/azure-identity/pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index 1f87634ea05c..4c3c5ce63fd1 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -71,7 +71,6 @@ msal4j 1.6.1 - com.nimbusds oauth2-oidc-sdk @@ -82,7 +81,6 @@ nanohttpd 2.3.1 - junit junit From 99e8c10842ff3661b8c4e7cb3d386cdbd75962c4 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 16:40:54 -0700 Subject: [PATCH 07/12] fix build errors and tests --- .../implementation/IdentityClient.java | 9 +- .../implementation/IdentityClientTests.java | 10 +- .../msalextensions/CacheLockTest.java | 235 --------------- .../msalextensions/CrossProgramVSTest.java | 127 --------- .../msalextensions/FileWriter.java | 47 --- .../msalextensions/MsalCacheStorageTest.java | 47 --- .../MultithreadedTokenCacheTest.java | 193 ------------- .../PersistentTokenCacheAccessAspectTest.java | 267 ------------------ .../msalextensions/TestConfiguration.java | 19 -- .../com/azure/identity/util/TestUtils.java | 18 +- .../autoconfigure/aad/AzureADGraphClient.java | 2 +- 11 files changed, 27 insertions(+), 947 deletions(-) delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java delete mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java index 33cad876b36b..5523b8d6a42d 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java @@ -110,7 +110,7 @@ public Mono authenticateWithClientSecret(String clientSecret, Token String authorityUrl = options.getAuthorityHost().replaceAll("/+$", "") + "/" + tenantId; try { ConfidentialClientApplication.Builder applicationBuilder = - ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.create(clientSecret)) + ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(clientSecret)) .authority(authorityUrl); if (options.getProxyOptions() != null) { applicationBuilder.proxy(proxyOptionsToJavaNetProxy(options.getProxyOptions())); @@ -139,8 +139,8 @@ public Mono authenticateWithPfxCertificate(String pfxCertificatePat String authorityUrl = options.getAuthorityHost().replaceAll("/+$", "") + "/" + tenantId; try { ConfidentialClientApplication.Builder applicationBuilder = - ConfidentialClientApplication.builder(clientId, - ClientCredentialFactory.create(new FileInputStream(pfxCertificatePath), pfxCertificatePassword)) + ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromCertificate( + new FileInputStream(pfxCertificatePath), pfxCertificatePassword)) .authority(authorityUrl); if (options.getProxyOptions() != null) { applicationBuilder.proxy(proxyOptionsToJavaNetProxy(options.getProxyOptions())); @@ -174,7 +174,8 @@ public Mono authenticateWithPemCertificate(String pemCertificatePat byte[] pemCertificateBytes = Files.readAllBytes(Paths.get(pemCertificatePath)); ConfidentialClientApplication.Builder applicationBuilder = ConfidentialClientApplication.builder(clientId, - ClientCredentialFactory.create(CertificateUtil.privateKeyFromPem(pemCertificateBytes), + ClientCredentialFactory.createFromCertificate( + CertificateUtil.privateKeyFromPem(pemCertificateBytes), CertificateUtil.publicKeyFromPem(pemCertificateBytes))).authority(authorityUrl); if (options.getProxyOptions() != null) { applicationBuilder.proxy(proxyOptionsToJavaNetProxy(options.getProxyOptions())); diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java index 9544bef34c8c..d5aec209d1e2 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java @@ -6,11 +6,11 @@ import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenRequestContext; import com.azure.identity.util.TestUtils; -import com.microsoft.aad.msal4j.AsymmetricKeyCredential; import com.microsoft.aad.msal4j.ClientCredentialParameters; -import com.microsoft.aad.msal4j.ClientSecret; import com.microsoft.aad.msal4j.ConfidentialClientApplication; import com.microsoft.aad.msal4j.DeviceCodeFlowParameters; +import com.microsoft.aad.msal4j.IClientCredential; +import com.microsoft.aad.msal4j.IClientSecret; import com.microsoft.aad.msal4j.MsalServiceException; import com.microsoft.aad.msal4j.PublicClientApplication; import org.junit.Assert; @@ -156,7 +156,7 @@ private void mockForClientSecret(String secret, TokenRequestContext request, Str when(builder.authority(any())).thenReturn(builder); whenNew(ConfidentialClientApplication.Builder.class).withAnyArguments().thenAnswer(invocation -> { String cid = (String) invocation.getArguments()[0]; - ClientSecret clientSecret = (ClientSecret) invocation.getArguments()[1]; + IClientSecret clientSecret = (IClientSecret) invocation.getArguments()[1]; if (!clientId.equals(cid)) { throw new MsalServiceException("Invalid clientId", "InvalidClientId"); } @@ -184,11 +184,11 @@ private void mockForClientCertificate(TokenRequestContext request, String access when(builder.authority(any())).thenReturn(builder); whenNew(ConfidentialClientApplication.Builder.class).withAnyArguments().thenAnswer(invocation -> { String cid = (String) invocation.getArguments()[0]; - AsymmetricKeyCredential keyCredential = (AsymmetricKeyCredential) invocation.getArguments()[1]; + IClientCredential keyCredential = (IClientCredential) invocation.getArguments()[1]; if (!clientId.equals(cid)) { throw new MsalServiceException("Invalid clientId", "InvalidClientId"); } - if (keyCredential == null || keyCredential.key() == null) { + if (keyCredential == null) { throw new MsalServiceException("Invalid clientCertificate", "InvalidClientCertificate"); } return builder; diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java deleted file mode 100644 index f28d76a8aef3..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import com.sun.jna.Platform; -import org.junit.*; - -import java.io.*; -import java.util.Stack; -import java.util.stream.Collectors; - -public class CacheLockTest { - - private static String folder; - private static String testerFilename; - private static String lockfile; - - @BeforeClass - public static void setup() { - // get proper file paths - String currDir = System.getProperty("user.dir"); - String home = System.getProperty("user.home"); - - java.nio.file.Path classes = java.nio.file.Paths.get(currDir, "target", "classes"); - java.nio.file.Path tests = java.nio.file.Paths.get(currDir, "target", "test-classes"); - - testerFilename = java.nio.file.Paths.get(home, "tester.txt").toString(); - lockfile = java.nio.file.Paths.get(home, "testlock.lockfile").toString(); - - String delimiter = ":"; - if (Platform.isWindows()) { - delimiter = ";"; - } - folder = classes.toString() + delimiter + tests; - } - - @Test - public void tenThreadsWritingToFile() throws IOException { - - // make sure tester.json file doesn't already exist - File tester = new File(testerFilename); - tester.delete(); - - // delete the lock file just in case before starting - File lock = new File(lockfile); - lock.delete(); - - FileWriter a = new FileWriter("a", lockfile, testerFilename); - FileWriter b = new FileWriter("b", lockfile, testerFilename); - FileWriter c = new FileWriter("c", lockfile, testerFilename); - FileWriter d = new FileWriter("d", lockfile, testerFilename); - FileWriter e = new FileWriter("e", lockfile, testerFilename); - FileWriter f = new FileWriter("f", lockfile, testerFilename); - FileWriter g = new FileWriter("g", lockfile, testerFilename); - FileWriter h = new FileWriter("h", lockfile, testerFilename); - FileWriter i = new FileWriter("i", lockfile, testerFilename); - FileWriter j = new FileWriter("j", lockfile, testerFilename); - - try { - a.t.join(); - b.t.join(); - c.t.join(); - d.t.join(); - e.t.join(); - f.t.join(); - g.t.join(); - h.t.join(); - i.t.join(); - j.t.join(); - } catch (Exception ex) { - System.out.printf("Error with threads"); - } - - Stack stack = new Stack<>(); - int popped = 0; - - File file = new File(testerFilename); - - if (file.exists()) { - FileReader reader = new FileReader(file); - BufferedReader bufferedReader = new BufferedReader(reader); - StringBuffer stringBuffer = new StringBuffer(); - String line; - while ((line = bufferedReader.readLine()) != null) { - String[] tokens = line.split(" "); - if (tokens[0].equals("<")) { // enter - stack.push(tokens[1]); - } else if (tokens[0].equals(">")) { // exit - if (stack.peek().equals(tokens[1])) { - stack.pop(); - popped++; - } else { - System.out.println("messed up: " + tokens[1]); - } - } - } - reader.close(); - - if (!stack.empty()) { - Assert.fail(); - } - } else { - Assert.fail("File does not exist"); - } - - Assert.assertEquals("10 processes didn't write", popped, 10); - - } - - @Ignore("Run local only - CI does not support classpath well") - public void tenProcessesWritingToFile() throws IOException, InterruptedException { - // make sure tester.json file doesn't already exist - File tester = new File(testerFilename); - tester.delete(); - - // delete the lock file just in case before starting - File lock = new File(lockfile); - lock.delete(); - - String mainClass = com.azure.identity.implementation.msalextensions.FileWriter.class.getName(); - Process process1 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(1), lockfile, testerFilename}).start(); - Process process2 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(2), lockfile, testerFilename}).start(); - Process process3 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(3), lockfile, testerFilename}).start(); - Process process4 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(4), lockfile, testerFilename}).start(); - Process process5 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(5), lockfile, testerFilename}).start(); - Process process6 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(6), lockfile, testerFilename}).start(); - Process process7 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(7), lockfile, testerFilename}).start(); - Process process8 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(8), lockfile, testerFilename}).start(); - Process process9 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(9), lockfile, testerFilename}).start(); - Process process10 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(10), lockfile, testerFilename}).start(); - - waitForProcess(process1); - waitForProcess(process2); - waitForProcess(process3); - waitForProcess(process4); - waitForProcess(process5); - waitForProcess(process6); - waitForProcess(process7); - waitForProcess(process8); - waitForProcess(process9); - waitForProcess(process10); - - Stack stack = new Stack<>(); - int popped = 0; - - File file = new File(testerFilename); - if (file.exists()) { - FileReader reader = new FileReader(file); - BufferedReader bufferedReader = new BufferedReader(reader); - StringBuffer stringBuffer = new StringBuffer(); - String line; - while ((line = bufferedReader.readLine()) != null) { - String[] tokens = line.split(" "); - if (tokens[0].equals("<")) { // enter - stack.push(tokens[1]); - } else if (tokens[0].equals(">")) { // exit - if (stack.peek().equals(tokens[1])) { - stack.pop(); - popped++; - } else { - System.out.println("messed up: " + tokens[1]); - } - } - } - reader.close(); - - if (!stack.empty()) { - Assert.fail(); - } - } else { - Assert.fail("File does not exist"); - } - - Assert.assertEquals("10 processes didn't write", popped, 10); - } - - private void waitForProcess(Process process) throws InterruptedException { - if (process.waitFor() != 0) { - throw new RuntimeException(new BufferedReader(new InputStreamReader(process.getErrorStream())) - .lines().collect(Collectors.joining("\n"))); - } - } - - /* - * Class to be used for testing threads - * */ - class FileWriter implements Runnable { - - String threadName; - File file; - String lockfile; - Thread t; - - FileWriter(String threadName, String lockfile, String filename) { - this.threadName = threadName; - this.lockfile = lockfile; - this.file = new File(filename); - - t = new Thread(this, threadName); - t.start(); - } - - public void run() { - CacheLock lock = new CacheLock(lockfile); - try { - lock.lock(); - try { - if (!file.exists()) { - file.createNewFile(); - } - FileOutputStream os = new FileOutputStream(file, true); - - os.write(("< " + threadName + "\n").getBytes()); - Thread.sleep(1000); - os.write(("> " + threadName + "\n").getBytes()); - - os.close(); - } catch (Exception ex) { - - } - } catch (Exception ex) { - System.out.println("Couldn't obtain lock"); - } finally { - try { - lock.unlock(); - } catch (Exception ex) { - System.out.println("aljsdladsk"); - } - } - - - } - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java deleted file mode 100644 index 2af976acc872..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.microsoft.aad.msal4j.ClientCredentialFactory; -import com.microsoft.aad.msal4j.ClientCredentialParameters; -import com.microsoft.aad.msal4j.ConfidentialClientApplication; -import com.microsoft.aad.msal4j.IAuthenticationResult; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - -/* - * Before running these tests, log into Azure with the new Visual Studio 16.3.0 Preview 1 - * This should create a msal.cache file in the the user directory, and these tests should be able to read and - * write from the same file. - * Note that deleting this cache file will cause the user to have to re-log in with Visual Studio as this will delete - * the tokens in the cache - * - * NOTE: These tests are written assuming that nothing else has written to the MSAL cache besides visual studio - * */ -public class CrossProgramVSTest { - - CachePersister cachePersister; - PersistentTokenCacheAccessAspect accessAspect; - - private ConfidentialClientApplication confApp; - private ClientCredentialParameters confParameters; - - private int count = 0; - - @Before - public void setup() throws Exception { - org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); - //using the default cachepersister and accessAspect objects - cachePersister = new CachePersister.Builder().build(); - accessAspect = new PersistentTokenCacheAccessAspect(); - - confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, - ClientCredentialFactory.create(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - confParameters = ClientCredentialParameters.builder( - Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) - .build(); - } - - @Test - public void readCacheAfterVSAzureLogin() { - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.has("AccessToken")); - Assert.assertTrue(jsonObj.has("RefreshToken")); - Assert.assertTrue(jsonObj.has("IdToken")); - Assert.assertTrue(jsonObj.has("Account")); - Assert.assertTrue(jsonObj.has("AppMetadata")); - - System.out.println(currJson); - - count = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - } - - @Test - public void writeToSameCacheFileAfterVSAzureLogin() { - String currJson = new String(cachePersister.readCache()); - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - int set = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - - CompletableFuture result = confApp.acquireToken(confParameters); - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - currJson = new String(cachePersister.readCache()); - jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - int newSet = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - - Assert.assertEquals(newSet, set + 1); - count++; - - System.out.println(currJson); - } - - @Test - public void countCache() { - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - int newSet = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - System.out.println(newSet); - } - - @Test - public void readCacheAfterPowershellAzureLogin() { - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - System.out.println(currJson); - - int newSet = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - - Assert.assertEquals(newSet, 6); - count++; - } - -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java deleted file mode 100644 index 17dd249c7493..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import java.io.File; -import java.io.FileOutputStream; - -public class FileWriter { - - public static void main(String[] args) throws Exception { - File file; - String lockfile; - - if (args.length == 3) { - lockfile = args[1]; - file = new File(args[2]); - } else { - System.out.println("wrong number of args lol????"); - return; - } - CacheLock lock = new CacheLock(lockfile); - - int retries = 3; - boolean succeeded = false; - while (retries-- > 0 && !succeeded) { - try { - lock.lock(); - - if (!file.exists()) { - file.createNewFile(); - } - FileOutputStream os = new FileOutputStream(file, true); - - os.write(("< " + args[0] + "\n").getBytes()); - Thread.sleep(1000); - os.write(("> " + args[0] + "\n").getBytes()); - - os.close(); - succeeded = true; - } finally { - lock.unlock(); - } - } - - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java deleted file mode 100644 index 90193076612e..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; -import com.sun.jna.Platform; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; - -public class MsalCacheStorageTest { - - private CachePersister cachePersister; - private String cacheLocation; - - @Before - public void setup() throws Exception { - org.junit.Assume.assumeTrue(Platform.isWindows()); - cacheLocation = java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString(); - cachePersister = new CachePersister.Builder() - .cacheLocation(cacheLocation) - .lockfileLocation(cacheLocation + ".lockfile") - .build(); - } - - @Test - public void writesReadsCacheData() { - try { - File f = new File(cacheLocation); - - String testString = "hello world"; - - cachePersister.writeCache(testString.getBytes()); - String receivedString = new String(cachePersister.readCache()); - - Assert.assertEquals(receivedString, testString); - - cachePersister.deleteCache(); - } finally { - cachePersister.deleteCache(); - } - } - -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java deleted file mode 100644 index 9d347ae8edaf..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.microsoft.aad.msal4j.*; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -public class MultithreadedTokenCacheTest { - - private PersistentTokenCacheAccessAspect accessAspect; - private CachePersister cachePersister; - - private ConfidentialClientApplication confApp; - private ConfidentialClientApplication confApp2; - private PublicClientApplication pubApp; - private ClientCredentialParameters confParameters; - private DeviceCodeFlowParameters pubParameters; - - @Before - public void setup() throws Exception { - org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); - // custom MsalCacheStorage for testing purposes so we don't overwrite the real one - cachePersister = new CachePersister.Builder() - .cacheLocation(java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString()) - .build(); - - accessAspect = new PersistentTokenCacheAccessAspect(cachePersister); - - confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, - ClientCredentialFactory.create(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - confApp2 = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID_2, - ClientCredentialFactory.create(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET_2)) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - confParameters = ClientCredentialParameters.builder( - Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) - .build(); - - - pubApp = PublicClientApplication.builder(TestConfiguration.PUBLIC_CLIENT_ID) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> System.out.println(deviceCode.message()); - - pubParameters = DeviceCodeFlowParameters.builder( - Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE), - deviceCodeConsumer) - .build(); - } - - @After - public void cleanup() { - if (accessAspect != null) { - accessAspect.deleteCache(); - } - } - - @Test - public void twoThreadsWritingTokens() { - - ConcurrentClient a = new ConcurrentClient("conf"); - ConcurrentClient b = new ConcurrentClient("pub"); - - try { - a.t.join(); - b.t.join(); - } catch (Exception e) { - System.out.printf("Error with threads"); - } - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.get("AccessToken").getAsJsonObject().keySet().size() == 2); - Assert.assertTrue(jsonObj.get("RefreshToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("IdToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("Account").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("AppMetadata").getAsJsonObject().keySet().size() == 1); - - accessAspect.deleteCache(); - } - - @Test - public void tenThreadsWritingSameConfTokens() { - - ConcurrentClient a = new ConcurrentClient("conf"); - ConcurrentClient b = new ConcurrentClient("conf"); - ConcurrentClient c = new ConcurrentClient("conf"); - ConcurrentClient d = new ConcurrentClient("conf"); - ConcurrentClient e = new ConcurrentClient("conf"); - ConcurrentClient f = new ConcurrentClient("conf"); - ConcurrentClient g = new ConcurrentClient("conf"); - ConcurrentClient h = new ConcurrentClient("conf"); - ConcurrentClient i = new ConcurrentClient("conf"); - ConcurrentClient j = new ConcurrentClient("conf"); - - try { - a.t.join(); - b.t.join(); - c.t.join(); - d.t.join(); - e.t.join(); - f.t.join(); - g.t.join(); - h.t.join(); - i.t.join(); - j.t.join(); - } catch (Exception ex) { - System.out.printf("Error with threads"); - } - - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - - System.out.println("keys: " + jsonObj.get("AccessToken").getAsJsonObject().keySet().size()); - - Assert.assertTrue(jsonObj.get("AccessToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("RefreshToken").getAsJsonObject().keySet().size() == 0); - Assert.assertTrue(jsonObj.get("IdToken").getAsJsonObject().keySet().size() == 0); - Assert.assertTrue(jsonObj.get("Account").getAsJsonObject().keySet().size() == 0); - Assert.assertTrue(jsonObj.get("AppMetadata").getAsJsonObject().keySet().size() == 0); - - accessAspect.deleteCache(); - } - - class ConcurrentClient implements Runnable { - - String threadName; - Thread t; - - ConcurrentClient(String threadName) { - this.threadName = threadName; - t = new Thread(this, threadName); - t.start(); - } - - public void run() { - - if (threadName.equals("conf")) { - CompletableFuture result = confApp.acquireToken(confParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - } else if (threadName.equals("pub")) { - - CompletableFuture result = pubApp.acquireToken( - pubParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); - return "Unknown!"; - } - - return res; - - }).join(); - } - } - - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java deleted file mode 100644 index 2b78b6daae7b..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.microsoft.aad.msal4j.*; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -public class PersistentTokenCacheAccessAspectTest { - - private PersistentTokenCacheAccessAspect accessAspect; - private CachePersister cachePersister; - - private ConfidentialClientApplication confApp; - private ConfidentialClientApplication confApp2; - private PublicClientApplication pubApp; - private ClientCredentialParameters confParameters; - private DeviceCodeFlowParameters pubParameters; - - @Before - public void setup() throws Exception { - org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); - // custom MsalCacheStorage for testing purposes so we don't overwrite the real one - cachePersister = new CachePersister.Builder() - .cacheLocation(java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString()) - .build(); - - accessAspect = new PersistentTokenCacheAccessAspect(cachePersister); - - Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> { - System.out.println(deviceCode.message()); - }; - - confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, - ClientCredentialFactory.create(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - confApp2 = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID_2, - ClientCredentialFactory.create(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET_2)) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - pubApp = PublicClientApplication.builder(TestConfiguration.PUBLIC_CLIENT_ID) - .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) - .setTokenCacheAccessAspect(accessAspect) - .build(); - - confParameters = ClientCredentialParameters.builder( - Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) - .build(); - - pubParameters = DeviceCodeFlowParameters.builder( - Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE), - deviceCodeConsumer) - .build(); - } - - @After - public void cleanup() { - if (accessAspect != null) { - accessAspect.deleteCache(); - } - } - - @Test - public void checkIfWritesToFileFirstTimeConfidentialClient() { - - CompletableFuture result = confApp.acquireToken(confParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.has("AccessToken")); - Assert.assertTrue(jsonObj.has("RefreshToken")); - Assert.assertTrue(jsonObj.has("IdToken")); - Assert.assertTrue(jsonObj.has("Account")); - Assert.assertTrue(jsonObj.has("AppMetadata")); - - int set = jsonObj.get("AccessToken").getAsJsonObject().keySet().size(); - - Assert.assertEquals(set, 1); - - accessAspect.deleteCache(); - } - - @Test - public void checkIfWritesToFileFirstTimePublicClient() { - - CompletableFuture result = pubApp.acquireToken( - pubParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.has("AccessToken")); - Assert.assertTrue(jsonObj.has("RefreshToken")); - Assert.assertTrue(jsonObj.has("IdToken")); - Assert.assertTrue(jsonObj.has("Account")); - Assert.assertTrue(jsonObj.has("AppMetadata")); - - Assert.assertTrue(jsonObj.get("AccessToken").getAsJsonObject().keySet().size() == 1); - - accessAspect.deleteCache(); - } - - @Test - public void addsAccountToListPubClient() { - - CompletableFuture result = pubApp.acquireToken( - pubParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception - " + ex.getMessage()); - return "Unknown!"; - } - - return res; - - }).join(); - - Assert.assertEquals(pubApp.getAccounts().join().size(), 1); - - accessAspect.deleteCache(); - } - - @Test - public void writesTwoTokensToCache() { - CompletableFuture result = pubApp.acquireToken( - pubParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); - return "Unknown!"; - } - - return res; - - }).join(); - - CompletableFuture result2 = confApp.acquireToken(confParameters); - - result2.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.get("AccessToken").getAsJsonObject().keySet().size() == 2); - Assert.assertTrue(jsonObj.get("RefreshToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("IdToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("Account").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("AppMetadata").getAsJsonObject().keySet().size() == 1); - - accessAspect.deleteCache(); - } - - @Test - public void writesReadsMultipleTokensToCache() { - CompletableFuture result = pubApp.acquireToken( - pubParameters); - - result.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - CompletableFuture result2 = confApp.acquireToken(confParameters); - - result2.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - CompletableFuture result3 = confApp2.acquireToken(confParameters); - - result3.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 3 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - byte[] currJsonBytes = cachePersister.readCache(); - String currJson = new String(currJsonBytes); - - JsonObject jsonObj = new JsonParser().parse(currJson).getAsJsonObject(); - - Assert.assertTrue(jsonObj.get("AccessToken").getAsJsonObject().keySet().size() == 3); - Assert.assertTrue(jsonObj.get("RefreshToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("IdToken").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("Account").getAsJsonObject().keySet().size() == 1); - Assert.assertTrue(jsonObj.get("AppMetadata").getAsJsonObject().keySet().size() == 1); - - accessAspect.deleteCache(); - } - - @Test - public void syncsCacheWithExpiredTokens() { - CompletableFuture result3 = confApp2.acquireToken(confParameters); - - result3.handle((res, ex) -> { - if (ex != null) { - System.out.println("Oops! We have an exception 3 - " + ex.getMessage()); - return "Unknown!"; - } - return res; - - }).join(); - - accessAspect.deleteCache(); - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java deleted file mode 100644 index 8841df4f0557..000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.msalextensions; - -public class TestConfiguration { - - static final String TENANT_SPECIFIC_AUTHORITY = "https://login.microsoftonline.com/[insert here]/"; - - static final String PUBLIC_CLIENT_ID = ""; - - static final String GRAPH_DEFAULT_SCOPE = "https://graph.windows.net/.default"; - - static final String CONFIDENTIAL_CLIENT_ID = ""; - static final String CONFIDENTIAL_CLIENT_ID_2 = ""; - - static final String CONFIDENTIAL_CLIENT_SECRET = ""; - static final String CONFIDENTIAL_CLIENT_SECRET_2 = ""; -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/util/TestUtils.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/util/TestUtils.java index fdd42968b9a7..78545f83ab39 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/util/TestUtils.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/util/TestUtils.java @@ -5,7 +5,6 @@ import com.azure.core.credential.AccessToken; import com.azure.identity.implementation.MsalToken; -import com.microsoft.aad.msal4j.Account; import com.microsoft.aad.msal4j.IAccount; import com.microsoft.aad.msal4j.IAuthenticationResult; import reactor.core.publisher.Mono; @@ -39,7 +38,22 @@ public String idToken() { @Override public IAccount account() { - return new Account(UUID.randomUUID().toString(), "http://login.microsoftonline.com", "testuser"); + return new IAccount() { + @Override + public String homeAccountId() { + return UUID.randomUUID().toString(); + } + + @Override + public String environment() { + return "http://login.microsoftonline.com"; + } + + @Override + public String username() { + return "testuser"; + } + }; } @Override diff --git a/sdk/spring/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/AzureADGraphClient.java b/sdk/spring/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/AzureADGraphClient.java index 107f2f483b6a..500d96d3aa29 100644 --- a/sdk/spring/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/AzureADGraphClient.java +++ b/sdk/spring/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/AzureADGraphClient.java @@ -195,7 +195,7 @@ private boolean isValidUserGroupToGrantAuthority(final UserGroup group) { public IAuthenticationResult acquireTokenForGraphApi(String idToken, String tenantId) throws ServiceUnavailableException { - final IClientCredential clientCredential = ClientCredentialFactory.create(clientSecret); + final IClientCredential clientCredential = ClientCredentialFactory.createFromSecret(clientSecret); final UserAssertion assertion = new UserAssertion(idToken); IAuthenticationResult result = null; From bf5e73ebc03543ecf996729217b98ecb5d4ebb16 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 16:59:54 -0700 Subject: [PATCH 08/12] Migrate file cache tests --- .../msalextensions/CacheLockTest.java | 235 ++++++++++++++ .../msalextensions/CrossProgramVSTest.java | 136 ++++++++ .../msalextensions/FileWriter.java | 47 +++ .../msalextensions/MsalCacheStorageTest.java | 47 +++ .../MultithreadedTokenCacheTest.java | 224 +++++++++++++ .../PersistentTokenCacheAccessAspectTest.java | 302 ++++++++++++++++++ .../msalextensions/TestConfiguration.java | 19 ++ 7 files changed, 1010 insertions(+) create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java create mode 100644 sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java new file mode 100644 index 000000000000..f28d76a8aef3 --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CacheLockTest.java @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import com.sun.jna.Platform; +import org.junit.*; + +import java.io.*; +import java.util.Stack; +import java.util.stream.Collectors; + +public class CacheLockTest { + + private static String folder; + private static String testerFilename; + private static String lockfile; + + @BeforeClass + public static void setup() { + // get proper file paths + String currDir = System.getProperty("user.dir"); + String home = System.getProperty("user.home"); + + java.nio.file.Path classes = java.nio.file.Paths.get(currDir, "target", "classes"); + java.nio.file.Path tests = java.nio.file.Paths.get(currDir, "target", "test-classes"); + + testerFilename = java.nio.file.Paths.get(home, "tester.txt").toString(); + lockfile = java.nio.file.Paths.get(home, "testlock.lockfile").toString(); + + String delimiter = ":"; + if (Platform.isWindows()) { + delimiter = ";"; + } + folder = classes.toString() + delimiter + tests; + } + + @Test + public void tenThreadsWritingToFile() throws IOException { + + // make sure tester.json file doesn't already exist + File tester = new File(testerFilename); + tester.delete(); + + // delete the lock file just in case before starting + File lock = new File(lockfile); + lock.delete(); + + FileWriter a = new FileWriter("a", lockfile, testerFilename); + FileWriter b = new FileWriter("b", lockfile, testerFilename); + FileWriter c = new FileWriter("c", lockfile, testerFilename); + FileWriter d = new FileWriter("d", lockfile, testerFilename); + FileWriter e = new FileWriter("e", lockfile, testerFilename); + FileWriter f = new FileWriter("f", lockfile, testerFilename); + FileWriter g = new FileWriter("g", lockfile, testerFilename); + FileWriter h = new FileWriter("h", lockfile, testerFilename); + FileWriter i = new FileWriter("i", lockfile, testerFilename); + FileWriter j = new FileWriter("j", lockfile, testerFilename); + + try { + a.t.join(); + b.t.join(); + c.t.join(); + d.t.join(); + e.t.join(); + f.t.join(); + g.t.join(); + h.t.join(); + i.t.join(); + j.t.join(); + } catch (Exception ex) { + System.out.printf("Error with threads"); + } + + Stack stack = new Stack<>(); + int popped = 0; + + File file = new File(testerFilename); + + if (file.exists()) { + FileReader reader = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(reader); + StringBuffer stringBuffer = new StringBuffer(); + String line; + while ((line = bufferedReader.readLine()) != null) { + String[] tokens = line.split(" "); + if (tokens[0].equals("<")) { // enter + stack.push(tokens[1]); + } else if (tokens[0].equals(">")) { // exit + if (stack.peek().equals(tokens[1])) { + stack.pop(); + popped++; + } else { + System.out.println("messed up: " + tokens[1]); + } + } + } + reader.close(); + + if (!stack.empty()) { + Assert.fail(); + } + } else { + Assert.fail("File does not exist"); + } + + Assert.assertEquals("10 processes didn't write", popped, 10); + + } + + @Ignore("Run local only - CI does not support classpath well") + public void tenProcessesWritingToFile() throws IOException, InterruptedException { + // make sure tester.json file doesn't already exist + File tester = new File(testerFilename); + tester.delete(); + + // delete the lock file just in case before starting + File lock = new File(lockfile); + lock.delete(); + + String mainClass = com.azure.identity.implementation.msalextensions.FileWriter.class.getName(); + Process process1 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(1), lockfile, testerFilename}).start(); + Process process2 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(2), lockfile, testerFilename}).start(); + Process process3 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(3), lockfile, testerFilename}).start(); + Process process4 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(4), lockfile, testerFilename}).start(); + Process process5 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(5), lockfile, testerFilename}).start(); + Process process6 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(6), lockfile, testerFilename}).start(); + Process process7 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(7), lockfile, testerFilename}).start(); + Process process8 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(8), lockfile, testerFilename}).start(); + Process process9 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(9), lockfile, testerFilename}).start(); + Process process10 = new ProcessBuilder(new String[]{"java", "-cp", folder, mainClass, Integer.toString(10), lockfile, testerFilename}).start(); + + waitForProcess(process1); + waitForProcess(process2); + waitForProcess(process3); + waitForProcess(process4); + waitForProcess(process5); + waitForProcess(process6); + waitForProcess(process7); + waitForProcess(process8); + waitForProcess(process9); + waitForProcess(process10); + + Stack stack = new Stack<>(); + int popped = 0; + + File file = new File(testerFilename); + if (file.exists()) { + FileReader reader = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(reader); + StringBuffer stringBuffer = new StringBuffer(); + String line; + while ((line = bufferedReader.readLine()) != null) { + String[] tokens = line.split(" "); + if (tokens[0].equals("<")) { // enter + stack.push(tokens[1]); + } else if (tokens[0].equals(">")) { // exit + if (stack.peek().equals(tokens[1])) { + stack.pop(); + popped++; + } else { + System.out.println("messed up: " + tokens[1]); + } + } + } + reader.close(); + + if (!stack.empty()) { + Assert.fail(); + } + } else { + Assert.fail("File does not exist"); + } + + Assert.assertEquals("10 processes didn't write", popped, 10); + } + + private void waitForProcess(Process process) throws InterruptedException { + if (process.waitFor() != 0) { + throw new RuntimeException(new BufferedReader(new InputStreamReader(process.getErrorStream())) + .lines().collect(Collectors.joining("\n"))); + } + } + + /* + * Class to be used for testing threads + * */ + class FileWriter implements Runnable { + + String threadName; + File file; + String lockfile; + Thread t; + + FileWriter(String threadName, String lockfile, String filename) { + this.threadName = threadName; + this.lockfile = lockfile; + this.file = new File(filename); + + t = new Thread(this, threadName); + t.start(); + } + + public void run() { + CacheLock lock = new CacheLock(lockfile); + try { + lock.lock(); + try { + if (!file.exists()) { + file.createNewFile(); + } + FileOutputStream os = new FileOutputStream(file, true); + + os.write(("< " + threadName + "\n").getBytes()); + Thread.sleep(1000); + os.write(("> " + threadName + "\n").getBytes()); + + os.close(); + } catch (Exception ex) { + + } + } catch (Exception ex) { + System.out.println("Couldn't obtain lock"); + } finally { + try { + lock.unlock(); + } catch (Exception ex) { + System.out.println("aljsdladsk"); + } + } + + + } + } +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java new file mode 100644 index 000000000000..e6dd0adefec1 --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/CrossProgramVSTest.java @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; +import com.azure.core.util.serializer.SerializerEncoding; +import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; +import com.microsoft.aad.msal4j.ClientCredentialFactory; +import com.microsoft.aad.msal4j.ClientCredentialParameters; +import com.microsoft.aad.msal4j.ConfidentialClientApplication; +import com.microsoft.aad.msal4j.IAuthenticationResult; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/* + * Before running these tests, log into Azure with the new Visual Studio 16.3.0 Preview 1 + * This should create a msal.cache file in the the user directory, and these tests should be able to read and + * write from the same file. + * Note that deleting this cache file will cause the user to have to re-log in with Visual Studio as this will delete + * the tokens in the cache + * + * NOTE: These tests are written assuming that nothing else has written to the MSAL cache besides visual studio + * */ +public class CrossProgramVSTest { + + CachePersister cachePersister; + PersistentTokenCacheAccessAspect accessAspect; + + private ConfidentialClientApplication confApp; + private ClientCredentialParameters confParameters; + + private int count = 0; + + private final SerializerAdapter serializerAdapter = JacksonAdapter.createDefaultSerializerAdapter(); + + @Before + public void setup() throws Exception { + org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); + //using the default cachepersister and accessAspect objects + cachePersister = new CachePersister.Builder().build(); + accessAspect = new PersistentTokenCacheAccessAspect(); + + confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, + ClientCredentialFactory.createFromSecret(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + confParameters = ClientCredentialParameters.builder( + Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) + .build(); + } + + @Test + public void readCacheAfterVSAzureLogin() throws Exception { + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + + Assert.assertTrue(jsonObj.containsKey("AccessToken")); + Assert.assertTrue(jsonObj.containsKey("RefreshToken")); + Assert.assertTrue(jsonObj.containsKey("IdToken")); + Assert.assertTrue(jsonObj.containsKey("Account")); + Assert.assertTrue(jsonObj.containsKey("AppMetadata")); + + System.out.println(currJson); + } + + @Test + public void writeToSameCacheFileAfterVSAzureLogin() throws Exception { + String currJson = new String(cachePersister.readCache()); + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + int set = accessTokenObj.size(); + + CompletableFuture result = confApp.acquireToken(confParameters); + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + currJson = new String(cachePersister.readCache()); + jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + int newSet = accessTokenObj.size(); + + Assert.assertEquals(newSet, set + 1); + count++; + + System.out.println(currJson); + } + + @Test + public void countCache() throws Exception { + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + int newSet = accessTokenObj.size(); + System.out.println(newSet); + } + + @Test + public void readCacheAfterPowershellAzureLogin() throws Exception { + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + System.out.println(currJson); + + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + int newSet = accessTokenObj.size(); + + Assert.assertEquals(newSet, 6); + count++; + } + +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java new file mode 100644 index 000000000000..17dd249c7493 --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/FileWriter.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import java.io.File; +import java.io.FileOutputStream; + +public class FileWriter { + + public static void main(String[] args) throws Exception { + File file; + String lockfile; + + if (args.length == 3) { + lockfile = args[1]; + file = new File(args[2]); + } else { + System.out.println("wrong number of args lol????"); + return; + } + CacheLock lock = new CacheLock(lockfile); + + int retries = 3; + boolean succeeded = false; + while (retries-- > 0 && !succeeded) { + try { + lock.lock(); + + if (!file.exists()) { + file.createNewFile(); + } + FileOutputStream os = new FileOutputStream(file, true); + + os.write(("< " + args[0] + "\n").getBytes()); + Thread.sleep(1000); + os.write(("> " + args[0] + "\n").getBytes()); + + os.close(); + succeeded = true; + } finally { + lock.unlock(); + } + } + + } +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java new file mode 100644 index 000000000000..90193076612e --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MsalCacheStorageTest.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; +import com.sun.jna.Platform; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +public class MsalCacheStorageTest { + + private CachePersister cachePersister; + private String cacheLocation; + + @Before + public void setup() throws Exception { + org.junit.Assume.assumeTrue(Platform.isWindows()); + cacheLocation = java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString(); + cachePersister = new CachePersister.Builder() + .cacheLocation(cacheLocation) + .lockfileLocation(cacheLocation + ".lockfile") + .build(); + } + + @Test + public void writesReadsCacheData() { + try { + File f = new File(cacheLocation); + + String testString = "hello world"; + + cachePersister.writeCache(testString.getBytes()); + String receivedString = new String(cachePersister.readCache()); + + Assert.assertEquals(receivedString, testString); + + cachePersister.deleteCache(); + } finally { + cachePersister.deleteCache(); + } + } + +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java new file mode 100644 index 000000000000..01ed02b6c032 --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/MultithreadedTokenCacheTest.java @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; +import com.azure.core.util.serializer.SerializerEncoding; +import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; +import com.microsoft.aad.msal4j.ClientCredentialFactory; +import com.microsoft.aad.msal4j.ClientCredentialParameters; +import com.microsoft.aad.msal4j.ConfidentialClientApplication; +import com.microsoft.aad.msal4j.DeviceCode; +import com.microsoft.aad.msal4j.DeviceCodeFlowParameters; +import com.microsoft.aad.msal4j.IAuthenticationResult; +import com.microsoft.aad.msal4j.PublicClientApplication; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class MultithreadedTokenCacheTest { + private final SerializerAdapter serializerAdapter = JacksonAdapter.createDefaultSerializerAdapter(); + + private PersistentTokenCacheAccessAspect accessAspect; + private CachePersister cachePersister; + + private ConfidentialClientApplication confApp; + private ConfidentialClientApplication confApp2; + private PublicClientApplication pubApp; + private ClientCredentialParameters confParameters; + private DeviceCodeFlowParameters pubParameters; + + @Before + public void setup() throws Exception { + org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); + // custom MsalCacheStorage for testing purposes so we don't overwrite the real one + cachePersister = new CachePersister.Builder() + .cacheLocation(java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString()) + .build(); + + accessAspect = new PersistentTokenCacheAccessAspect(cachePersister); + + confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, + ClientCredentialFactory.createFromSecret(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + confApp2 = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID_2, + ClientCredentialFactory.createFromSecret(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET_2)) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + confParameters = ClientCredentialParameters.builder( + Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) + .build(); + + + pubApp = PublicClientApplication.builder(TestConfiguration.PUBLIC_CLIENT_ID) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> System.out.println(deviceCode.message()); + + pubParameters = DeviceCodeFlowParameters.builder( + Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE), + deviceCodeConsumer) + .build(); + } + + @After + public void cleanup() { + if (accessAspect != null) { + accessAspect.deleteCache(); + } + } + + @Test + public void twoThreadsWritingTokens() throws Exception { + + ConcurrentClient a = new ConcurrentClient("conf"); + ConcurrentClient b = new ConcurrentClient("pub"); + + try { + a.t.join(); + b.t.join(); + } catch (Exception e) { + System.out.printf("Error with threads"); + } + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map refreshTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("RefreshToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map idTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("IdToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map accountObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("Account"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map appMetadataObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AppMetadata"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + + Assert.assertEquals(2, accessTokenObj.size()); + Assert.assertEquals(1, refreshTokenObj.size()); + Assert.assertEquals(1, idTokenObj.size()); + Assert.assertEquals(1, accountObj.size()); + Assert.assertEquals(1, appMetadataObj.size()); + + accessAspect.deleteCache(); + } + + @Test + public void tenThreadsWritingSameConfTokens() throws Exception { + + ConcurrentClient a = new ConcurrentClient("conf"); + ConcurrentClient b = new ConcurrentClient("conf"); + ConcurrentClient c = new ConcurrentClient("conf"); + ConcurrentClient d = new ConcurrentClient("conf"); + ConcurrentClient e = new ConcurrentClient("conf"); + ConcurrentClient f = new ConcurrentClient("conf"); + ConcurrentClient g = new ConcurrentClient("conf"); + ConcurrentClient h = new ConcurrentClient("conf"); + ConcurrentClient i = new ConcurrentClient("conf"); + ConcurrentClient j = new ConcurrentClient("conf"); + + try { + a.t.join(); + b.t.join(); + c.t.join(); + d.t.join(); + e.t.join(); + f.t.join(); + g.t.join(); + h.t.join(); + i.t.join(); + j.t.join(); + } catch (Exception ex) { + System.out.printf("Error with threads"); + } + + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + System.out.println("keys: " + accessTokenObj.size()); + + Map refreshTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("RefreshToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map idTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("IdToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map accountObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("Account"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map appMetadataObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AppMetadata"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + + Assert.assertEquals(1, accessTokenObj.size()); + Assert.assertEquals(0, refreshTokenObj.size()); + Assert.assertEquals(0, idTokenObj.size()); + Assert.assertEquals(0, accountObj.size()); + Assert.assertEquals(0, appMetadataObj.size()); + + accessAspect.deleteCache(); + } + + class ConcurrentClient implements Runnable { + + String threadName; + Thread t; + + ConcurrentClient(String threadName) { + this.threadName = threadName; + t = new Thread(this, threadName); + t.start(); + } + + public void run() { + + if (threadName.equals("conf")) { + CompletableFuture result = confApp.acquireToken(confParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + } else if (threadName.equals("pub")) { + + CompletableFuture result = pubApp.acquireToken( + pubParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); + return "Unknown!"; + } + + return res; + + }).join(); + } + } + + } +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java new file mode 100644 index 000000000000..bcdc0cde978d --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/PersistentTokenCacheAccessAspectTest.java @@ -0,0 +1,302 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; +import com.azure.core.util.serializer.SerializerEncoding; +import com.azure.identity.implementation.msalextensions.cachepersister.CachePersister; +import com.microsoft.aad.msal4j.ClientCredentialFactory; +import com.microsoft.aad.msal4j.ClientCredentialParameters; +import com.microsoft.aad.msal4j.ConfidentialClientApplication; +import com.microsoft.aad.msal4j.DeviceCode; +import com.microsoft.aad.msal4j.DeviceCodeFlowParameters; +import com.microsoft.aad.msal4j.IAuthenticationResult; +import com.microsoft.aad.msal4j.PublicClientApplication; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class PersistentTokenCacheAccessAspectTest { + private final SerializerAdapter serializerAdapter = JacksonAdapter.createDefaultSerializerAdapter(); + + private PersistentTokenCacheAccessAspect accessAspect; + private CachePersister cachePersister; + + private ConfidentialClientApplication confApp; + private ConfidentialClientApplication confApp2; + private PublicClientApplication pubApp; + private ClientCredentialParameters confParameters; + private DeviceCodeFlowParameters pubParameters; + + @Before + public void setup() throws Exception { + org.junit.Assume.assumeTrue("Skipping these tests until we mock or record it", false); + // custom MsalCacheStorage for testing purposes so we don't overwrite the real one + cachePersister = new CachePersister.Builder() + .cacheLocation(java.nio.file.Paths.get(System.getProperty("user.home"), "test.cache").toString()) + .build(); + + accessAspect = new PersistentTokenCacheAccessAspect(cachePersister); + + Consumer deviceCodeConsumer = (DeviceCode deviceCode) -> { + System.out.println(deviceCode.message()); + }; + + confApp = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID, + ClientCredentialFactory.createFromSecret(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET)) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + confApp2 = ConfidentialClientApplication.builder(TestConfiguration.CONFIDENTIAL_CLIENT_ID_2, + ClientCredentialFactory.createFromSecret(TestConfiguration.CONFIDENTIAL_CLIENT_SECRET_2)) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + pubApp = PublicClientApplication.builder(TestConfiguration.PUBLIC_CLIENT_ID) + .authority(TestConfiguration.TENANT_SPECIFIC_AUTHORITY) + .setTokenCacheAccessAspect(accessAspect) + .build(); + + confParameters = ClientCredentialParameters.builder( + Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE)) + .build(); + + pubParameters = DeviceCodeFlowParameters.builder( + Collections.singleton(TestConfiguration.GRAPH_DEFAULT_SCOPE), + deviceCodeConsumer) + .build(); + } + + @After + public void cleanup() { + if (accessAspect != null) { + accessAspect.deleteCache(); + } + } + + @Test + public void checkIfWritesToFileFirstTimeConfidentialClient() throws Exception { + + CompletableFuture result = confApp.acquireToken(confParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + + Assert.assertTrue(jsonObj.containsKey("AccessToken")); + Assert.assertTrue(jsonObj.containsKey("RefreshToken")); + Assert.assertTrue(jsonObj.containsKey("IdToken")); + Assert.assertTrue(jsonObj.containsKey("Account")); + Assert.assertTrue(jsonObj.containsKey("AppMetadata")); + + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + Assert.assertEquals(1, accessTokenObj.size()); + + accessAspect.deleteCache(); + } + + @Test + public void checkIfWritesToFileFirstTimePublicClient() throws Exception { + + CompletableFuture result = pubApp.acquireToken( + pubParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + + Assert.assertTrue(jsonObj.containsKey("AccessToken")); + Assert.assertTrue(jsonObj.containsKey("RefreshToken")); + Assert.assertTrue(jsonObj.containsKey("IdToken")); + Assert.assertTrue(jsonObj.containsKey("Account")); + Assert.assertTrue(jsonObj.containsKey("AppMetadata")); + + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + Assert.assertEquals(1, accessTokenObj.size()); + + accessAspect.deleteCache(); + } + + @Test + public void addsAccountToListPubClient() { + + CompletableFuture result = pubApp.acquireToken( + pubParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception - " + ex.getMessage()); + return "Unknown!"; + } + + return res; + + }).join(); + + Assert.assertEquals(pubApp.getAccounts().join().size(), 1); + + accessAspect.deleteCache(); + } + + @Test + public void writesTwoTokensToCache() throws Exception { + CompletableFuture result = pubApp.acquireToken( + pubParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); + return "Unknown!"; + } + + return res; + + }).join(); + + CompletableFuture result2 = confApp.acquireToken(confParameters); + + result2.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map refreshTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("RefreshToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map idTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("IdToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map accountObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("Account"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map appMetadataObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AppMetadata"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + + Assert.assertEquals(2, accessTokenObj.size()); + Assert.assertEquals(1, refreshTokenObj.size()); + Assert.assertEquals(1, idTokenObj.size()); + Assert.assertEquals(1, accountObj.size()); + Assert.assertEquals(1, appMetadataObj.size()); + + accessAspect.deleteCache(); + } + + @Test + public void writesReadsMultipleTokensToCache() throws Exception { + CompletableFuture result = pubApp.acquireToken( + pubParameters); + + result.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 1 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + CompletableFuture result2 = confApp.acquireToken(confParameters); + + result2.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 2 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + CompletableFuture result3 = confApp2.acquireToken(confParameters); + + result3.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 3 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + byte[] currJsonBytes = cachePersister.readCache(); + String currJson = new String(currJsonBytes); + + Map jsonObj = serializerAdapter.deserialize(currJson, Map.class, SerializerEncoding.JSON); + Map accessTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AccessToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map refreshTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("RefreshToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map idTokenObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("IdToken"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map accountObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("Account"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + Map appMetadataObj = serializerAdapter.deserialize( + serializerAdapter.serialize(jsonObj.get("AppMetadata"), SerializerEncoding.JSON), Map.class, SerializerEncoding.JSON); + + + Assert.assertEquals(3, accessTokenObj.size()); + Assert.assertEquals(1, refreshTokenObj.size()); + Assert.assertEquals(1, idTokenObj.size()); + Assert.assertEquals(1, accountObj.size()); + Assert.assertEquals(1, appMetadataObj.size()); + + accessAspect.deleteCache(); + } + + @Test + public void syncsCacheWithExpiredTokens() { + CompletableFuture result3 = confApp2.acquireToken(confParameters); + + result3.handle((res, ex) -> { + if (ex != null) { + System.out.println("Oops! We have an exception 3 - " + ex.getMessage()); + return "Unknown!"; + } + return res; + + }).join(); + + accessAspect.deleteCache(); + } +} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java new file mode 100644 index 000000000000..8841df4f0557 --- /dev/null +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/msalextensions/TestConfiguration.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity.implementation.msalextensions; + +public class TestConfiguration { + + static final String TENANT_SPECIFIC_AUTHORITY = "https://login.microsoftonline.com/[insert here]/"; + + static final String PUBLIC_CLIENT_ID = ""; + + static final String GRAPH_DEFAULT_SCOPE = "https://graph.windows.net/.default"; + + static final String CONFIDENTIAL_CLIENT_ID = ""; + static final String CONFIDENTIAL_CLIENT_ID_2 = ""; + + static final String CONFIDENTIAL_CLIENT_SECRET = ""; + static final String CONFIDENTIAL_CLIENT_SECRET_2 = ""; +} From f997e7b0e9b9050981268b73c66ea593ee6104f2 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 17:50:02 -0700 Subject: [PATCH 09/12] Fix eventhubs test and add change log --- .../azure/eventhubs/sendrecv/MsalTest.java | 19 +++++++++---------- sdk/identity/azure-identity/CHANGELOG.md | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sdk/eventhubs/microsoft-azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/MsalTest.java b/sdk/eventhubs/microsoft-azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/MsalTest.java index 6e9db81aeb3f..ac8435634cf8 100644 --- a/sdk/eventhubs/microsoft-azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/MsalTest.java +++ b/sdk/eventhubs/microsoft-azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/MsalTest.java @@ -5,7 +5,6 @@ import com.microsoft.aad.msal4j.ClientCredentialFactory; import com.microsoft.aad.msal4j.ClientCredentialParameters; -import com.microsoft.aad.msal4j.ClientSecret; import com.microsoft.aad.msal4j.ConfidentialClientApplication; import com.microsoft.aad.msal4j.IAuthenticationResult; import com.microsoft.azure.eventhubs.AzureActiveDirectoryTokenProvider; @@ -18,7 +17,7 @@ //import org.junit.Test; /** - * These JUnit test cases are all commented out by default because they can only be run with special setup. + * These JUnit test cases are all commented out by default because they can only be run with special setup. * They extract the namespace (endpoint) and event hub name from the connection string in the environment variable * which all test cases use, but they assume that the namespace (or event hub) has been set up with special permissions. * Within the AAD directory indicated by "authority", there is a registered application with id "clientId" and a secret @@ -29,7 +28,7 @@ public class MsalTest extends AadBase { private final String authority = "https://login.windows.net/replaceWithTenantIdGuid"; private final String clientId = "replaceWithClientIdGuid"; private final String clientSecret = "replaceWithClientSecret"; - + //@Test public void runSendReceiveWithAuthCallbackTest() throws Exception { final AuthCallback callback = new AuthCallback(this.clientId, this.clientSecret); @@ -38,7 +37,7 @@ public void runSendReceiveWithAuthCallbackTest() throws Exception { innerTest(ehc); } - + //@Test public void runSendReceiveWithAADTokenProvider() throws Exception { final AuthCallback callback = new AuthCallback(this.clientId, this.clientSecret); @@ -46,26 +45,26 @@ public void runSendReceiveWithAADTokenProvider() throws Exception { new AzureActiveDirectoryTokenProvider(callback, this.authority, null); final EventHubClient ehc = EventHubClient.createWithTokenProvider(MsalTest.endpoint, MsalTest.eventHubName, aadTokenProvider, this.executorService, null).get(); - + innerTest(ehc); } - + //@Test public void runSendReceiveWithCustomTokenProvider() throws Exception { final CustomTokenProvider tokenProvider = new CustomTokenProvider(this.authority, this.clientId, this.clientSecret); final EventHubClient ehc = EventHubClient.createWithTokenProvider(MsalTest.endpoint, MsalTest.eventHubName, tokenProvider, this.executorService, null).get(); - + innerTest(ehc); } - + @Override String tokenGet(final String authority, final String clientId, final String clientSecret, final String audience, final String extra) throws MalformedURLException, InterruptedException, ExecutionException { - ConfidentialClientApplication app = ConfidentialClientApplication.builder(clientId, new ClientSecret(clientSecret)) + ConfidentialClientApplication app = ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(clientSecret)) .authority(authority) .build(); - + ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton(audience + extra)).build(); IAuthenticationResult result = app.acquireToken(parameters).get(); diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index e18eca60e91c..cd2f8870c8a3 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,7 +1,7 @@ # Release History -## 1.1.0-beta.1 (Unreleased) - +## 1.0.9 (2020-07-15) +- Upgraded `msal4j` dependency to 1.6.1 ## 1.0.8 (2020-07-06) - Upgraded `azure-core` dependency to 1.6.0 From f20743b39d5db0bdb7e84d431db57c2adcdd1cbc Mon Sep 17 00:00:00 2001 From: Gauri Prasad <51212198+gapra-msft@users.noreply.github.com> Date: Wed, 8 Jul 2020 12:21:20 -0700 Subject: [PATCH 10/12] Ignored flaky CF tests (#12915) --- .../azure/storage/blob/changefeed/ChangefeedNetworkTest.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/storage/azure-storage-blob-changefeed/src/test/java/com/azure/storage/blob/changefeed/ChangefeedNetworkTest.groovy b/sdk/storage/azure-storage-blob-changefeed/src/test/java/com/azure/storage/blob/changefeed/ChangefeedNetworkTest.groovy index 8445bd10aa58..fcdea2d5b68b 100644 --- a/sdk/storage/azure-storage-blob-changefeed/src/test/java/com/azure/storage/blob/changefeed/ChangefeedNetworkTest.groovy +++ b/sdk/storage/azure-storage-blob-changefeed/src/test/java/com/azure/storage/blob/changefeed/ChangefeedNetworkTest.groovy @@ -1,5 +1,6 @@ package com.azure.storage.blob.changefeed +import spock.lang.Ignore import reactor.test.StepVerifier import spock.lang.Requires import spock.lang.Unroll @@ -73,6 +74,7 @@ class ChangefeedNetworkTest extends APISpec { @Unroll @Requires( { playbackMode() }) + @Ignore("flaky in CI") def "get continuationToken"() { when: BlobChangefeedPagedIterable iterable = new BlobChangefeedClientBuilder(primaryBlobServiceClient) @@ -101,6 +103,7 @@ class ChangefeedNetworkTest extends APISpec { @Unroll @Requires( { playbackMode() }) + @Ignore("flaky in CI") def "resume continuationToken"() { when: BlobChangefeedPagedFlux flux = new BlobChangefeedClientBuilder(primaryBlobServiceAsyncClient) From c2a4c19d90755556dbbb5740ffb73e7740a976e6 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 15 Jul 2020 21:46:28 -0700 Subject: [PATCH 11/12] Sync with master eng/common --- .../TestResources/deploy-test-resources.yml | 2 +- eng/common/Update-Change-Log.ps1 | 36 +++++---- .../templates/steps/create-pull-request.yml | 16 ++++ .../steps/daily-dev-build-variable.yml | 12 +++ .../templates/steps/docs-metadata-release.yml | 4 + .../templates/steps/get-pr-owners.yml | 46 +++++++++++ .../templates/steps/verify-links.yml | 4 +- eng/common/scripts/Submit-PullRequest.ps1 | 6 ++ eng/common/scripts/Verify-ChangeLog.ps1 | 53 ++++++++----- .../scripts/add-pullrequest-reviewers.ps1 | 79 +++++++++++++++++++ eng/common/scripts/get-codeowners.ps1 | 40 ++++++++++ .../scripts/modules/ChangeLog-Operations.psm1 | 51 +++++++----- .../scripts/modules/Package-Properties.psm1 | 50 +++++++++--- 13 files changed, 332 insertions(+), 67 deletions(-) create mode 100644 eng/common/pipelines/templates/steps/daily-dev-build-variable.yml create mode 100644 eng/common/pipelines/templates/steps/get-pr-owners.yml create mode 100644 eng/common/scripts/add-pullrequest-reviewers.ps1 create mode 100644 eng/common/scripts/get-codeowners.ps1 diff --git a/eng/common/TestResources/deploy-test-resources.yml b/eng/common/TestResources/deploy-test-resources.yml index b580d73f1406..b875a806b143 100644 --- a/eng/common/TestResources/deploy-test-resources.yml +++ b/eng/common/TestResources/deploy-test-resources.yml @@ -13,7 +13,7 @@ parameters: # "TestApplicationId": "", # "TestApplicationSecret": "", # "ProvisionerApplicationId": "", -# "ProvisoinerApplicationSecret": "", +# "ProvisionerApplicationSecret": "", # "Environment": "AzureCloud | AzureGov | AzureChina | " # } diff --git a/eng/common/Update-Change-Log.ps1 b/eng/common/Update-Change-Log.ps1 index d50316f223b7..a819a05e8bb2 100644 --- a/eng/common/Update-Change-Log.ps1 +++ b/eng/common/Update-Change-Log.ps1 @@ -27,10 +27,10 @@ function Get-ChangelogPath($Path) { # Check if CHANGELOG.md is present in path $ChangeLogPath = Join-Path -Path $Path -ChildPath "CHANGELOG.md" - if ((Test-Path -Path $ChangeLogPath) -eq $False){ + if ((Test-Path -Path $ChangeLogPath) -eq $False) { # Check if change log exists with name HISTORY.md $ChangeLogPath = Join-Path -Path $Path -ChildPath "HISTORY.md" - if ((Test-Path -Path $ChangeLogPath) -eq $False){ + if ((Test-Path -Path $ChangeLogPath) -eq $False) { Write-Host "Change log is not found in path[$Path]" exit(1) } @@ -45,7 +45,7 @@ function Get-VersionTitle($Version, $Unreleased) { # Generate version title $newVersionTitle = "## $Version $UNRELEASED_TAG" - if ($Unreleased -eq $False){ + if ($Unreleased -eq $False) { $releaseDate = Get-Date -Format "(yyyy-MM-dd)" $newVersionTitle = "## $Version $releaseDate" } @@ -67,10 +67,10 @@ function Get-NewChangeLog( [System.Collections.ArrayList]$ChangelogLines, $Versi # Version increment tool passes replaceversion as False and Unreleased as True $is_version_increment = $ReplaceVersion -eq $False -and $Unreleased -eq $True - for(; $Index -lt $ChangelogLines.Count; $Index++){ - if (Version-Matches($ChangelogLines[$Index])){ + for (; $Index -lt $ChangelogLines.Count; $Index++) { + if (Version-Matches($ChangelogLines[$Index])) { # Find current title in change log - if( -not $CurrentTitle){ + if( -not $CurrentTitle) { $CurrentTitle = $ChangelogLines[$Index] $CurrentIndex = $Index Write-Host "Current Version title: $CurrentTitle" @@ -80,7 +80,7 @@ function Get-NewChangeLog( [System.Collections.ArrayList]$ChangelogLines, $Versi # update change log script is triggered for all packages with current version for Java ( or any language where version is maintained in common file) # and this can cause an issue if someone changes changelog manually to prepare for release without updating actual version in central version file # Do not add new line or replace existing title when version is already present and script is triggered to add new line - if ($is_version_increment -and $ChangelogLines[$Index].Contains($Version)){ + if ($is_version_increment -and $ChangelogLines[$Index].Contains($Version)) { Write-Host "Version is already present in change log." exit(0) } @@ -90,26 +90,24 @@ function Get-NewChangeLog( [System.Collections.ArrayList]$ChangelogLines, $Versi # Generate version title $newVersionTitle = Get-VersionTitle -Version $Version -Unreleased $Unreleased - if( $newVersionTitle -eq $CurrentTitle){ + if( $newVersionTitle -eq $CurrentTitle) { Write-Host "No change is required in change log. Version is already present." exit(0) } - - - if (($ReplaceVersion -eq $True) -and ($Unreleased -eq $False) -and (-not $CurrentTitle.Contains($UNRELEASED_TAG))){ + if (($ReplaceVersion -eq $True) -and ($Unreleased -eq $False) -and $CurrentTitle.Contains($version) -and (-not $CurrentTitle.Contains($UNRELEASED_TAG))) { Write-Host "Version is already present in change log with a release date." exit(0) } # if current version title already has new version then we should replace title to update it - if ($CurrentTitle.Contains($Version) -and $ReplaceVersion -eq $False){ + if ($CurrentTitle.Contains($Version) -and $ReplaceVersion -eq $False) { Write-Host "Version is already present in title. Updating version title" $ReplaceVersion = $True } # if version is already found and not replacing then nothing to do - if ($ReplaceVersion -eq $False){ + if ($ReplaceVersion -eq $False) { Write-Host "Adding version title $newVersionTitle" $ChangelogLines.insert($CurrentIndex, "") $ChangelogLines.insert($CurrentIndex, "") @@ -121,24 +119,28 @@ function Get-NewChangeLog( [System.Collections.ArrayList]$ChangelogLines, $Versi $ChangelogLines[$CurrentIndex] = $newVersionTitle } - return $ChangelogLines + return $ChangelogLines } # Make sure path is valid -if ((Test-Path -Path $ChangeLogPath) -eq $False){ +if ((Test-Path -Path $ChangeLogPath) -eq $False) { Write-Host "Change log path is invalid. [$ChangeLogPath]" exit(1) } # probe change log path if path is directory -if (Test-Path -Path $ChangeLogPath -PathType Container) -{ +if (Test-Path -Path $ChangeLogPath -PathType Container) { $ChangeLogPath = Get-ChangelogPath -Path $ChangeLogPath } # Read current change logs and add/update version $ChangelogLines = [System.Collections.ArrayList](Get-Content -Path $ChangeLogPath) + +if ($null -eq $ChangelogLines) { + $ChangelogLines = @() +} + $NewContents = Get-NewChangeLog -ChangelogLines $ChangelogLines -Version $Version -Unreleased $Unreleased -ReplaceVersion $ReplaceVersion Write-Host "Writing change log to file [$ChangeLogPath]" diff --git a/eng/common/pipelines/templates/steps/create-pull-request.yml b/eng/common/pipelines/templates/steps/create-pull-request.yml index 790de92bcbe5..ce0680ff8f99 100644 --- a/eng/common/pipelines/templates/steps/create-pull-request.yml +++ b/eng/common/pipelines/templates/steps/create-pull-request.yml @@ -12,6 +12,8 @@ parameters: WorkingDirectory: $(System.DefaultWorkingDirectory) PRTitle: not-specified ScriptDirectory: eng/common/scripts + GHReviewersVariable: '' + GHTeamReviewersVariable: '' steps: @@ -63,3 +65,17 @@ steps: -PRBranch "${{ parameters.PRBranchName }}" -AuthToken "$(azuresdk-github-pat)" -PRTitle "${{ parameters.PRTitle }}" + +- task: PowerShell@2 + displayName: Tag a Reviewer on PR + inputs: + pwsh: true + workingDirectory: ${{ parameters.WorkingDirectory }} + filePath: ${{ parameters.ScriptDirectory }}/add-pullrequest-reviewers.ps1 + arguments: > + -RepoOwner "${{ parameters.RepoOwner }}" + -RepoName "${{ parameters.RepoName }}" + -AuthToken "$(azuresdk-github-pat)" + -GitHubUsers "$(${{ parameters.GHReviewersVariable }})" + -GitHubTeams "$(${{ parameters.GHTeamReviewersVariable }})" + -PRNumber "$(Submitted.PullRequest.Number)" diff --git a/eng/common/pipelines/templates/steps/daily-dev-build-variable.yml b/eng/common/pipelines/templates/steps/daily-dev-build-variable.yml new file mode 100644 index 000000000000..2e10f695c998 --- /dev/null +++ b/eng/common/pipelines/templates/steps/daily-dev-build-variable.yml @@ -0,0 +1,12 @@ +# This script fragment is used across our repos to set a variable "SetDevVersion" which +# is used when this pipeline is going to be generating and publishing daily dev builds. + +steps: +- pwsh: | + $setDailyDevBuild = "false" + if (('$(Build.Reason)' -eq 'Schedule') -and ('$(System.TeamProject)' -eq 'internal')) { + $setDailyDevBuild = "true" + } + echo "##vso[task.setvariable variable=SetDevVersion]$setDailyDevBuild" + displayName: "Setup Versioning Properties" + condition: eq(variables['SetDevVersion'], '') diff --git a/eng/common/pipelines/templates/steps/docs-metadata-release.yml b/eng/common/pipelines/templates/steps/docs-metadata-release.yml index 6ff9f84ff3ee..a9ff8c4e17b4 100644 --- a/eng/common/pipelines/templates/steps/docs-metadata-release.yml +++ b/eng/common/pipelines/templates/steps/docs-metadata-release.yml @@ -12,6 +12,8 @@ parameters: ArtifactName: '' Language: '' DocRepoDestinationPath: '' #usually docs-ref-services/ + GHReviewersVariable: '' + GHTeamReviewersVariable: '' # externally set, as eng-common does not have the identity-resolver. Run as pre-step steps: - pwsh: | @@ -56,3 +58,5 @@ steps: BaseBranchName: smoke-test WorkingDirectory: ${{ parameters.WorkingDirectory }}/repo ScriptDirectory: ${{ parameters.WorkingDirectory }}/${{ parameters.ScriptDirectory }} + GHReviewersVariable: ${{ parameters.GHReviewersVariable }} + GHTeamReviewersVariable: ${{ parameters.GHTeamReviewersVariable }} diff --git a/eng/common/pipelines/templates/steps/get-pr-owners.yml b/eng/common/pipelines/templates/steps/get-pr-owners.yml new file mode 100644 index 000000000000..a80d5b83b2de --- /dev/null +++ b/eng/common/pipelines/templates/steps/get-pr-owners.yml @@ -0,0 +1,46 @@ +parameters: + TargetVariable: '' + ServiceDirectory: '' + +steps: + - pwsh: | + git clone https://github.com/Azure/azure-sdk-tools.git $(Build.SourcesDirectory)/tools_repo + cd $(Build.SourcesDirectory)/tools_repo + git checkout 564ad63ae72d18422533fa1da9d396e7703c1cb5 + displayName: Setup Identity Resolver + + - pwsh: | + $result = dotnet run -v q -- ` + --aad-app-id-var APP_ID ` + --aad-app-secret-var APP_SECRET ` + --aad-tenant-var AAD_TENANT ` + --kusto-url-var KUSTO_URL ` + --kusto-database-var KUSTO_DB ` + --kusto-table-var KUSTO_TABLE ` + --identity "$(Build.QueuedBy)" + $resolvedIdentity = $result[-1] | ConvertFrom-Json + + Write-Host $resolvedIdentity + + Write-Output "##vso[task.setvariable variable=${{ parameters.TargetVariable }}]$($resolvedIdentity.GithubUserName)" + displayName: 'Resolving Queuing User' + workingDirectory: $(Build.SourcesDirectory)/tools_repo/tools/notification-configuration/identity-resolver + env: + APP_ID: $(notification-aad-app-id) + APP_SECRET: $(notification-aad-secret) + AAD_TENANT: $(notification-aad-tenant) + KUSTO_URL: $(notification-kusto-url) + KUSTO_DB: $(notification-kusto-db) + KUSTO_TABLE: $(notification-kusto-table) + + - pwsh: | + Remove-Item -Force -Recurse $(Build.SourcesDirectory)/tools_repo + displayName: Clean Up Cloned Tools Repo + + - pwsh: | + $originalValue = "$(${{ parameters.TargetVariable }})" + $result = $(Build.SourcesDirectory)/eng/common/scripts/get-codeowners.ps1 -TargetDirectory /sdk/${{ parameters.ServiceDirectory }}/ -RootDirectory $(Build.SourcesDirectory) + if ($result) { + Write-Output "##vso[task.setvariable variable=${{ parameters.TargetVariable }}]$originalValue,$result" + } + displayName: Add CodeOwners if Present \ No newline at end of file diff --git a/eng/common/pipelines/templates/steps/verify-links.yml b/eng/common/pipelines/templates/steps/verify-links.yml index 1a99350f0161..a3d385becefc 100644 --- a/eng/common/pipelines/templates/steps/verify-links.yml +++ b/eng/common/pipelines/templates/steps/verify-links.yml @@ -1,5 +1,7 @@ parameters: Directory: 'not-specified' + IgnoreLinksFile: "$(Build.SourcesDirectory)/eng/ignore-links.txt" + steps: - task: PowerShell@2 @@ -9,4 +11,4 @@ steps: workingDirectory: $(Build.SourcesDirectory)/${{ parameters.Directory }} filePath: eng/common/scripts/Verify-Links.ps1 arguments: > - -urls $(dir -r -i *.md) -rootUrl "file://$(Build.SourcesDirectory)/${{ parameters.Directory }}" + -urls $(dir -r -i *.md) -rootUrl "file://$(Build.SourcesDirectory)/${{ parameters.Directory }}" -recursive:$false -ignoreLinksFile ${{ parameters.IgnoreLinksFile }} diff --git a/eng/common/scripts/Submit-PullRequest.ps1 b/eng/common/scripts/Submit-PullRequest.ps1 index ef2a6f545061..5edabc599a99 100644 --- a/eng/common/scripts/Submit-PullRequest.ps1 +++ b/eng/common/scripts/Submit-PullRequest.ps1 @@ -58,6 +58,9 @@ $resp | Write-Verbose if ($resp.Count -gt 0) { Write-Host -f green "Pull request already exists $($resp[0].html_url)" + + # setting variable to reference the pull request by number + Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp[0].number)" } else { $data = @{ @@ -80,4 +83,7 @@ else { $resp | Write-Verbose Write-Host -f green "Pull request created https://github.com/$RepoOwner/$RepoName/pull/$($resp.number)" + + # setting variable to reference the pull request by number + Write-Host "##vso[task.setvariable variable=Submitted.PullRequest.Number]$($resp.number)" } diff --git a/eng/common/scripts/Verify-ChangeLog.ps1 b/eng/common/scripts/Verify-ChangeLog.ps1 index 816a82f5bcb2..26218d988df2 100644 --- a/eng/common/scripts/Verify-ChangeLog.ps1 +++ b/eng/common/scripts/Verify-ChangeLog.ps1 @@ -1,31 +1,48 @@ # Wrapper Script for ChangeLog Verification param ( - [String]$ChangeLogLocation, - [String]$VersionString, - [string]$PackageName, - [string]$ServiceName, - [string]$RepoRoot, - [ValidateSet("net","java","js","python")] - [string]$Language, - [string]$RepoName, - [boolean]$ForRelease=$False + [String]$ChangeLogLocation, + [String]$VersionString, + [string]$PackageName, + [string]$ServiceName, + [string]$RepoRoot, + [ValidateSet("net", "java", "js", "python")] + [string]$Language, + [string]$RepoName, + [boolean]$ForRelease = $False ) +$ProgressPreference = "SilentlyContinue" . (Join-Path $PSScriptRoot SemVer.ps1) Import-Module (Join-Path $PSScriptRoot modules ChangeLog-Operations.psm1) -if ((Test-Path $ChangeLogLocation) -and -not([System.String]::IsNullOrEmpty($VersionString))) +$validChangeLog = $false +if ($ChangeLogLocation -and $VersionString) { - Confirm-ChangeLogEntry -ChangeLogLocation $ChangeLogLocation -VersionString $VersionString -ForRelease $ForRelease + $validChangeLog = Confirm-ChangeLogEntry -ChangeLogLocation $ChangeLogLocation -VersionString $VersionString -ForRelease $ForRelease } -else +else { - Import-Module (Join-Path $PSScriptRoot modules Package-Properties.psm1) - if ([System.String]::IsNullOrEmpty($Language)) + Import-Module (Join-Path $PSScriptRoot modules Package-Properties.psm1) + if ([System.String]::IsNullOrEmpty($Language)) + { + if ($RepoName -match "azure-sdk-for-(?[^-]+)") { - $Language = $RepoName.Substring($RepoName.LastIndexOf('-') + 1) + $Language = $matches["lang"] } + else + { + Write-Error "Failed to set Language automatically. Please pass the appropriate Language as a parameter." + exit 1 + } + } + + $PackageProp = Get-PkgProperties -PackageName $PackageName -ServiceName $ServiceName -Language $Language -RepoRoot $RepoRoot + $validChangeLog = Confirm-ChangeLogEntry -ChangeLogLocation $PackageProp.pkgChangeLogPath -VersionString $PackageProp.pkgVersion -ForRelease $ForRelease +} + +if (!$validChangeLog) +{ + exit 1 +} - $PackageProp = Get-PkgProperties -PackageName $PackageName -ServiceName $ServiceName -Language $Language -RepoRoot $RepoRoot - Confirm-ChangeLogEntry -ChangeLogLocation $PackageProp.pkgChangeLogPath -VersionString $PackageProp.pkgVersion -ForRelease $ForRelease -} \ No newline at end of file +exit 0 \ No newline at end of file diff --git a/eng/common/scripts/add-pullrequest-reviewers.ps1 b/eng/common/scripts/add-pullrequest-reviewers.ps1 new file mode 100644 index 000000000000..00460ce701f0 --- /dev/null +++ b/eng/common/scripts/add-pullrequest-reviewers.ps1 @@ -0,0 +1,79 @@ +param( + [Parameter(Mandatory = $true)] + $RepoOwner, + + [Parameter(Mandatory = $true)] + $RepoName, + + [Parameter(Mandatory = $false)] + $GitHubUsers = "", + + [Parameter(Mandatory = $false)] + $GitHubTeams = "", + + [Parameter(Mandatory = $true)] + $PRNumber, + + [Parameter(Mandatory = $true)] + $AuthToken +) + +# at least one of these needs to be populated +if (-not $GitHubUsers -and -not $GitHubTeams) { + Write-Host "No user provided for addition, exiting." + exit 0 +} + +$userAdditions = @($GitHubUsers.Split(",") | % { $_.Trim() } | ? { return $_ }) +$teamAdditions = @($GitHubTeams.Split(",") | % { $_.Trim() } | ? { return $_ }) + +$headers = @{ + Authorization = "bearer $AuthToken" +} +$uri = "https://api.github.com/repos/$RepoOwner/$RepoName/pulls/$PRNumber/requested_reviewers" + +try { + $resp = Invoke-RestMethod -Headers $headers $uri -MaximumRetryCount 3 +} +catch { + Write-Error "Invoke-RestMethod [$uri] failed with exception:`n$_" + exit 1 +} + +# the response object takes this form: https://developer.github.com/v3/pulls/review_requests/#response-1 +# before we can push a new reviewer, we need to pull the simple Ids out of the complex objects that came back in the response +$userReviewers = @($resp.users | % { return $_.login }) +$teamReviewers = @($resp.teams | % { return $_.slug }) + +if (!$usersReviewers) { $modifiedUserReviewers = @() } else { $modifiedUserReviewers = $usersReviewers.Clone() } +$modifiedUserReviewers += ($modifiedUserReviewers | ? { !$usersReviews.Contains($_) }) + +if ($teamReviewers) { $modifiedTeamReviewers = @() } else { $modifiedTeamReviewers = $teamReviewers.Clone() } +$modifiedTeamReviewers += ($modifiedUserReviewers | ? { !$teamReviewers.Contains($_) }) + +$detectedUserDiffs = Compare-Object -ReferenceObject $userReviewers -DifferenceObject $modifiedUserReviewers +$detectedTeamDiffs = Compare-Object -ReferenceObject $teamReviewers -DifferenceObject $modifiedTeamReviewers + +# Compare-Object returns values when there is a difference between the comparied objects. +# we only want to run the update if there IS a difference. +if ($detectedUserDiffs -or $detectedTeamDiffs) { + $postResp = @{} + + if ($modifiedUserReviewers) { $postResp["reviewers"] = $modifiedUserReviewers } + if ($modifiedTeamReviewers) { $postResp["team_reviewers"] = $modifiedTeamReviewers } + + $postResp = $postResp | ConvertTo-Json + + try { + $resp = Invoke-RestMethod -Method Post -Headers $headers -Body $postResp -Uri $uri -MaximumRetryCount 3 + $resp | Write-Verbose + } + catch { + Write-Error "Unable to update PR reviewers. `n$_" + } +} +else { + $results = $GitHubUsers + $GitHubTeams + Write-Host "Reviewers $results already added. Exiting." + exit(0) +} diff --git a/eng/common/scripts/get-codeowners.ps1 b/eng/common/scripts/get-codeowners.ps1 new file mode 100644 index 000000000000..edbae4cb18c6 --- /dev/null +++ b/eng/common/scripts/get-codeowners.ps1 @@ -0,0 +1,40 @@ +param ( + $TargetDirectory, # should be in relative form from root of repo. EG: sdk/servicebus + $RootDirectory # ideally $(Build.SourcesDirectory) +) + +$codeOwnersLocation = Join-Path $RootDirectory -ChildPath ".github/CODEOWNERS" + +if (!(Test-Path $codeOwnersLocation)) { + Write-Host "Unable to find CODEOWNERS file in target directory $RootDirectory" + exit 1 +} + +$codeOwnersContent = Get-Content $codeOwnersLocation + +$ownedFolders = @{} + +foreach ($contentLine in $codeOwnersContent) { + if (-not $contentLine.StartsWith("#") -and $contentLine){ + $splitLine = $contentLine -split "\s+" + + # CODEOWNERS file can also have labels present after the owner aliases + # gh aliases start with @ in codeowners. don't pass on to API calls + $ownedFolders[$splitLine[0].ToLower()] = ($splitLine[1..$($splitLine.Length)] ` + | ? { $_.StartsWith("@") } ` + | % { return $_.substring(1) }) -join "," + } +} + +$results = $ownedFolders[$TargetDirectory.ToLower()] + +if ($results) { + Write-Host "Discovered code owners for path $TargetDirectory are $results." + return $results +} +else { + Write-Host "Unable to match path $TargetDirectory in CODEOWNERS file located at $codeOwnersLocation." + Write-Host $ownedFolders | ConvertTo-Json + return "" +} + diff --git a/eng/common/scripts/modules/ChangeLog-Operations.psm1 b/eng/common/scripts/modules/ChangeLog-Operations.psm1 index e92070b195b3..5aed584d018b 100644 --- a/eng/common/scripts/modules/ChangeLog-Operations.psm1 +++ b/eng/common/scripts/modules/ChangeLog-Operations.psm1 @@ -11,8 +11,8 @@ function Get-ChangeLogEntries { $changeLogEntries = @{} if (!(Test-Path $ChangeLogLocation)) { - Write-Host "ChangeLog '{0}' was not found" -f $ChangeLogLocation - exit 1 + Write-Error "ChangeLog[${ChangeLogLocation}] does not exist" + return $null } try { @@ -51,14 +51,12 @@ function Get-ChangeLogEntry { [Parameter(Mandatory = $true)] [String]$VersionString ) - $changeLogEntries = Get-ChangeLogEntries -ChangeLogLocation $ChangeLogLocation - if ($changeLogEntries.ContainsKey($VersionString)) { + if ($changeLogEntries -and $changeLogEntries.ContainsKey($VersionString)) { return $changeLogEntries[$VersionString] } - Write-Error "Release Notes for the Specified version ${VersionString} was not found" - exit 1 + return $null } #Returns the changelog for a particular version as string @@ -70,9 +68,16 @@ function Get-ChangeLogEntryAsString { [String]$VersionString ) - $changeLogEntries = Get-ChangeLogEntry -ChangeLogLocation $ChangeLogLocation -VersionString $VersionString - [string]$releaseTitle = $changeLogEntries.ReleaseTitle - [string]$releaseContent = $changeLogEntries.ReleaseContent -Join [Environment]::NewLine + $changeLogEntry = Get-ChangeLogEntry -ChangeLogLocation $ChangeLogLocation -VersionString $VersionString + return ChangeLogEntryAsString $changeLogEntry +} + +function ChangeLogEntryAsString($changeLogEntry) { + if (!$changeLogEntry) { + return "[Missing change log entry]" + } + [string]$releaseTitle = $changeLogEntry.ReleaseTitle + [string]$releaseContent = $changeLogEntry.ReleaseContent -Join [Environment]::NewLine return $releaseTitle, $releaseContent -Join [Environment]::NewLine } @@ -87,27 +92,33 @@ function Confirm-ChangeLogEntry { $changeLogEntry = Get-ChangeLogEntry -ChangeLogLocation $ChangeLogLocation -VersionString $VersionString + if (!$changeLogEntry) { + Write-Error "ChangeLog[${ChangeLogLocation}] does not have an entry for version ${VersionString}." + return $false + } + + Write-Host "Found the following change log entry for version '${VersionString}' in [${ChangeLogLocation}]." + Write-Host "-----" + Write-Host (ChangeLogEntryAsString $changeLogEntry) + Write-Host "-----" + if ([System.String]::IsNullOrEmpty($changeLogEntry.ReleaseStatus)) { - Write-Host ("##[error]Changelog '{0}' has wrong release note title" -f $ChangeLogLocation) - Write-Host "##[info]Ensure the release date is included i.e. (yyyy-MM-dd) or (Unreleased) if not yet released" - exit 1 + Write-Error "Entry does not have a correct release status. Please ensure the status is set to a date '(yyyy-MM-dd)' or '(Unreleased)' if not yet released." + return $false } if ($ForRelease -eq $True) { if ($changeLogEntry.ReleaseStatus -eq "(Unreleased)") { - Write-Host ("##[error]No release date set. Please set a release date with format 'yyyy-MM-dd' in the heading for version '{0}' in the changelog '{1}'." -f $VersionString, $ChangelogLocation) - exit 1 + Write-Error "Entry has no release date set. Please ensure to set a release date with format 'yyyy-MM-dd'." + return $false } if ([System.String]::IsNullOrWhiteSpace($changeLogEntry.ReleaseContent)) { - Write-Host ("##[error]Empty Release Notes for '{0}' in '{1}'" -f $VersionString, $ChangeLogLocation) - Write-Host "##[info]Please ensure there is a release notes entry before releasing the package." - exit 1 + Write-Error "Entry has no content. Please ensure to provide some content of what changed in this version." + return $false } } - - Write-Host $changeLogEntry.ReleaseTitle - Write-Host $changeLogEntry.ReleaseContent + return $true } Export-ModuleMember -Function 'Get-ChangeLogEntries' diff --git a/eng/common/scripts/modules/Package-Properties.psm1 b/eng/common/scripts/modules/Package-Properties.psm1 index dca123f929f7..b9a8eb11780d 100644 --- a/eng/common/scripts/modules/Package-Properties.psm1 +++ b/eng/common/scripts/modules/Package-Properties.psm1 @@ -3,13 +3,24 @@ class PackageProps { [string]$pkgName - [AzureEngSemanticVersion]$pkgVersion + [string]$pkgVersion [string]$pkgDirectoryPath [string]$pkgServiceName [string]$pkgReadMePath [string]$pkgChangeLogPath + [string]$pkgGroup - PackageProps( + PackageProps([string]$pkgName,[string]$pkgVersion,[string]$pkgDirectoryPath,[string]$pkgServiceName) + { + $this.Initialize($pkgName, $pkgVersion, $pkgDirectoryPath, $pkgServiceName) + } + + PackageProps([string]$pkgName,[string]$pkgVersion,[string]$pkgDirectoryPath,[string]$pkgServiceName,[string]$pkgGroup="") + { + $this.Initialize($pkgName, $pkgVersion, $pkgDirectoryPath, $pkgServiceName, $pkgGroup) + } + + hidden [void]Initialize( [string]$pkgName, [string]$pkgVersion, [string]$pkgDirectoryPath, @@ -17,11 +28,7 @@ class PackageProps ) { $this.pkgName = $pkgName - $this.pkgVersion = [AzureEngSemanticVersion]::ParseVersionString($pkgVersion) - if ($this.pkgVersion -eq $null) - { - Write-Error "Invalid version in $pkgDirectoryPath" - } + $this.pkgVersion = $pkgVersion $this.pkgDirectoryPath = $pkgDirectoryPath $this.pkgServiceName = $pkgServiceName @@ -43,8 +50,24 @@ class PackageProps $this.pkgChangeLogPath = $null } } + + hidden [void]Initialize( + [string]$pkgName, + [string]$pkgVersion, + [string]$pkgDirectoryPath, + [string]$pkgServiceName, + [string]$pkgGroup + ) + { + $this.Initialize($pkgName, $pkgVersion, $pkgDirectoryPath, $pkgServiceName) + $this.pkgGroup = $pkgGroup + } } +$ProgressPreference = "SilentlyContinue" + + +Register-PSRepository -Default -ErrorAction:SilentlyContinue Install-Module -Name powershell-yaml -RequiredVersion 0.4.1 -Force -Scope CurrentUser function Extract-PkgProps ($pkgPath, $serviceName, $pkgName, $lang) @@ -126,10 +149,11 @@ function Extract-JavaPkgProps ($pkgPath, $serviceName, $pkgName) $projectData.load($projectPath) $projectPkgName = $projectData.project.artifactId $pkgVersion = $projectData.project.version + $pkgGroup = $projectData.project.groupId if ($projectPkgName -eq $pkgName) { - return [PackageProps]::new($pkgName, $pkgVersion.ToString(), $pkgPath, $serviceName) + return [PackageProps]::new($pkgName, $pkgVersion.ToString(), $pkgPath, $serviceName, $pkgGroup) } } return $null @@ -239,8 +263,14 @@ function Get-PkgListFromYml ($ciYmlPath) { $ciYmlContent = Get-Content $ciYmlPath -Raw $ciYmlObj = ConvertFrom-Yaml $ciYmlContent -Ordered - $artifactsInCI = $ciYmlObj["stages"][0]["parameters"]["Artifacts"] - + if ($ciYmlObj.Contains("stages")) + { + $artifactsInCI = $ciYmlObj["stages"][0]["parameters"]["Artifacts"] + } + elseif ($ciYmlObj.Contains("extends")) + { + $artifactsInCI = $ciYmlObj["extends"]["parameters"]["Artifacts"] + } if ($artifactsInCI -eq $null) { Write-Error "Failed to retrive package names in ci $ciYmlPath" From df3f611e20462883a010e684665b32ca27d2aad8 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 16 Jul 2020 22:48:54 -0700 Subject: [PATCH 12/12] Update change log date --- sdk/identity/azure-identity/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index cd2f8870c8a3..e4c4ca143879 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 1.0.9 (2020-07-15) +## 1.0.9 (2020-07-17) - Upgraded `msal4j` dependency to 1.6.1 ## 1.0.8 (2020-07-06)