Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public async Task AcquireTokenToRegionalEndpointAsync(bool instanceDiscoveryEnab
{
// Arrange
var factory = new HttpSnifferClientFactory();
var settings = ConfidentialAppSettings.GetSettings(Cloud.PublicLegacy); // Use legacy config for regional tests
var settings = ConfidentialAppSettings.GetSettings(Cloud.PublicLegacy); // Use legacy config for regional tests
settings.InstanceDiscoveryEndpoint = instanceDiscoveryEnabled;
_confidentialClientApplication = BuildCCA(settings, factory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Collections.Generic;
using Microsoft.Identity.Test.Integration.NetFx.Infrastructure;

namespace Microsoft.Identity.Test.Integration.NetCore.HeadlessTests
namespace Microsoft.Identity.Test.Integration.HeadlessTests
{
/// <summary>
/// The tests in this file are demonstrations of the various authentication flows outlined in the "FMI protocol spec v1.0" Section 3.2
Expand All @@ -26,28 +27,28 @@ namespace Microsoft.Identity.Test.Integration.NetCore.HeadlessTests
public class FmiIntegrationTests
{
private byte[] _serializedCache;
private const string Testslice = "dc=ESTSR-PUB-WUS-LZ1-TEST"; //Updated slice for regional tests
private Dictionary<string, (string, bool)> TestsliceQueryParam = new Dictionary<string, (string value, bool includeInCacheKey)> { { "dc", ("ESTSR-PUB-WUS-LZ1-TEST", false) } };
private const string AzureRegion = "westus3";
private const string TenantId = "f645ad92-e38d-4d1a-b510-d1b09a74a8ca"; // MSIDLAB4 tenant (legacy)

private const string TenantId = ConfidentialAppSettings.ID4SLab1TenantId;
private const string RmaClientId = "3bf56293-fbb5-42bd-a407-248ba7431a8c";
private const string WebApiScope = "api://aa464f73-2868-4f67-b0e7-fc2f749e757f/.default";
private const string ExpectedResourceAudience = "api://aa464f73-2868-4f67-b0e7-fc2f749e757f";
private const string ExpectedFmiCredentialAudience = "a9dd8a2a-df54-4ae0-84f9-38c8d57e5265";

[TestMethod]
//RMA getting FMI cred for a leaf entity or sub-RMA
public async Task Flow1_Credential_From_Cert()
{
//Arrange
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);

//Fmi app/scenario parameters
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
//Fmi app/scenario parameters
var scope = "api://AzureFMITokenExchange/.default";

//Act
//Create application
var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.Create(RmaClientId)
.WithAuthority("https://login.microsoftonline.com/", TenantId)
.WithExtraQueryParameters(TestsliceQueryParam) //Enables MSAL to target ESTS Test slice
.WithCertificate(cert, sendX5C: true) //sendX5c enables SN+I auth which is required for FMI flows
.WithAzureRegion(AzureRegion)
.BuildConcrete();
Expand All @@ -58,7 +59,7 @@ public async Task Flow1_Credential_From_Cert()

//Recording test data for Asserts
string expectedFmiPathHash = "zm2n0E62zwTsnNsozptLsoOoB_C7i-GfpxHYQQINJUw";
var expectedExternalCacheKey = $"{clientId}_{TenantId}_{expectedFmiPathHash}_AppTokenCache"; // last part is the SHA256 of the fmi path
var expectedExternalCacheKey = $"{RmaClientId}_{TenantId}_{expectedFmiPathHash}_AppTokenCache"; // last part is the SHA256 of the fmi path
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(
(args) => Assert.AreEqual(args.SuggestedCacheKey, expectedExternalCacheKey));

Expand All @@ -69,11 +70,11 @@ public async Task Flow1_Credential_From_Cert()
.ConfigureAwait(false);

//Assert
var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{clientId}-{TenantId}-{scope}-{expectedFmiPathHash}".ToLowerInvariant();
var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{RmaClientId}-{TenantId}-{scope}-{expectedFmiPathHash}".ToLowerInvariant();
AssertResults(authResult,
confidentialApp,
expectedInternalCacheKey,
"a9dd8a2a-df54-4ae0-84f9-38c8d57e5265",
ExpectedFmiCredentialAudience,
"SomeFmiPath/FmiCredentialPath");
}

Expand All @@ -84,15 +85,10 @@ public async Task Flow2_Token_From_CertTest()
//Arrange
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);

//Fmi app/scenario parameters
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
var scope = "3091264c-7afb-45d4-b527-39737ee86187/.default";

//Act
var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.Create(RmaClientId)
.WithAuthority("https://login.microsoftonline.com/", TenantId)
.WithExtraQueryParameters(TestsliceQueryParam)
.WithCertificate(cert, sendX5C: true)
.WithAzureRegion(AzureRegion)
.BuildConcrete();
Expand All @@ -102,20 +98,20 @@ public async Task Flow2_Token_From_CertTest()

//Recording test data for Asserts
string expectedFmiPathHash = "zm2n0E62zwTsnNsozptLsoOoB_C7i-GfpxHYQQINJUw";
var expectedExternalCacheKey = $"{clientId}_{TenantId}_{expectedFmiPathHash}_AppTokenCache";
var expectedExternalCacheKey = $"{RmaClientId}_{TenantId}_{expectedFmiPathHash}_AppTokenCache";
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(
(args) => Assert.AreEqual(args.SuggestedCacheKey, expectedExternalCacheKey));

var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
var authResult = await confidentialApp.AcquireTokenForClient(new[] { WebApiScope })
.WithFmiPath("SomeFmiPath/FmiCredentialPath")
.ExecuteAsync()
.ConfigureAwait(false);

var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{clientId}-{TenantId}-{scope}-{expectedFmiPathHash}".ToLowerInvariant();
var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{RmaClientId}-{TenantId}-{WebApiScope}-{expectedFmiPathHash}".ToLowerInvariant();
AssertResults(authResult,
confidentialApp,
expectedInternalCacheKey,
"3091264c-7afb-45d4-b527-39737ee86187",
ExpectedResourceAudience,
"SomeFmiPath/FmiCredentialPath");
}

Expand All @@ -130,10 +126,9 @@ public async Task Flow3_FmiCredential_From_AnotherFmiCredential()
var scope = "api://AzureFMITokenExchange/.default";

var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.Create("urn:microsoft:identity:fmi")
.WithAuthority("https://login.microsoftonline.com/", TenantId)
.WithExtraQueryParameters(TestsliceQueryParam)
.WithClientAssertion((options) => GetFmiCredentialFromRma(options, Testslice))
.WithClientAssertion((options) => GetFmiCredentialFromRma(options))
.WithAzureRegion(AzureRegion)
.BuildConcrete();

Expand All @@ -155,7 +150,7 @@ public async Task Flow3_FmiCredential_From_AnotherFmiCredential()
AssertResults(authResult,
confidentialApp,
expectedInternalCacheKey,
"a9dd8a2a-df54-4ae0-84f9-38c8d57e5265",
ExpectedFmiCredentialAudience,
"SomeFmiPath/Path");
}

Expand All @@ -173,8 +168,7 @@ public async Task Flow4_SubRma_FIC_From_FmiCredential()
var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority("https://login.microsoftonline.com/", TenantId)
.WithExtraQueryParameters(TestsliceQueryParam)
.WithClientAssertion((options) => GetFmiCredentialFromRma(options, Testslice))
.WithClientAssertion((options) => GetFmiCredentialFromRma(options))
.WithAzureRegion(AzureRegion)
.BuildConcrete();

Expand All @@ -196,7 +190,7 @@ public async Task Flow4_SubRma_FIC_From_FmiCredential()
AssertResults(authResult,
confidentialApp,
expectedInternalCacheKey,
"3091264c-7afb-45d4-b527-39737ee86187",
ExpectedResourceAudience,
"SomeFmiPath/Path");
}

Expand All @@ -207,14 +201,12 @@ public async Task Flow5_FmiToken_From_FmiCred()
//Arrange
X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);

var clientId = "urn:microsoft:identity:fmi";
var scope = "3091264c-7afb-45d4-b527-39737ee86187/.default";
var clientId = "urn:microsoft:identity:fmi";

var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority("https://login.microsoftonline.com/", TenantId)
.WithExtraQueryParameters(TestsliceQueryParam)
.WithClientAssertion((options) => GetFmiCredentialFromRma(options, Testslice))
.WithClientAssertion((options) => GetFmiCredentialFromRma(options))
.WithAzureRegion(AzureRegion)
.BuildConcrete();

Expand All @@ -227,37 +219,34 @@ public async Task Flow5_FmiToken_From_FmiCred()
var appCacheAccess = confidentialApp.AppTokenCache.RecordAccess(
(args) => Assert.AreEqual(args.SuggestedCacheKey, expectedExternalCacheKey));

var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
var authResult = await confidentialApp.AcquireTokenForClient(new[] { WebApiScope })
.WithFmiPath("SomeFmiPath/Path")
.ExecuteAsync()
.ConfigureAwait(false);

var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{clientId}-{TenantId}-{scope}-{expectedFmiPathHash}".ToLowerInvariant();
var expectedInternalCacheKey = $"-login.microsoftonline.com-atext-{clientId}-{TenantId}-{WebApiScope}-{expectedFmiPathHash}".ToLowerInvariant();
AssertResults(authResult,
confidentialApp,
expectedInternalCacheKey,
"3091264c-7afb-45d4-b527-39737ee86187",
ExpectedResourceAudience,
"SomeFmiPath/Path");
}

private static async Task<string> GetFmiCredentialFromRma(AssertionRequestOptions options, string eqParameters)
private static async Task<string> GetFmiCredentialFromRma(AssertionRequestOptions options)
{
//Fmi app/scenario parameters
var clientId = "4df2cbbb-8612-49c1-87c8-f334d6d065ad";
var scope = "api://AzureFMITokenExchange/.default";

X509Certificate2 cert = CertificateHelper.FindCertificateByName(TestConstants.AutomationTestCertName);

#pragma warning disable CS0618 // Type or member is obsolete
//Create application
var confidentialApp = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca", true)
.WithExtraQueryParameters(eqParameters) //Enables MSAL to target ESTS Test slice
.WithCertificate(cert, sendX5C: true) //sendX5c enables SN+I auth which is required for FMI flows
.WithAzureRegion(AzureRegion)
.BuildConcrete();
#pragma warning restore CS0618 // Type or member is obsolete

//Acquire Token
var authResult = await confidentialApp.AcquireTokenForClient(new[] { scope })
Expand Down Expand Up @@ -292,6 +281,10 @@ private void AssertResults(
var token = confidentialApp.AppTokenCacheInternal.Accessor.GetAllAccessTokens().First();

Assert.IsNotNull(authResult);
if (audience.EndsWith("/.default"))
{
audience = audience.Substring(0, audience.Length - "/.default".Length);
}
Assert.AreEqual(expectedAudience, audience);
Assert.IsTrue(subject.Contains(expectedFmiPath));
Assert.AreEqual(expectedInternalCacheKey, token.CacheKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ public interface IConfidentialAppSettings

public class ConfidentialAppSettings
{
public const string ID4SLab1TenantId = "10c419d4-4a50-45b2-aa4e-919fb84df24f";

private class PublicCloudConfidentialAppSettings : IConfidentialAppSettings
{
// TODO: Tenant Migration - Migrated to new id4slab1 tenant for non-regional tests
// Regional tests still use legacy configuration due to AADSTS100007 restrictions
public string ClientId => UseAppIdUri? "api://54a2d933-8bf8-483b-a8f8-0a31924f3c1f" : "54a2d933-8bf8-483b-a8f8-0a31924f3c1f"; // MSAL-APP-AzureADMultipleOrgs in ID4SLAB1 tenant

public string TenantId => "10c419d4-4a50-45b2-aa4e-919fb84df24f"; // ID4SLAB1 tenant
public string TenantId => ID4SLab1TenantId;

public string Environment => "login.microsoftonline.com";

Expand Down