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"); }
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(); }
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); }
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); }