diff --git a/test/Identity.Test/IdentityServer/DynamicClientStoreTests.cs b/test/Identity.Test/IdentityServer/DynamicClientStoreTests.cs new file mode 100644 index 0000000000..b95011e937 --- /dev/null +++ b/test/Identity.Test/IdentityServer/DynamicClientStoreTests.cs @@ -0,0 +1,148 @@ +using Bit.Identity.IdentityServer; +using Duende.IdentityServer.Models; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Xunit; + +namespace Bit.Identity.Test.IdentityServer; + +public class DynamicClientStoreTests +{ + private readonly IServiceCollection _services; + private readonly IClientProvider _apiKeyProvider; + + private readonly Func _sutCreator; + + public DynamicClientStoreTests() + { + _services = new ServiceCollection(); + _apiKeyProvider = Substitute.For(); + + _sutCreator = () => new DynamicClientStore( + _services.BuildServiceProvider(), + _apiKeyProvider, + new StaticClientStore(new Core.Settings.GlobalSettings()) + ); + } + + [Theory] + [InlineData("mobile")] + [InlineData("web")] + [InlineData("browser")] + [InlineData("desktop")] + [InlineData("cli")] + [InlineData("connector")] + public async Task FindClientByIdAsync_StaticClients_Works(string staticClientId) + { + var sut = _sutCreator(); + + var client = await sut.FindClientByIdAsync(staticClientId); + + Assert.NotNull(client); + Assert.Equal(staticClientId, client.ClientId); + } + + [Fact] + public async Task FindClientByIdAsync_SplitName_NoService_ReturnsNull() + { + _services.AddClientProvider("my-provider"); + + var sut = _sutCreator(); + + var client = await sut.FindClientByIdAsync("blah.something"); + + Assert.Null(client); + + await _apiKeyProvider + .Received(0) + .GetAsync(Arg.Any()); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task FindClientByIdAsync_SplitName_HasService_ReturnsValueFromService(bool returnNull) + { + var fakeProvider = Substitute.For(); + + fakeProvider + .GetAsync("something") + .Returns(returnNull ? null : new Client { ClientId = "fake" }); + + _services.AddKeyedSingleton("my-provider", fakeProvider); + + var sut = _sutCreator(); + + var client = await sut.FindClientByIdAsync("my-provider.something"); + + if (returnNull) + { + Assert.Null(client); + } + else + { + Assert.NotNull(client); + } + + await fakeProvider + .Received(1) + .GetAsync("something"); + + await _apiKeyProvider + .Received(0) + .GetAsync(Arg.Any()); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task FindClientByIdAsync_RandomString_NotSplit_TriesApiKey(bool returnsNull) + { + _apiKeyProvider + .GetAsync("random-string") + .Returns(returnsNull ? null : new Client { ClientId = "test" }); + + var sut = _sutCreator(); + + var client = await sut.FindClientByIdAsync("random-string"); + + if (returnsNull) + { + Assert.Null(client); + } + else + { + Assert.NotNull(client); + } + + await _apiKeyProvider + .Received(1) + .GetAsync("random-string"); + } + + [Theory] + [InlineData("id.")] + [InlineData("id. ")] + public async Task FindClientByIdAsync_InvalidIdentifierValue_ReturnsNull(string clientId) + { + var sut = _sutCreator(); + + var client = await sut.FindClientByIdAsync(clientId); + Assert.Null(client); + } + + private class FakeClientProvider : IClientProvider + { + public FakeClientProvider() + { + Fake = Substitute.For(); + } + + public IClientProvider Fake { get; } + + public Task GetAsync(string identifier) + { + return Fake.GetAsync(identifier); + } + } +}