diff --git a/build/azure-pr-pipeline.yaml b/build/azure-pr-pipeline.yaml index bc6c22af..b21273b0 100644 --- a/build/azure-pr-pipeline.yaml +++ b/build/azure-pr-pipeline.yaml @@ -21,115 +21,224 @@ variables: skip.integration.tests: false system.debug: false -pool: - vmImage: windows-2025 - -steps: - - checkout: self - clean: false - fetchDepth: 0 - fetchTags: false - - - task: DownloadSecureFile@1 - name: LabAuth - displayName: Download LabAuth certificate - inputs: - secureFile: 6cfea379-ebe1-4e95-b2b8-1b509a4e70c4 - retryCount: "8" - - - task: PowerShell@2 - displayName: Save certificate in store - inputs: - targetType: inline - script: | - $ErrorActionPreference = "Stop" - - Import-PfxCertificate ` - -FilePath "$(LabAuth.secureFilePath)" ` - -CertStoreLocation "Cert:\CurrentUser\My" ` - -Exportable - - - task: PowerShell@2 - displayName: Install Chrome and ChromeDriver - inputs: - targetType: inline - script: | - $ErrorActionPreference = "Stop" - - $installer = Join-Path $env:Agent_TempDirectory "chrome-installer.exe" - Invoke-WebRequest ` - -Uri "https://dl.google.com/chrome/install/latest/chrome_installer.exe" ` - -OutFile $installer - - Start-Process ` - -FilePath $installer ` - -ArgumentList "/silent", "/install" ` - -Wait - - $chromePath = "${env:ProgramFiles}\Google\Chrome\Application\chrome.exe" - $chromeVersion = (Get-Item $chromePath).VersionInfo.ProductVersion - $chromeBuild = ($chromeVersion.Split(".")[0..2] -join ".") - - Write-Host "Installed Chrome version: $chromeVersion" - - $driverVersion = Invoke-RestMethod ` - "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_$chromeBuild" - - Write-Host "Using ChromeDriver version: $driverVersion" - - $zip = Join-Path $env:Agent_TempDirectory "chromedriver.zip" - $extract = Join-Path $env:Agent_TempDirectory "chromedriver" - - Invoke-WebRequest ` - -Uri "https://storage.googleapis.com/chrome-for-testing-public/$driverVersion/win64/chromedriver-win64.zip" ` - -OutFile $zip - - Expand-Archive -Path $zip -DestinationPath $extract -Force - Copy-Item ` - "$extract\chromedriver-win64\chromedriver.exe" ` - "C:\Windows\chromedriver.exe" ` - -Force - - - task: Maven@4 - displayName: Run unit tests - inputs: - mavenPomFile: pom.xml - goals: verify - options: >- - -fae - -Drevapi.failBuildOnProblemsFound=false - -Dskip.unit.tests=$(skip.unit.tests) - -Dskip.integration.tests=true - -Dadfs.disabled=true - publishJUnitResults: true - testResultsFiles: "**/surefire-reports/TEST-*.xml" - javaHomeOption: JDKVersion - jdkVersionOption: "1.8" - jdkArchitectureOption: x64 - - - task: Maven@4 - displayName: Run integration tests - inputs: - mavenPomFile: pom.xml - goals: verify - options: >- - -fae - -Drevapi.failBuildOnProblemsFound=false - -Dskip.unit.tests=true - -Dskip.integration.tests=$(skip.integration.tests) - -Dadfs.disabled=true - publishJUnitResults: true - testResultsFiles: "**/failsafe-reports/TEST-*.xml" - javaHomeOption: JDKVersion - jdkVersionOption: "1.8" - jdkArchitectureOption: x64 - - - task: PublishCodeCoverageResults@2 - displayName: Publish JaCoCo coverage - condition: succeededOrFailed() - inputs: - summaryFileLocation: >- - $(System.DefaultWorkingDirectory)\msal4j-sdk\target\site\jacoco\jacoco.xml - pathToSources: >- - $(System.DefaultWorkingDirectory)\msal4j-sdk\src\main\java - failIfCoverageEmpty: false +jobs: + - job: BuildAndTest + displayName: Build and test + pool: + vmImage: windows-2025 + steps: + - checkout: self + clean: false + fetchDepth: 0 + fetchTags: false + + - task: DownloadSecureFile@1 + name: LabAuth + displayName: Download LabAuth certificate + inputs: + secureFile: 6cfea379-ebe1-4e95-b2b8-1b509a4e70c4 + retryCount: "8" + + - task: PowerShell@2 + displayName: Save certificate in store + inputs: + targetType: inline + script: | + $ErrorActionPreference = "Stop" + + Import-PfxCertificate ` + -FilePath "$(LabAuth.secureFilePath)" ` + -CertStoreLocation "Cert:\CurrentUser\My" ` + -Exportable + + - task: PowerShell@2 + displayName: Install Chrome and ChromeDriver + inputs: + targetType: inline + script: | + $ErrorActionPreference = "Stop" + + $installer = Join-Path ` + $env:Agent_TempDirectory ` + "chrome-installer.exe" + Invoke-WebRequest ` + -Uri "https://dl.google.com/chrome/install/latest/chrome_installer.exe" ` + -OutFile $installer + + Start-Process ` + -FilePath $installer ` + -ArgumentList "/silent", "/install" ` + -Wait + + $chromePath = ` + "${env:ProgramFiles}\Google\Chrome\Application\chrome.exe" + $chromeVersion = (Get-Item $chromePath).VersionInfo.ProductVersion + $chromeBuild = ($chromeVersion.Split(".")[0..2] -join ".") + + Write-Host "Installed Chrome version: $chromeVersion" + + $driverVersion = Invoke-RestMethod ` + "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_$chromeBuild" + + Write-Host "Using ChromeDriver version: $driverVersion" + + $zip = Join-Path ` + $env:Agent_TempDirectory ` + "chromedriver.zip" + $extract = Join-Path ` + $env:Agent_TempDirectory ` + "chromedriver" + + Invoke-WebRequest ` + -Uri "https://storage.googleapis.com/chrome-for-testing-public/$driverVersion/win64/chromedriver-win64.zip" ` + -OutFile $zip + + Expand-Archive -Path $zip -DestinationPath $extract -Force + Copy-Item ` + "$extract\chromedriver-win64\chromedriver.exe" ` + "C:\Windows\chromedriver.exe" ` + -Force + + - task: Maven@4 + displayName: Run unit tests + inputs: + mavenPomFile: pom.xml + goals: verify + options: >- + -fae + -Drevapi.failBuildOnProblemsFound=false + -Dskip.unit.tests=$(skip.unit.tests) + -Dskip.integration.tests=true + -Dadfs.disabled=true + publishJUnitResults: true + testResultsFiles: "**/surefire-reports/TEST-*.xml" + javaHomeOption: JDKVersion + jdkVersionOption: "1.8" + jdkArchitectureOption: x64 + + - task: Maven@4 + displayName: Run integration tests + inputs: + mavenPomFile: pom.xml + goals: verify + options: >- + -fae + -Drevapi.failBuildOnProblemsFound=false + -Dskip.unit.tests=true + -Dskip.integration.tests=$(skip.integration.tests) + -Dadfs.disabled=true + publishJUnitResults: true + testResultsFiles: "**/failsafe-reports/TEST-*.xml" + javaHomeOption: JDKVersion + jdkVersionOption: "1.8" + jdkArchitectureOption: x64 + + - task: PublishCodeCoverageResults@2 + displayName: Publish JaCoCo coverage + condition: succeededOrFailed() + inputs: + summaryFileLocation: >- + $(System.DefaultWorkingDirectory)\msal4j-sdk\target\site\jacoco\jacoco.xml + pathToSources: >- + $(System.DefaultWorkingDirectory)\msal4j-sdk\src\main\java + failIfCoverageEmpty: false + + - job: PrepareManagedIdentityTools + displayName: Prepare Managed Identity E2E tools + pool: + vmImage: windows-2025 + steps: + - checkout: self + clean: false + fetchDepth: 1 + + - task: PowerShell@2 + displayName: Download verified JDK and Maven archives + inputs: + filePath: build/prepare-managed-identity-e2e-tools.ps1 + arguments: >- + -OutputDirectory + "$(Build.ArtifactStagingDirectory)\managed-identity-e2e-tools" + + - task: PublishPipelineArtifact@1 + displayName: Publish Managed Identity E2E tools + inputs: + targetPath: >- + $(Build.ArtifactStagingDirectory)\managed-identity-e2e-tools + artifact: managed-identity-e2e-tools + + - job: ManagedIdentityImds + displayName: Managed Identity E2E - IMDS + dependsOn: PrepareManagedIdentityTools + pool: + name: MISEManagedIdentity + variables: + runCodesignValidationInjection: false + Codeql.SkipTaskAutoInjection: true + steps: + - checkout: self + clean: true + fetchDepth: 1 + + - task: DownloadPipelineArtifact@2 + displayName: Download Managed Identity E2E tools + inputs: + artifact: managed-identity-e2e-tools + path: $(Pipeline.Workspace)\managed-identity-e2e-tools + + - task: PowerShell@2 + displayName: Run Managed Identity IMDS E2E + inputs: + filePath: build/run-managed-identity-e2e.ps1 + arguments: >- + -TestClass ManagedIdentityImdsE2E + -ToolsArchiveDirectory + "$(Pipeline.Workspace)\managed-identity-e2e-tools" + + - task: PublishTestResults@2 + displayName: Publish Managed Identity IMDS results + condition: succeededOrFailed() + inputs: + testResultsFormat: JUnit + testResultsFiles: >- + **/failsafe-reports/TEST-*.xml + failTaskOnFailedTests: true + testRunTitle: Managed Identity IMDS E2E + + - job: ManagedIdentityAzureArc + displayName: Managed Identity E2E - Azure Arc + dependsOn: PrepareManagedIdentityTools + pool: + name: MISEAZUREARC + variables: + runCodesignValidationInjection: false + Codeql.SkipTaskAutoInjection: true + steps: + - checkout: self + clean: true + fetchDepth: 1 + + - task: DownloadPipelineArtifact@2 + displayName: Download Managed Identity E2E tools + inputs: + artifact: managed-identity-e2e-tools + path: $(Pipeline.Workspace)\managed-identity-e2e-tools + + - task: PowerShell@2 + displayName: Run Managed Identity Azure Arc E2E + inputs: + filePath: build/run-managed-identity-e2e.ps1 + arguments: >- + -TestClass ManagedIdentityAzureArcE2E + -ToolsArchiveDirectory + "$(Pipeline.Workspace)\managed-identity-e2e-tools" + + - task: PublishTestResults@2 + displayName: Publish Managed Identity Azure Arc results + condition: succeededOrFailed() + inputs: + testResultsFormat: JUnit + testResultsFiles: >- + **/failsafe-reports/TEST-*.xml + failTaskOnFailedTests: true + testRunTitle: Managed Identity Azure Arc E2E diff --git a/build/prepare-managed-identity-e2e-tools.ps1 b/build/prepare-managed-identity-e2e-tools.ps1 new file mode 100644 index 00000000..87ec7970 --- /dev/null +++ b/build/prepare-managed-identity-e2e-tools.ps1 @@ -0,0 +1,133 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string] $OutputDirectory +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" +[Net.ServicePointManager]::SecurityProtocol = ` + [Net.ServicePointManager]::SecurityProtocol -bor ` + [Net.SecurityProtocolType]::Tls12 + +function Invoke-WithRetry { + param( + [Parameter(Mandatory = $true)] + [scriptblock] $Operation, + + [Parameter(Mandatory = $true)] + [string] $Description, + + [int] $MaximumAttempts = 3 + ) + + for ($attempt = 1; $attempt -le $MaximumAttempts; $attempt++) { + try { + return & $Operation + } catch { + if ($attempt -eq $MaximumAttempts) { + throw + } + + Write-Warning ( + "$Description failed on attempt $attempt. Retrying..." + ) + Start-Sleep -Seconds (5 * $attempt) + } + } +} + +New-Item -ItemType Directory -Force -Path $OutputDirectory | Out-Null + +$jdkAssetsUrl = "https://api.adoptium.net/v3/assets/latest/8/hotspot" + + "?architecture=x64&heap_size=normal&image_type=jdk" + + "&jvm_impl=hotspot&os=windows&vendor=eclipse" +$jdkAsset = (Invoke-WithRetry ` + -Description "Adoptium metadata request" ` + -Operation { Invoke-RestMethod -Uri $jdkAssetsUrl })[0] +if ($null -eq $jdkAsset.binary.package.link -or + $null -eq $jdkAsset.binary.package.checksum) { + throw "Adoptium did not return a downloadable JDK 8 package." +} + +$jdkArchive = Join-Path $OutputDirectory "temurin-jdk8.zip" +Invoke-WithRetry ` + -Description "JDK 8 download" ` + -Operation { + Invoke-WebRequest ` + -Uri $jdkAsset.binary.package.link ` + -OutFile $jdkArchive + } +Set-Content ` + -LiteralPath "$jdkArchive.sha256" ` + -Value $jdkAsset.binary.package.checksum ` + -NoNewline + +$jdkExtractRoot = Join-Path $env:Agent_TempDirectory "mi-e2e-jdk" +Expand-Archive ` + -LiteralPath $jdkArchive ` + -DestinationPath $jdkExtractRoot ` + -Force +$javaExecutable = Get-ChildItem ` + -Path $jdkExtractRoot ` + -Filter java.exe ` + -File ` + -Recurse | + Where-Object { $_.DirectoryName -like "*\bin" } | + Select-Object -First 1 +if ($null -eq $javaExecutable) { + throw "Downloaded JDK 8 archive did not contain java.exe." +} +$env:JAVA_HOME = $javaExecutable.Directory.Parent.FullName +$env:PATH = "$($javaExecutable.Directory.FullName);$env:PATH" + +$mavenVersion = "3.9.11" +$mavenArchiveName = "apache-maven-$mavenVersion-bin.zip" +$mavenArchiveUrl = + "https://archive.apache.org/dist/maven/maven-3/$mavenVersion/binaries/" + + $mavenArchiveName +$mavenArchive = Join-Path $OutputDirectory $mavenArchiveName +Invoke-WithRetry ` + -Description "Maven download" ` + -Operation { + Invoke-WebRequest ` + -Uri $mavenArchiveUrl ` + -OutFile $mavenArchive + } +$mavenHash = ( + (Invoke-WithRetry ` + -Description "Maven checksum request" ` + -Operation { + Invoke-RestMethod -Uri "$mavenArchiveUrl.sha512" + }) -split "\s+" +)[0] +Set-Content ` + -LiteralPath "$mavenArchive.sha512" ` + -Value $mavenHash ` + -NoNewline + +$mavenExtractRoot = Join-Path $env:Agent_TempDirectory "mi-e2e-maven" +Expand-Archive ` + -LiteralPath $mavenArchive ` + -DestinationPath $mavenExtractRoot ` + -Force +$maven = Join-Path ` + $mavenExtractRoot ` + "apache-maven-$mavenVersion\bin\mvn.cmd" +$mavenRepository = Join-Path $OutputDirectory "maven-repository" + +& $maven ` + "-f" (Join-Path $env:BUILD_SOURCESDIRECTORY "pom.xml") ` + "-pl" "msal4j-sdk" ` + "-am" ` + "-Drevapi.failBuildOnProblemsFound=false" ` + "-Dskip.unit.tests=true" ` + "-Dskip.integration.tests=false" ` + "-Dadfs.disabled=true" ` + "-Dit.test=ManagedIdentityImdsE2E" ` + "-DmanagedIdentity.e2e.enabled=false" ` + "-Dmaven.repo.local=$mavenRepository" ` + "verify" +if ($LASTEXITCODE -ne 0) { + throw "Failed to prepare the offline Maven repository." +} diff --git a/build/run-managed-identity-e2e.ps1 b/build/run-managed-identity-e2e.ps1 new file mode 100644 index 00000000..6aaf0557 --- /dev/null +++ b/build/run-managed-identity-e2e.ps1 @@ -0,0 +1,98 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [ValidateSet("ManagedIdentityImdsE2E", "ManagedIdentityAzureArcE2E")] + [string] $TestClass, + + [Parameter(Mandatory = $true)] + [string] $ToolsArchiveDirectory +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$mavenVersion = "3.9.11" +$mavenArchiveName = "apache-maven-$mavenVersion-bin.zip" +$mavenArchivePath = Join-Path $ToolsArchiveDirectory $mavenArchiveName +$mavenRoot = + Join-Path $env:Agent_TempDirectory "apache-maven-$mavenVersion" +$maven = Join-Path $mavenRoot "bin\mvn.cmd" +$mavenRepository = Join-Path $ToolsArchiveDirectory "maven-repository" + +$jdkRoot = Join-Path $env:Agent_TempDirectory "temurin-jdk8" +$javaExecutable = Get-ChildItem ` + -Path $jdkRoot ` + -Filter java.exe ` + -File ` + -Recurse ` + -ErrorAction SilentlyContinue | + Where-Object { $_.DirectoryName -like "*\bin" } | + Select-Object -First 1 + +if ($null -eq $javaExecutable) { + $jdkArchive = Join-Path $ToolsArchiveDirectory "temurin-jdk8.zip" + $expectedJdkHash = Get-Content ` + -LiteralPath "$jdkArchive.sha256" ` + -Raw + $actualJdkHash = (Get-FileHash ` + -LiteralPath $jdkArchive ` + -Algorithm SHA256).Hash + if ($actualJdkHash -ne $expectedJdkHash) { + throw "Downloaded JDK 8 archive failed SHA-256 verification." + } + + New-Item -ItemType Directory -Force -Path $jdkRoot | Out-Null + Expand-Archive ` + -LiteralPath $jdkArchive ` + -DestinationPath $jdkRoot ` + -Force + + $javaExecutable = Get-ChildItem ` + -Path $jdkRoot ` + -Filter java.exe ` + -File ` + -Recurse | + Where-Object { $_.DirectoryName -like "*\bin" } | + Select-Object -First 1 + if ($null -eq $javaExecutable) { + throw "Downloaded JDK 8 archive did not contain java.exe." + } +} + +$env:JAVA_HOME = $javaExecutable.Directory.Parent.FullName +$env:PATH = "$($javaExecutable.Directory.FullName);$env:PATH" + +if (-not (Test-Path -LiteralPath $maven -PathType Leaf)) { + $expectedMavenHash = Get-Content ` + -LiteralPath "$mavenArchivePath.sha512" ` + -Raw + $actualMavenHash = (Get-FileHash ` + -LiteralPath $mavenArchivePath ` + -Algorithm SHA512).Hash + if ($actualMavenHash -ne $expectedMavenHash) { + throw "Downloaded Maven archive failed SHA-512 verification." + } + + Expand-Archive ` + -LiteralPath $mavenArchivePath ` + -DestinationPath $env:Agent_TempDirectory ` + -Force +} + +& $javaExecutable.FullName -version +& $maven -version +& $maven ` + "-o" ` + "-pl" "msal4j-sdk" ` + "-am" ` + "-Drevapi.failBuildOnProblemsFound=false" ` + "-Dskip.unit.tests=true" ` + "-Dskip.integration.tests=false" ` + "-Dadfs.disabled=true" ` + "-Dit.test=$TestClass" ` + "-DmanagedIdentity.e2e.enabled=true" ` + "-Dmaven.repo.local=$mavenRepository" ` + "verify" +if ($LASTEXITCODE -ne 0) { + throw "$TestClass failed with exit code $LASTEXITCODE." +} diff --git a/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityAzureArcE2E.java b/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityAzureArcE2E.java new file mode 100644 index 00000000..56a44a56 --- /dev/null +++ b/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityAzureArcE2E.java @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +class ManagedIdentityAzureArcE2E { + + private static final String ARM_RESOURCE = "https://management.azure.com"; + private static final String UNASSIGNED_CLIENT_ID = + "00000000-0000-0000-0000-000000000001"; + + @BeforeAll + static void requireLiveManagedIdentityEnvironment() { + assumeTrue( + Boolean.getBoolean("managedIdentity.e2e.enabled"), + "Live Managed Identity E2E execution is not enabled."); + } + + @Test + void systemAssignedIdentityAcquiresAndCachesToken() throws Exception { + ManagedIdentityApplication application = ManagedIdentityApplication.builder( + ManagedIdentityId.systemAssigned()).build(); + ManagedIdentityParameters parameters = + ManagedIdentityParameters.builder(ARM_RESOURCE).build(); + + IAuthenticationResult first = + application.acquireTokenForManagedIdentity(parameters).get(); + assertValidResult(first); + assertEquals(TokenSource.IDENTITY_PROVIDER, first.metadata().tokenSource()); + + IAuthenticationResult cached = + application.acquireTokenForManagedIdentity(parameters).get(); + assertValidResult(cached); + assertEquals(TokenSource.CACHE, cached.metadata().tokenSource()); + assertEquals(first.accessToken(), cached.accessToken()); + } + + @Test + void unassignedUserAssignedIdentityFailsClosed() { + ManagedIdentityApplication application = ManagedIdentityApplication.builder( + ManagedIdentityId.userAssignedClientId(UNASSIGNED_CLIENT_ID)).build(); + ManagedIdentityParameters parameters = + ManagedIdentityParameters.builder(ARM_RESOURCE).build(); + + ExecutionException executionException = assertThrows( + ExecutionException.class, + () -> application.acquireTokenForManagedIdentity(parameters).get()); + assertTrue(executionException.getCause() instanceof MsalServiceException); + + MsalServiceException serviceException = + (MsalServiceException) executionException.getCause(); + assertEquals( + MsalError.MANAGED_IDENTITY_REQUEST_FAILED, + serviceException.errorCode()); + assertEquals( + ManagedIdentitySourceType.AZURE_ARC.name(), + serviceException.managedIdentitySource()); + assertTrue( + serviceException.getMessage().contains("identity_not_found") + || serviceException.getMessage().contains("Identity not found")); + } + + private static void assertValidResult(IAuthenticationResult result) { + assertNotNull(result); + assertNotNull(result.accessToken()); + assertFalse(result.accessToken().isEmpty()); + } +} diff --git a/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityImdsE2E.java b/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityImdsE2E.java new file mode 100644 index 00000000..ed257df4 --- /dev/null +++ b/msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/ManagedIdentityImdsE2E.java @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.aad.msal4j; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ManagedIdentityImdsE2E { + + private static final String ARM_RESOURCE = "https://management.azure.com"; + private static final String USER_ASSIGNED_CLIENT_ID = + "6325cd32-9911-41f3-819c-416cdf9104e7"; + private static final String USER_ASSIGNED_RESOURCE_ID = + "/subscriptions/c1686c51-b717-4fe0-9af3-24a20a41fb0c/" + + "resourcegroups/MSIV2-Testing-MSALNET/providers/" + + "Microsoft.ManagedIdentity/userAssignedIdentities/msiv2uami"; + private static final String USER_ASSIGNED_OBJECT_ID = + "ecb2ad92-3e30-4505-b79f-ac640d069f24"; + + @BeforeAll + static void requireLiveManagedIdentityEnvironment() { + assumeTrue( + Boolean.getBoolean("managedIdentity.e2e.enabled"), + "Live Managed Identity E2E execution is not enabled."); + } + + @Test + void systemAssignedIdentityAcquiresAndCachesToken() throws Exception { + assertTokenAcquisition(ManagedIdentityId.systemAssigned()); + } + + @Test + void userAssignedClientIdAcquiresAndCachesToken() throws Exception { + assertTokenAcquisition( + ManagedIdentityId.userAssignedClientId(USER_ASSIGNED_CLIENT_ID)); + } + + @Test + void userAssignedResourceIdAcquiresAndCachesToken() throws Exception { + assertTokenAcquisition( + ManagedIdentityId.userAssignedResourceId(USER_ASSIGNED_RESOURCE_ID)); + } + + @Test + void userAssignedObjectIdAcquiresAndCachesToken() throws Exception { + assertTokenAcquisition( + ManagedIdentityId.userAssignedObjectId(USER_ASSIGNED_OBJECT_ID)); + } + + private static void assertTokenAcquisition(ManagedIdentityId identity) + throws Exception { + ManagedIdentityApplication application = + ManagedIdentityApplication.builder(identity).build(); + ManagedIdentityParameters parameters = + ManagedIdentityParameters.builder(ARM_RESOURCE).build(); + + IAuthenticationResult first = + application.acquireTokenForManagedIdentity(parameters).get(); + assertValidResult(first); + assertEquals(TokenSource.IDENTITY_PROVIDER, first.metadata().tokenSource()); + + IAuthenticationResult cached = + application.acquireTokenForManagedIdentity(parameters).get(); + assertValidResult(cached); + assertEquals(TokenSource.CACHE, cached.metadata().tokenSource()); + assertEquals(first.accessToken(), cached.accessToken()); + } + + private static void assertValidResult(IAuthenticationResult result) { + assertNotNull(result); + assertNotNull(result.accessToken()); + assertFalse(result.accessToken().isEmpty()); + } +}