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.GetMetadataEntry(authorityUri, this.ValidateAuthority, callState); 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 async Task TestInstanceDiscovery_WhenAuthorityIsInvalidButValidationIsNotRequired_ShouldCacheTheProvidedAuthority() { 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.GetMetadataEntry(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.GetMetadataEntry(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 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.GetMetadataEntry(new Uri($"https://{host}/tenant"), true, callState), InstanceDiscovery.GetMetadataEntry(new Uri($"https://{host}/tenant"), true, callState)); Assert.AreEqual(1, HttpMessageHandlerFactory.MockHandlersCount()); // 1 mock response is consumed, 1 remaining }
public async Task TestInstanceDiscovery_WhenAuthorityIsValidAndMetadataIsReturned_ShouldCacheAllReturnedAliases() { 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.GetMetadataEntry(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.GetMetadataEntry(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_ShouldCacheTheProvidedAuthority() { 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.GetMetadataEntry(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.GetMetadataEntry(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 }
protected AcquireTokenHandlerBase(RequestData requestData) { this.Authenticator = requestData.Authenticator; this.CallState = CreateCallState(this.Authenticator.CorrelationId); brokerHelper.CallState = this.CallState; var msg = string.Format(CultureInfo.CurrentCulture, "ADAL {0} with assembly version '{1}', file version '{2}' and informational version '{3}' is running...", platformInformation.GetProductName(), AdalIdHelper.GetAdalVersion(), AdalIdHelper.GetAssemblyFileVersion(), AdalIdHelper.GetAssemblyInformationalVersion()); CallState.Logger.Information(null, msg); CallState.Logger.InformationPii(null, msg); msg = string.Format(CultureInfo.CurrentCulture, "=== Token Acquisition started: \n\tCacheType: {0}\n\tAuthentication Target: {1}\n\t", tokenCache != null ? tokenCache.GetType().FullName + string.Format(CultureInfo.CurrentCulture, " ({0} items)", tokenCache.Count) : "null", requestData.SubjectType); if (InstanceDiscovery.IsWhitelisted(requestData.Authenticator.GetAuthorityHost())) { msg += string.Format(CultureInfo.CurrentCulture, ", Authority Host: {0}", requestData.Authenticator.GetAuthorityHost()); } CallState.Logger.Information(CallState, msg); var piiMsg = string.Format(CultureInfo.CurrentCulture, "=== Token Acquisition started:\n\tAuthority: {0}\n\tResource: {1}\n\tClientId: {2}\n\tCacheType: {3}\n\tAuthentication Target: {4}\n\t", requestData.Authenticator.Authority, requestData.Resource, requestData.ClientKey.ClientId, (tokenCache != null) ? tokenCache.GetType().FullName + string.Format(CultureInfo.CurrentCulture, " ({0} items)", tokenCache.Count) : "null", requestData.SubjectType); CallState.Logger.InformationPii(this.CallState, piiMsg); this.tokenCache = requestData.TokenCache; if (string.IsNullOrWhiteSpace(requestData.Resource)) { throw new ArgumentNullException("resource"); } this.Resource = (requestData.Resource != NullResource) ? requestData.Resource : null; this.ClientKey = requestData.ClientKey; this.TokenSubjectType = requestData.SubjectType; this.LoadFromCache = (tokenCache != null); this.StoreToCache = (tokenCache != null); this.SupportADFS = false; this.brokerParameters = new Dictionary <string, string>(); brokerParameters[BrokerParameter.Authority] = requestData.Authenticator.Authority; brokerParameters[BrokerParameter.Resource] = requestData.Resource; brokerParameters[BrokerParameter.ClientId] = requestData.ClientKey.ClientId; brokerParameters[BrokerParameter.CorrelationId] = this.CallState.CorrelationId.ToString(); var adalVersion = AdalIdHelper.GetAdalVersion(); if (AdalIdHelper.VersionNotDetermined.Equals(adalVersion)) { adalVersion = AdalIdHelper.GetAssemblyFileVersion(); } brokerParameters[BrokerParameter.ClientVersion] = adalVersion; this.ResultEx = null; CacheQueryData.ExtendedLifeTimeEnabled = requestData.ExtendedLifeTimeEnabled; }