示例#1
0
        public void ParsingCertificateStoreShouldWork()
        {
            var az      = new Mock <IAzureHelper>();
            var factory = new Mock <IStorageFactory>();

            var log       = new Mock <ILoggerFactory>();
            var kvFactory = new Mock <IKeyVaultFactory>();
            var client    = new Mock <CertificateClient>();

            kvFactory.Setup(x => x.CreateCertificateClient("example"))
            .Returns(client.Object);
            IRenewalOptionLoader parser = new RenewalOptionLoader(
                az.Object,
                kvFactory.Object,
                factory.Object,
                new Mock <IAzureAppServiceClient>().Object,
                new Mock <IAzureCdnClient>().Object,
                log.Object);

            var cfg   = TestHelper.LoadConfig("config");
            var store = parser.ParseCertificateStore(cfg.Certificates[0]);

            store.Type.Should().Be("keyVault");
            store.Name.Should().Be("example");
        }
示例#2
0
        public void ParsingChallengeResponderShouldWorkIfCallerHasMsiAccessToStorage()
        {
            var az      = new Mock <IAzureHelper>();
            var factory = new Mock <IStorageFactory>();
            var storage = new Mock <IStorageProvider>();

            // check is used by parser to verify MSI access
            storage.Setup(x => x.ExistsAsync(RenewalOptionLoader.FileNameForPermissionCheck, It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(false));
            factory.Setup(x => x.FromMsiAsync("example", new StorageProperties().ContainerName, It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(storage.Object));

            var kvFactory = new Mock <IKeyVaultFactory>();
            var client    = new Mock <CertificateClient>();

            kvFactory.Setup(x => x.CreateCertificateClient("example"))
            .Returns(client.Object);
            var log = new Mock <ILoggerFactory>();
            IRenewalOptionLoader parser = new RenewalOptionLoader(
                az.Object,
                kvFactory.Object,
                factory.Object,
                new Mock <IAzureAppServiceClient>().Object,
                new Mock <IAzureCdnClient>().Object,
                log.Object);

            var cfg = TestHelper.LoadConfig("config");

            new Func <Task>(async() => _ = await parser.ParseChallengeResponderAsync(cfg.Certificates[0], CancellationToken.None)).Should().NotThrow();
        }
示例#3
0
        public async Task ParsingChallengeResponderShouldSucceedIfCallerHasNoMsiAccessToStorageButKeyVaultFallbackIsAvailable()
        {
            var az      = new Mock <IAzureHelper>();
            var factory = new Mock <IStorageFactory>();
            var storage = new Mock <IStorageProvider>();

            // check is used by parser to verify MSI access
            storage.Setup(x => x.ExistsAsync(RenewalOptionLoader.FileNameForPermissionCheck, It.IsAny <CancellationToken>()))
            .Throws(new RequestFailedException((int)HttpStatusCode.Forbidden, "Access denied, due to missing MSI permissions"));

            factory.Setup(x => x.FromMsiAsync("example", new StorageProperties().ContainerName, It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(storage.Object));

            var log = new Mock <ILoggerFactory>();

            log.Setup(x => x.CreateLogger(It.IsAny <string>()))
            .Returns(new Mock <ILogger>().Object);
            var kvFactory    = new Mock <IKeyVaultFactory>();
            var client       = new Mock <CertificateClient>();
            var secretClient = new Mock <SecretClient>();
            // fallback is keyvault
            const string connectionString = "this will grant me access";
            var          response         = new Mock <Response <KeyVaultSecret> >();

            response.SetupGet(x => x.Value)
            .Returns(new KeyVaultSecret(new StorageProperties().SecretName, connectionString));
            secretClient.Setup(x => x.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(response.Object);
            kvFactory.Setup(x => x.CreateSecretClient("example"))
            .Returns(secretClient.Object);
            kvFactory.Setup(x => x.CreateCertificateClient("example"))
            .Returns(client.Object);

            // fallback
            factory.Setup(x => x.FromConnectionString(connectionString, new StorageProperties().ContainerName))
            .Returns(storage.Object);
            IRenewalOptionLoader parser = new RenewalOptionLoader(
                az.Object,
                kvFactory.Object,
                factory.Object,
                new Mock <IAzureAppServiceClient>().Object,
                new Mock <IAzureCdnClient>().Object,
                log.Object);

            var cfg = TestHelper.LoadConfig("config");
            var r   = await parser.ParseChallengeResponderAsync(cfg.Certificates[0], CancellationToken.None);

            secretClient.Verify(x => x.GetSecretAsync(new StorageProperties().SecretName, null, CancellationToken.None), Times.Once);
            factory.Verify(x => x.FromConnectionString(connectionString, new StorageProperties().ContainerName), Times.Once);
        }
示例#4
0
        public void ParsingChallengeResponderShouldFailIfCallerHasNoMsiAccessToStorageAndFallbacksAreNotAvailable()
        {
            var az      = new Mock <IAzureHelper>();
            var factory = new Mock <IStorageFactory>();
            var storage = new Mock <IStorageProvider>();

            // check is used by parser to verify MSI access
            storage.Setup(x => x.ExistsAsync(RenewalOptionLoader.FileNameForPermissionCheck, It.IsAny <CancellationToken>()))
            .Throws(new RequestFailedException((int)HttpStatusCode.Forbidden, "Access denied, due to missing MSI permissions"));

            factory.Setup(x => x.FromMsiAsync("example", new StorageProperties().ContainerName, It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(storage.Object));

            var log = new Mock <ILoggerFactory>();

            log.Setup(x => x.CreateLogger(It.IsAny <string>()))
            .Returns(new Mock <ILogger>().Object);
            var kvFactory    = new Mock <IKeyVaultFactory>();
            var client       = new Mock <CertificateClient>();
            var secretClient = new Mock <SecretClient>();

            // fallback is keyvault -> secret not found.
            secretClient.Setup(x => x.GetSecretAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Throws(new RequestFailedException((int)HttpStatusCode.NotFound, "denied"));
            kvFactory.Setup(x => x.CreateSecretClient("example"))
            .Returns(secretClient.Object);
            kvFactory.Setup(x => x.CreateCertificateClient("example"))
            .Returns(client.Object);

            IRenewalOptionLoader parser = new RenewalOptionLoader(
                az.Object,
                kvFactory.Object,
                factory.Object,
                new Mock <IAzureAppServiceClient>().Object,
                new Mock <IAzureCdnClient>().Object,
                log.Object);

            var cfg = TestHelper.LoadConfig("config");

            new Func <Task>(async() => _ = await parser.ParseChallengeResponderAsync(cfg.Certificates[0], CancellationToken.None)).Should().Throw <InvalidOperationException>();

            secretClient.Verify(x => x.GetSecretAsync(new StorageProperties().SecretName, null, CancellationToken.None), Times.Once);
        }
        public async Task LoadingConfigWithCustomStoragePathShouldUseIt()
        {
            IConfigurationProcessor processor = new ConfigurationProcessor();
            var content = File.ReadAllText("Files/config+custompath.json");
            var cfg     = processor.ValidateAndLoad(content);
            var cert    = cfg.Certificates[0];

            cert.HostNames.Should().BeEquivalentTo(new[]
            {
                "example.com", "www.example.com"
            });
            cert.ChallengeResponder.Should().NotBeNull();

            // fake grant MSI access
            var factory = new Mock <IStorageFactory>();
            var storage = new Mock <IStorageProvider>();

            storage.Setup(x => x.ExistsAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(true));
            factory.Setup(x => x.FromMsiAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(storage.Object));

            var kvFactory = new Mock <IKeyVaultFactory>();
            var client    = new Mock <CertificateClient>();

            kvFactory.Setup(x => x.CreateCertificateClient("example"))
            .Returns(client.Object);
            var parser = new RenewalOptionLoader(
                new Mock <IAzureHelper>().Object,
                kvFactory.Object,
                factory.Object,
                new Mock <IAzureAppServiceClient>().Object,
                new Mock <IAzureCdnClient>().Object,
                new Mock <ILoggerFactory>().Object);
            var responder = await parser.ParseChallengeResponderAsync(cert, CancellationToken.None);

            var ctx = new Mock <IChallengeContext>();

            // Certes .Http() extension method internall filters for this type
            ctx.SetupGet(x => x.Type)
            .Returns("http-01");

            ctx.SetupGet(x => x.Token)
            .Returns("fileNAME");
            ctx.SetupGet(x => x.KeyAuthz)
            .Returns("$content");

            var auth = new Mock <IAuthorizationContext>();

            auth.Setup(x => x.Challenges())
            .Returns(Task.FromResult(new[] { ctx.Object }.AsEnumerable()));
            var order = new Mock <IOrderContext>();

            order.Setup(x => x.Authorizations())
            .Returns(Task.FromResult(new[] { auth.Object }.AsEnumerable()));
            _ = await responder.InitiateChallengesAsync(order.Object, CancellationToken.None);

            const string pathPrefix = "not/well-known/";

            storage.Verify(x => x.SetAsync(pathPrefix + "fileNAME", "$content", It.IsAny <CancellationToken>()), Times.Once);
        }