diff --git a/identity-model/src/IdentityModel/Client/DiscoveryCache.cs b/identity-model/src/IdentityModel/Client/DiscoveryCache.cs index d08e68e4..7de256a2 100644 --- a/identity-model/src/IdentityModel/Client/DiscoveryCache.cs +++ b/identity-model/src/IdentityModel/Client/DiscoveryCache.cs @@ -15,7 +15,7 @@ public class DiscoveryCache : IDiscoveryCache private readonly DiscoveryPolicy _policy; private readonly Func _getHttpClient; - private readonly string _authority; + private readonly string? _authority; /// /// Initialize instance of DiscoveryCache with passed authority. @@ -42,6 +42,18 @@ public DiscoveryCache(string authority, Func httpClientFunc, _getHttpClient = httpClientFunc ?? throw new ArgumentNullException(nameof(httpClientFunc)); } + /// + /// Initialize instance of DiscoveryCache without authority - the HttpClient used must have a BaseAddress configured. + /// + /// The HTTP client function which must have a BaseAddress configured. + /// The policy. + public DiscoveryCache(Func httpClientFunc, DiscoveryPolicy? policy = null) + { + _getHttpClient = httpClientFunc ?? throw new ArgumentNullException(nameof(httpClientFunc)); + _policy = policy ?? new DiscoveryPolicy(); + _authority = null; + } + /// /// Frequency to refresh discovery document. Defaults to 24 hours. /// @@ -68,9 +80,17 @@ public Task GetAsync() private async Task GetResponseAsync() { - var result = await _getHttpClient().GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest + var client = _getHttpClient(); + var httpClient = client as HttpClient; + var address = _authority ?? httpClient?.BaseAddress?.AbsoluteUri; + if (address.IsMissing()) + { + throw new InvalidOperationException("DiscoveryCache cannot determine the authority. Either pass the authority in the constructor or pass httpClientFunc which returns an instance of HttpClient with a BaseAddress."); + } + + var result = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest { - Address = _authority, + Address = address, Policy = _policy }).ConfigureAwait(); diff --git a/identity-model/test/IdentityModel.Tests/DiscoveryCacheTests.cs b/identity-model/test/IdentityModel.Tests/DiscoveryCacheTests.cs index 5c69587e..f9f42158 100644 --- a/identity-model/test/IdentityModel.Tests/DiscoveryCacheTests.cs +++ b/identity-model/test/IdentityModel.Tests/DiscoveryCacheTests.cs @@ -41,4 +41,26 @@ public async Task New_initialization_should_work() disco.IsError.ShouldBeFalse(); } + + [Fact] + public async Task New_initialization_without_authority_should_work() + { + var client = new HttpClient(_successHandler) { BaseAddress = new Uri(_authority) }; + var cache = new DiscoveryCache(() => client); + + var disco = await cache.GetAsync(); + + disco.IsError.ShouldBeFalse(); + } + + [Fact] + public async Task New_initialization_with_no_authority_and_client_func_without_base_address_should_throw() + { + var client = new HttpClient(_successHandler); + var cache = new DiscoveryCache(() => client); + + var exception = await Should.ThrowAsync(async () => await cache.GetAsync()); + + exception.Message.ShouldBe("DiscoveryCache cannot determine the authority. Either pass the authority in the constructor or pass httpClientFunc which returns an instance of HttpClient with a BaseAddress."); + } } diff --git a/identity-model/test/IdentityModel.Tests/Verifications/PublicApiVerificationTests.VerifyPublicApi.verified.txt b/identity-model/test/IdentityModel.Tests/Verifications/PublicApiVerificationTests.VerifyPublicApi.verified.txt index 8d7d7f43..43ebff1e 100644 --- a/identity-model/test/IdentityModel.Tests/Verifications/PublicApiVerificationTests.VerifyPublicApi.verified.txt +++ b/identity-model/test/IdentityModel.Tests/Verifications/PublicApiVerificationTests.VerifyPublicApi.verified.txt @@ -791,6 +791,7 @@ namespace Duende.IdentityModel.Client } public class DiscoveryCache : Duende.IdentityModel.Client.IDiscoveryCache { + public DiscoveryCache(System.Func httpClientFunc, Duende.IdentityModel.Client.DiscoveryPolicy? policy = null) { } public DiscoveryCache(string authority, Duende.IdentityModel.Client.DiscoveryPolicy? policy = null) { } public DiscoveryCache(string authority, System.Func httpClientFunc, Duende.IdentityModel.Client.DiscoveryPolicy? policy = null) { } public System.TimeSpan CacheDuration { get; set; }