public void AddMsisLookup_GivenMockDisabled_AddsRealClientToCollection()
        {
            // Arrange
            var config = new MsisConfig
            {
                Mock    = false,
                CertId  = "some-cert",
                BaseUrl = "https://msis.api.com/api/v1/"
            };

            var certificate = CertUtils.GenerateTestEccCert();

            var certLocator = new Mock <ICertificateLocator>();

            certLocator
            .Setup(x => x.GetCertificate("some-cert"))
            .Returns(certificate.Some());

            var serviceCollection = new ServiceCollection();

            serviceCollection.AddMemoryCache();
            serviceCollection.AddSingleton(certLocator.Object);

            // Act
            serviceCollection.AddMsisLookup(config);

            // Assert
            var serviceProvider = serviceCollection.BuildServiceProvider();
            var msisClient      = serviceProvider.GetRequiredService <IMsisClient>();

            msisClient.Should().BeOfType <MsisClient>();
            certLocator.Verify();
        }
        public async Task GetSigningCredentialsAsync_ResultIsCached_ReturnsCachedResult()
        {
            //Arrange
            var cert = CertUtils.GenerateTestEccCert();
            var alg  = SecurityAlgorithms.RsaSha256;
            var activeSigningCredentials = new SigningCredentials(new X509SecurityKey(cert), alg);
            IEnumerable <SecurityKeyInfo> enabledValidationKeys = new[]
            {
                new SecurityKeyInfo
                {
                    Key = new X509SecurityKey(cert),
                    SigningAlgorithm = SecurityAlgorithms.RsaSha256
                }
            };
            object cachedResult = (activeSigningCredentials, enabledValidationKeys);

            var automocker = new AutoMocker();

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue("IsOAuthCerts", out cachedResult))
            .Returns(true);

            var target = automocker.CreateInstance <SigningCredentialsStore>();

            //Act
            var result = await target.GetSigningCredentialsAsync();

            //Assert
            result.Should().Be(activeSigningCredentials);
        }
        public async Task GetSigningCredentialsAsync_ResultNotCachedMultipleValidVersions_ReturnsFirstOlderThanRollover()
        {
            //Arrange
            var cert1 = CertUtils.GenerateTestEccCert();
            var cert2 = CertUtils.GenerateTestEccCert();
            var cert3 = CertUtils.GenerateTestEccCert();

            var    rollover     = TimeSpan.FromHours(2);
            var    epsilon      = TimeSpan.FromSeconds(1);
            object cachedResult = null;

            var automocker = new AutoMocker();

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue("IsOAuthCerts", out cachedResult))
            .Returns(false);

            automocker
            .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry("IsOAuthCerts"))
            .Returns(Mock.Of <ICacheEntry>());

            automocker
            .Setup <IOptions <SigningCredentialsStore.Config>, SigningCredentialsStore.Config>(x => x.Value)
            .Returns(new SigningCredentialsStore.Config
            {
                Signing             = "cert-id",
                KeyRolloverDuration = rollover
            });

            automocker
            .Setup <ICertificateLocator, Task <ICollection <CertificateVersion> > >(x =>
                                                                                    x.GetAllEnabledCertificateVersionsAsync("cert-id"))
            .ReturnsAsync(new[]
            {
                new CertificateVersion
                {
                    Certificate = cert1,
                    Timestamp   = DateTime.UtcNow
                },
                new CertificateVersion
                {
                    Certificate = cert2,
                    Timestamp   = DateTime.UtcNow - rollover - epsilon
                },
                new CertificateVersion
                {
                    Certificate = cert3,
                    Timestamp   = DateTime.UtcNow - rollover - epsilon
                }
            });

            var target = automocker.CreateInstance <SigningCredentialsStore>();

            //Act
            var result = await target.GetSigningCredentialsAsync();

            //Assert
            result.Key.Should().BeOfType <X509SecurityKey>();
            ((X509SecurityKey)result.Key).Certificate.Should().Be(cert2);
        }
        public void GetMasterKeyCertificate_CertNotCached_ReturnsFromLocator()
        {
            var options = new MsisClientCertLocator.Config
            {
                CertId = "key-id"
            };
            var    cacheKey          = nameof(MsisClientCertLocator);
            object emptyCachedResult = null;
            var    certificate       = CertUtils.GenerateTestEccCert();

            var automocker = new AutoMocker();

            automocker.SetupOptions(options);

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out emptyCachedResult))
            .Returns(false);

            automocker
            .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(cacheKey))
            .Returns(Mock.Of <ICacheEntry>());

            automocker
            .Setup <ICertificateLocator, Option <X509Certificate2> >(x => x.GetCertificate("key-id"))
            .Returns(certificate.Some());

            var target = automocker.CreateInstance <MsisClientCertLocator>();

            var result = target.GetCertificate();

            result.Should().Be(certificate);
        }
        public async Task GetSigningCredentialsAsync_ResultNotCachedConfigSigningOnly_ReturnsBasedOnCertLocator()
        {
            //Arrange
            var    cert         = CertUtils.GenerateTestEccCert();
            object cachedResult = null;

            var automocker = new AutoMocker();

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue("IsOAuthCerts", out cachedResult))
            .Returns(false);

            automocker
            .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry("IsOAuthCerts"))
            .Returns(Mock.Of <ICacheEntry>());

            automocker
            .Setup <IOptions <SigningCredentialsStore.Config>, SigningCredentialsStore.Config>(x => x.Value)
            .Returns(new SigningCredentialsStore.Config
            {
                Signing = "cert-id"
            });

            automocker
            .Setup <ICertificateLocator, Task <ICollection <CertificateVersion> > >(x =>
                                                                                    x.GetAllEnabledCertificateVersionsAsync("cert-id"))
            .ReturnsAsync(new[]
            {
                new CertificateVersion
                {
                    Certificate = cert,
                    Timestamp   = DateTime.Now
                }
            });

            var target = automocker.CreateInstance <SigningCredentialsStore>();

            //Act
            var result = await target.GetSigningCredentialsAsync();

            //Assert
            result.Key.Should().BeOfType <X509SecurityKey>();
            ((X509SecurityKey)result.Key).Certificate.Should().Be(cert);
        }
        public async Task GetMasterKeyCertificate_GivenEccCertificate_ReturnsPrivateKeyBytes()
        {
            var options = new AnonymousTokensConfig
            {
                MasterKeyCertId = "key-id"
            };

            var eccCert = CertUtils.GenerateTestEccCert();

            var automocker = new AutoMocker();

            automocker.SetupOptions(options);

            automocker
            .Setup <ICertificateLocator, Task <Option <X509Certificate2> > >(x => x.GetCertificateAsync("key-id"))
            .ReturnsAsync(eccCert.Some);

            var target = automocker.CreateInstance <AnonymousTokenMasterKeyLoader>();

            var result = await target.LoadMasterKeyBytes();

            result.Should().NotBeNullOrEmpty();
        }
        public void GetMasterKeyCertificate_CertCached_ReturnsFromCache()
        {
            var options = new MsisClientCertLocator.Config
            {
                CertId = "key-id"
            };
            var    cacheKey     = nameof(MsisClientCertLocator);
            var    certificate  = CertUtils.GenerateTestEccCert();
            object cachedResult = certificate.Some();

            var automocker = new AutoMocker();

            automocker.SetupOptions(options);

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue(cacheKey, out cachedResult))
            .Returns(true);

            var target = automocker.CreateInstance <MsisClientCertLocator>();

            var result = target.GetCertificate();

            result.Should().Be(certificate);
        }
        public async Task GetValidationKeysAsync_ResultNotCachedAdditonalValidationKeys_ReturnsAllVersionsAllCerts()
        {
            //Arrange
            var cert1 = CertUtils.GenerateTestEccCert();
            var cert2 = CertUtils.GenerateTestEccCert();
            var cert3 = CertUtils.GenerateTestEccCert();
            var cert4 = CertUtils.GenerateTestEccCert();

            var    rollover     = TimeSpan.FromHours(2);
            var    epsilon      = TimeSpan.FromSeconds(1);
            object cachedResult = null;

            var automocker = new AutoMocker();

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue("IsOAuthCerts", out cachedResult))
            .Returns(false);

            automocker
            .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry("IsOAuthCerts"))
            .Returns(Mock.Of <ICacheEntry>());

            automocker
            .Setup <IOptions <SigningCredentialsStore.Config>, SigningCredentialsStore.Config>(x => x.Value)
            .Returns(new SigningCredentialsStore.Config
            {
                Signing = "cert-id-1",
                AdditionalValidation = new [] { "cert-id-2" },
                KeyRolloverDuration  = rollover
            });

            automocker
            .Setup <ICertificateLocator, Task <ICollection <CertificateVersion> > >(x =>
                                                                                    x.GetAllEnabledCertificateVersionsAsync("cert-id-1"))
            .ReturnsAsync(new[]
            {
                new CertificateVersion
                {
                    Certificate = cert1,
                    Timestamp   = DateTime.Now
                },
                new CertificateVersion
                {
                    Certificate = cert2,
                    Timestamp   = DateTime.Now - rollover - epsilon
                }
            });

            automocker
            .Setup <ICertificateLocator, Task <ICollection <CertificateVersion> > >(x =>
                                                                                    x.GetAllEnabledCertificateVersionsAsync("cert-id-2"))
            .ReturnsAsync(new[]
            {
                new CertificateVersion
                {
                    Certificate = cert3,
                    Timestamp   = DateTime.Now - rollover - epsilon
                },
                new CertificateVersion
                {
                    Certificate = cert4,
                    Timestamp   = DateTime.Now - rollover - epsilon
                }
            });

            var target = automocker.CreateInstance <SigningCredentialsStore>();

            //Act
            var result = (await target.GetValidationKeysAsync()).ToList();

            //Assert
            result.Count.Should().Be(4);
            result.Select(x => x.Key)
            .OfType <X509SecurityKey>()
            .Select(x => x.Certificate)
            .ToList()
            .Should().Contain(cert1)
            .And.Contain(cert2)
            .And.Contain(cert3)
            .And.Contain(cert4);
        }