public async Task TestInstanceDiscovery_WhenAuthorityIsInvalidButValidationIsNotRequired_ShouldCacheTheProvidedAuthorityAsync() { for (int i = 0; i < 2; i++) // Prepare 2 mock responses { HttpMessageHandlerFactory.AddMockHandler(new MockHttpMessageHandler(TestConstants.DefaultAuthorityHomeTenant) { Method = HttpMethod.Get, Url = $"https://{InstanceDiscovery.DefaultTrustedAuthority}/common/discovery/instance", ResponseMessage = MockHelpers.CreateFailureResponseMessage("{\"error\":\"invalid_instance\"}") }); } CallState callState = new CallState(Guid.NewGuid()); string host = "invalid_instance.example.com"; // ADAL still behaves correctly using developer provided authority var entry = await InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), false, callState).ConfigureAwait(false); Assert.AreEqual(host, entry.PreferredNetwork); // No exception raised, the host is returned as-is Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // 1 mock response is consumed, 1 remaining // Subsequent requests do not result in further authority validation network requests for the process lifetime var entry2 = await InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), false, callState).ConfigureAwait(false); Assert.AreEqual(host, entry2.PreferredNetwork); Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // Still 1 mock response remaining, so no new request was attempted }
public async Task UpdateFromTemplateAsync(CallState callState) { if (!this.updatedFromTemplate) { var authorityUri = new Uri(this.Authority); var host = authorityUri.Host; string path = authorityUri.AbsolutePath.Substring(1); string tenant = path.Substring(0, path.IndexOf("/", StringComparison.Ordinal)); if (this.AuthorityType == AuthorityType.AAD) { var metadata = await InstanceDiscovery.GetMetadataEntryAsync(authorityUri, this.ValidateAuthority, callState).ConfigureAwait(false); host = metadata.PreferredNetwork; // All the endpoints will use this updated host, and it affects future network calls, as desired. // The Authority remains its original host, and will be used in TokenCache later. } else { InstanceDiscovery.AddMetadataEntry(host); } this.AuthorizationUri = InstanceDiscovery.FormatAuthorizeEndpoint(host, tenant); this.DeviceCodeUri = string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/oauth2/devicecode", host, tenant); this.TokenUri = string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/oauth2/token", host, tenant); this.UserRealmUri = EnsureUrlEndsWithForwardSlash(string.Format(CultureInfo.InvariantCulture, "https://{0}/common/userrealm", host)); this.IsTenantless = (string.Compare(tenant, TenantlessTenantName, StringComparison.OrdinalIgnoreCase) == 0); this.SelfSignedJwtAudience = this.TokenUri; this.updatedFromTemplate = true; } }
public void TestInstanceDiscovery_WhenMultipleSimultaneousCallsWithTheSameAuthority_ShouldMakeOnlyOneRequest() { for (int i = 0; i < 2; i++) // Prepare 2 mock responses { HttpMessageHandlerFactory.AddMockHandler(MockHelpers.CreateInstanceDiscoveryMockHandler("https://login.windows.net/common/discovery/instance")); } CallState callState = new CallState(Guid.NewGuid()); string host = "login.windows.net"; Task.WaitAll( // Simulate several simultaneous calls InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), true, callState), InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), true, callState)); Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // 1 mock response is consumed, 1 remaining }
public async Task TestInstanceDiscovery_WhenAuthorityIsValidAndMetadataIsReturned_ShouldCacheAllReturnedAliasesAsync() { string host = "login.windows.net"; for (int i = 0; i < 2; i++) // Prepare 2 mock responses { HttpMessageHandlerFactory.AddMockHandler(new MockHttpMessageHandler(TestConstants.DefaultAuthorityHomeTenant) { Method = HttpMethod.Get, Url = $"https://{host}/common/discovery/instance", ResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent( @"{ ""tenant_discovery_endpoint"" : ""https://login.microsoftonline.com/v1/.well-known/openid-configuration"", ""metadata"": [ { ""preferred_network"": ""login.microsoftonline.com"", ""preferred_cache"": ""login.windows.net"", ""aliases"": [""login.microsoftonline.com"", ""login.windows.net"", ""sts.microsoft.com""] } ] }" ) } }); } CallState callState = new CallState(Guid.NewGuid()); // ADAL still behaves correctly using developer provided authority var entry = await InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), true, callState).ConfigureAwait(false); Assert.AreEqual("login.microsoftonline.com", entry.PreferredNetwork); // No exception raised, the host is returned as-is Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // 1 mock response is consumed, 1 remaining // Subsequent requests do not result in further authority validation network requests for the process lifetime var entry2 = await InstanceDiscovery.GetMetadataEntryAsync(new Uri("https://sts.microsoft.com/tenant"), true, callState).ConfigureAwait(false); Assert.AreEqual("login.microsoftonline.com", entry2.PreferredNetwork); Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // Still 1 mock response remaining, so no new request was attempted }
public async Task TestInstanceDiscovery_WhenAuthorityIsValidButNoMetadataIsReturned_ShouldCacheTheProvidedAuthorityAsync() { string host = "login.windows.net"; // A whitelisted host CallState callState = new CallState(Guid.NewGuid()); for (int i = 0; i < 2; i++) // Prepare 2 mock responses { HttpMessageHandlerFactory.AddMockHandler(MockHelpers.CreateInstanceDiscoveryMockHandler( $"https://{host}/common/discovery/instance", @"{""tenant_discovery_endpoint"":""https://login.microsoftonline.com/tenant/.well-known/openid-configuration""}")); } // ADAL still behaves correctly using developer provided authority var entry = await InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), true, callState).ConfigureAwait(false); Assert.AreEqual(host, entry.PreferredNetwork); // No exception raised, the host is returned as-is Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // 1 mock response is consumed, 1 remaining // Subsequent requests do not result in further authority validation network requests for the process lifetime var entry2 = await InstanceDiscovery.GetMetadataEntryAsync(new Uri($"https://{host}/tenant"), true, callState).ConfigureAwait(false); Assert.AreEqual(host, entry2.PreferredNetwork); Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // Still 1 mock response remaining, so no new request was attempted }