Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void AddToPublicEnvironment(InstanceDiscoveryMetadataEntry entry)
PreferredCache = "login.partner.microsoftonline.cn"
};

InstanceDiscoveryMetadataEntry cloudEntryGermany = new InstanceDiscoveryMetadataEntry()
InstanceDiscoveryMetadataEntry cloudEntryLegacyGermany = new InstanceDiscoveryMetadataEntry()
{
Aliases = new[] { "login.microsoftonline.de" },
PreferredNetwork = "login.microsoftonline.de",
Expand Down Expand Up @@ -79,12 +79,36 @@ void AddToPublicEnvironment(InstanceDiscoveryMetadataEntry entry)
PreferredCache = "login.windows-ppe.net"
};

InstanceDiscoveryMetadataEntry bleuCloudEntry = new InstanceDiscoveryMetadataEntry()
{
Aliases = new[] { "login.sovcloud-identity.fr" },
PreferredNetwork = "login.sovcloud-identity.fr",
PreferredCache = "login.sovcloud-identity.fr"
};

InstanceDiscoveryMetadataEntry delosCloudEntry = new InstanceDiscoveryMetadataEntry()
{
Aliases = new[] { "login.sovcloud-identity.de" },
PreferredNetwork = "login.sovcloud-identity.de",
PreferredCache = "login.sovcloud-identity.de"
};

InstanceDiscoveryMetadataEntry govSGCloudEntry = new InstanceDiscoveryMetadataEntry()
{
Aliases = new[] { "login.sovcloud-identity.sg" },
PreferredNetwork = "login.sovcloud-identity.sg",
PreferredCache = "login.sovcloud-identity.sg"
};

AddToKnownCache(publicCloudEntry);
AddToKnownCache(cloudEntryChina);
AddToKnownCache(cloudEntryGermany);
AddToKnownCache(cloudEntryLegacyGermany);
AddToKnownCache(usGovCloudEntry);
AddToKnownCache(usCloudEntry);
AddToKnownCache(ppeCloudEntry);
AddToKnownCache(bleuCloudEntry);
AddToKnownCache(delosCloudEntry);
AddToKnownCache(govSGCloudEntry);
AddToPublicEnvironment(publicCloudEntry);
}

Expand Down
4 changes: 3 additions & 1 deletion tests/Microsoft.Identity.Test.Common/TestConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ public static HashSet<string> s_scope
public const string SovereignNetworkEnvironmentCN = "login.partner.microsoftonline.cn";
public const string PpeEnvironment = "login.windows-ppe.net";
public const string PpeOrgEnvironment = "login.windows-ppe.org"; //This environment is not known to MSAL or AAD

public const string SovereignNetworkEnvironmentBleu = "login.sovcloud-identity.fr";
public const string SovereignNetworkEnvironmentDelos = "login.sovcloud-identity.de";
public const string SovereignNetworkEnvironmentGovSG = "login.sovcloud-identity.sg";
public const string AuthorityNotKnownCommon = "https://sts.access.edu/" + Common + "/";
public const string AuthorityNotKnownTenanted = "https://sts.access.edu/" + Utid + "/";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,22 @@ public async Task KnownInstanceMetadataIsUpToDateAsync()
}
}

IDictionary<string, InstanceDiscoveryMetadataEntry> expectedMetadata =
IDictionary<string, InstanceDiscoveryMetadataEntry> allKnownMetadata =
KnownMetadataProvider.GetAllEntriesForTest();

// Filter out new sovereign clouds that are not part of the public discovery endpoint responses
// These clouds (Bleu, Delos, GovSG) rely on client-side configuration only
var sovereignCloudsNotInDiscovery = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"login.sovcloud-identity.fr", // Bleu (France)
"login.sovcloud-identity.de", // Delos (Germany)
"login.sovcloud-identity.sg" // GovSG (Singapore)
};

IDictionary<string, InstanceDiscoveryMetadataEntry> expectedMetadata =
allKnownMetadata.Where(kvp => !sovereignCloudsNotInDiscovery.Contains(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

CoreAssert.AssertDictionariesAreEqual(
expectedMetadata,
processedMetadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ namespace Microsoft.Identity.Test.Unit.ApiConfigTests
public class AuthorityTests : TestBase
{
private static readonly Authority s_commonAuthority = Authority.CreateAuthority(TestConstants.AuthorityCommonTenant, true);
private static readonly string s_ppeCommonUri = $@"https://{TestConstants.PpeEnvironment}/{TestConstants.TenantId}";
private static readonly Authority s_ppeAuthority = Authority.CreateAuthority(s_ppeCommonUri, true);
private static readonly string s_ppeOrgCommonUri = $@"https://{TestConstants.PpeOrgEnvironment}/{TestConstants.TenantId}";
private static readonly Authority s_ppeOrgAuthority = Authority.CreateAuthority(s_ppeOrgCommonUri, true);
private static readonly Authority s_utidAuthority = Authority.CreateAuthority(TestConstants.AuthorityUtidTenant, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ public void KnownMetadataProvider_IsKnown()

Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("login.microsoftonline.de"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("LOGIN.microsoftonline.de"));

// New sovereign clouds
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("login.sovcloud-identity.fr"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("LOGIN.sovcloud-identity.fr"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("login.sovcloud-identity.de"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("LOGIN.sovcloud-identity.de"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("login.sovcloud-identity.sg"));
Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("LOGIN.sovcloud-identity.sg"));
}

[TestMethod]
Expand All @@ -136,6 +144,30 @@ public void KnownMetadataProvider_publicEnvironment()
Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("login.microsoft.com"));
Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("login.microsoftonline.com"));
Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("Login.microsoftonline.com"));

// New sovereign clouds should NOT be public environments
Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment("login.sovcloud-identity.fr"));
Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment("login.sovcloud-identity.de"));
Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment("login.sovcloud-identity.sg"));
}

[DataTestMethod]
[DataRow("login.sovcloud-identity.fr")]
[DataRow("login.sovcloud-identity.de")]
[DataRow("login.sovcloud-identity.sg")]
public void KnownMetadataProvider_NewSovereignClouds(string host)
{
// Arrange
KnownMetadataProvider knownMetadataProvider = new KnownMetadataProvider();

// Act
InstanceDiscoveryMetadataEntry result = knownMetadataProvider.GetMetadata(host, null, _logger);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(host, result.PreferredNetwork);
Assert.AreEqual(host, result.PreferredCache);
CollectionAssert.Contains(result.Aliases, host);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,9 @@ public async Task OtherCloud_WithValidation_Async(bool validateAuthority, bool a
[DataRow("login.microsoftonline.us", "login.microsoftonline.us")]
[DataRow("login.usgovcloudapi.net", "login.microsoftonline.us")]
[DataRow("login-us.microsoftonline.com", "login-us.microsoftonline.com")]
[DataRow(TestConstants.SovereignNetworkEnvironmentBleu, TestConstants.SovereignNetworkEnvironmentBleu)]
[DataRow(TestConstants.SovereignNetworkEnvironmentDelos, TestConstants.SovereignNetworkEnvironmentDelos)]
[DataRow(TestConstants.SovereignNetworkEnvironmentGovSG, TestConstants.SovereignNetworkEnvironmentGovSG)]
[DataRow("login.windows.net", "login.microsoft.com")]
[DataRow("login.microsoft.com", "login.microsoft.com")]
[DataRow("sts.windows.net", "login.microsoft.com")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,35 @@ namespace Microsoft.Identity.Test.Unit.PublicApiTests
[TestClass]
public class InstanceDiscoveryTests : TestBase
{
[DataTestMethod]
[DataRow("login.microsoftonline.com", DisplayName = "Public")]
[DataRow("login.microsoftonline.us", DisplayName = "UsGov")]
[DataRow("login.microsoftonline.de", DisplayName = "GermanyLegacy")]
[DataRow("login.partner.microsoftonline.cn", DisplayName = "China")]
[DataRow("login.sovcloud-identity.fr", DisplayName = "Fr")]
[DataRow("login.sovcloud-identity.de", DisplayName = "De")]
[DataRow("login.sovcloud-identity.sg", DisplayName = "Sg")]
public async Task InstanceDiscoveryHappensOnKnownCloud(string discoveryHost)
{
using (var httpManager = new MockHttpManager())
{
var app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
.WithAuthority($"https://{discoveryHost}/tenant")
.WithRedirectUri(TestConstants.RedirectUri)
.WithClientSecret(TestConstants.ClientSecret)
.WithHttpManager(httpManager)
.BuildConcrete();

Uri expectedDiscoveryEndpoint = new Uri($"https://{discoveryHost}/tenant/discovery/instance");
httpManager.AddInstanceDiscoveryMockHandler(customDiscoveryEndpoint: expectedDiscoveryEndpoint);
var handler = httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();
handler.ExpectedUrl = $"https://{discoveryHost}/tenant/oauth2/v2.0/token";

var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

}
}

[TestMethod]
public async Task ConfidentialClientUsingSecretNoInstanceDiscoveryTestAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,12 @@ await app
[DataRow("https://login.microsoftonline.us", TestConstants.Organizations, "Azure Government")]
[DataRow("https://login.partner.microsoftonline.cn", TestConstants.Common, "Azure China")]
[DataRow("https://login.partner.microsoftonline.cn", TestConstants.Organizations, "Azure China")]
[DataRow("https://login.sovcloud-identity.fr", TestConstants.Common, "Azure Sovereign - France Bleu")]
[DataRow("https://login.sovcloud-identity.fr", TestConstants.Organizations, "Azure Sovereign - France Bleu")]
[DataRow("https://login.sovcloud-identity.de", TestConstants.Common, "Azure Sovereign - Germany Delos")]
[DataRow("https://login.sovcloud-identity.de", TestConstants.Organizations, "Azure Sovereign - Germany Delos")]
[DataRow("https://login.sovcloud-identity.sg", TestConstants.Common, "Azure Sovereign - Singapore Gov SG")]
[DataRow("https://login.sovcloud-identity.sg", TestConstants.Organizations, "Azure Sovereign - Singapore Gov SG")]
public async Task MtlsPop_WithUnsupportedNonTenantedAuthorityAsync_ThrowsException(string authorityUrl, string nonTenantValue, string cloudType)
{
const string region = "eastus";
Expand Down Expand Up @@ -666,6 +672,9 @@ public async Task MtlsPop_ValidateExpectedUrlAsync()
[DataRow("login.usgovcloudapi.net", "mtlsauth.microsoftonline.us")]
[DataRow("login.partner.microsoftonline.cn", "mtlsauth.partner.microsoftonline.cn")]
[DataRow("login.chinacloudapi.cn", "mtlsauth.partner.microsoftonline.cn")]
[DataRow("login.sovcloud-identity.fr", "mtlsauth.sovcloud-identity.fr")]
[DataRow("login.sovcloud-identity.de", "mtlsauth.sovcloud-identity.de")]
[DataRow("login.sovcloud-identity.sg", "mtlsauth.sovcloud-identity.sg")]
public async Task PublicAndSovereignCloud_UsesPreferredNetwork_AndNoDiscovery_Async(string inputEnv, string expectedEnv)
{
// Append the input environment to create the authority URL
Expand Down