public async Task Unkown_Client()
        {
            var credential = new ClientCredential
            {
                ClientId = "unknown",
                Secret = "invalid"
            };

            var client = await _validator.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public async Task Invalid_Client_Credentials()
        {
            var credential = new ClientCredential
            {
                ClientId = "codeclient",
                Secret = "invalid"
            };

            var client = await _validator.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public async Task Valid_Single_Secret_Hashed()
        {
            var clientId = "single_secret_hashed_no_expiration";

            var credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "secret"
            };

            var client = await _validatorHashed.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);
        }
        public async Task Valid_Single_Secret_No_Protection()
        {
            var clientId = "single_secret_no_protection_no_expiration";

            var credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "secret"
            };

            var client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);
        }
        public async Task Valid_Multiple_Secrets_No_Protection()
        {
            var clientId = "multiple_secrets_no_protection";

            var credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "secret"
            };

            var client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);

            credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "foobar"
            };

            client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);

            credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "quux"
            };

            client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);

            credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "notexpired"
            };

            client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().NotBeNull();
            client.ClientId.Should().Be(clientId);
        }
        public async Task<Client> ValidateClientCredentialsAsync(ClientCredential credential)
        {
            if (credential == null || credential.ClientId == null || credential.Secret == null)
            {
                throw new InvalidOperationException("credential is null");
            }

            var client = await _clients.FindClientByIdAsync(credential.ClientId);
            if (client == null || client.Enabled == false)
            {
                Logger.Error("Client not found in registry or not enabled: " + credential.ClientId);
                return null;
            }

            if (!ObfuscatingComparer.IsEqual(client.ClientSecret, credential.Secret))
            {
                Logger.Error("Invalid client secret: " + client.ClientId);
                return null;
            }

            Logger.InfoFormat("Client found in registry: {0} / {1}", client.ClientId, client.ClientName);
            return client;
        }
        public void No_Secret_Client_Credentials_No_Secret()
        {
            var credential = new ClientCredential
            {
                ClientId = "no_secret_client"
            };

            Func<Task> act = () => _validatorHashed.ValidateClientCredentialsAsync(credential);

            act.ShouldThrow<InvalidOperationException>();
        }
        public async Task No_Secret_Client_Credentials_Empty_Secret()
        {
            var credential = new ClientCredential
            {
                ClientId = "no_secret_client",
                Secret = ""
            };

            var client = await _validatorHashed.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public void Null_ClientId()
        {
            var credential = new ClientCredential();

            Func<Task> act = () => _validatorHashed.ValidateClientCredentialsAsync(credential);

            act.ShouldThrow<InvalidOperationException>();
        }
        public async Task Disabled_Client()
        {
            var credential = new ClientCredential
            {
                ClientId = "disabled_client",
                Secret = "secret"
            };

            var client = await _validatorHashed.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public async Task Invalid_Multiple_Secrets_Hashed()
        {
            var clientId = "multiple_secrets_hashed";

            var credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "invalid"
            };

            var client = await _validatorHashed.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public async Task Invalid_Multiple_Secrets_No_Protection()
        {
            var clientId = "multiple_secrets_no_protection";

            var credential = new ClientCredential
            {
                ClientId = clientId,
                Secret = "invalid"
            };

            var client = await _validatorPlain.ValidateClientCredentialsAsync(credential);

            client.Should().BeNull();
        }
        public async Task<Client> ValidateClientCredentialsAsync(ClientCredential credential)
        {
            if (credential == null || credential.ClientId == null || credential.Secret == null)
            {
                throw new InvalidOperationException("credential is null");
            }

            var client = await _clients.FindClientByIdAsync(credential.ClientId);
            if (client == null || client.Enabled == false)
            {
                LogError("Client not found in registry or not enabled");
                return null;
            }

            var secretValid = await _secretValidator.ValidateClientSecretAsync(client, credential.Secret);
            if (secretValid == false)
            {
                LogError("Invalid client secret");
                return null;
            }

            return client;
        }