Пример #1
0
        public async Task AuthorizedRoute_WithCertificateAuthentication_ShouldFailWithUnauthorized_WhenClientCertificateSubjectNameDoesntMatch()
        {
            // Arrange
            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithSubject("unrecognized-subject-name"))
            {
                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.SecretProvider, SubjectKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(SubjectKey, "CN=subject"))
                    .AddClientCertificate(clientCertificate)
                    .AddSingleton(certificateValidator);
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(CertificateAuthenticationOnMethodController.AuthorizedGetRoute);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Arrange
                        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                    }
                }
            }
        }
Пример #2
0
        public async Task CertificateAuthorizedRoute_WithBypassAttribute_SkipsAuthentication(string route)
        {
            // Arrange
            const string issuerKey = "issuer";

            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithIssuerAndSubjectName("issuer", "subject"))
            {
                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithIssuer(X509ValidationLocation.SecretProvider, issuerKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(issuerKey, "CN=issuer"))
                    .AddClientCertificate(clientCertificate)
                    .AddSingleton(certificateValidator)
                    .AddMvc(opt => opt.Filters.AddCertificateAuthentication());
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(route);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    }
                }
            }
        }
Пример #3
0
        public async Task AuthorizedRoute_WithCertificateAuthentication_ShouldFailOnInvalidBase64Format()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services =>
            {
                var certificateValidator =
                    new CertificateAuthenticationValidator(
                        new CertificateAuthenticationConfigBuilder()
                        .Build());

                services.AddSingleton(certificateValidator)
                .AddMvc(opt => opt.Filters.AddCertificateAuthentication());
            });

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(NoneAuthenticationController.GetRoute)
                              .WithHeader("X-ARR-ClientCert", "something not even close to an client certificate export");

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                }
            }
        }
Пример #4
0
        public async Task AuthorizedRoute_WithCertificateAuthenticationViaConfiguration_ShouldFailWithUnauthorized_WhenAnyClientCertificateValidationDoesntSucceeds(
            string subjectName,
            string issuerName,
            string thumbprintNoise,
            bool expected)
        {
            // Arrange
            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithIssuerAndSubjectName(issuerName, subjectName))
            {
                var options = new TestApiServerOptions()
                              .ConfigureAppConfiguration(config => config.AddInMemoryCollection(new []
                {
                    new KeyValuePair <string, string>(SubjectKey, "CN=subject"),
                    new KeyValuePair <string, string>(IssuerKey, "CN=issuer"),
                    new KeyValuePair <string, string>(ThumbprintKey, clientCertificate.Thumbprint + thumbprintNoise)
                }))
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.Configuration, SubjectKey)
                            .WithIssuer(X509ValidationLocation.Configuration, IssuerKey)
                            .WithThumbprint(X509ValidationLocation.Configuration, ThumbprintKey)
                            .Build());

                    services.AddSingleton(certificateValidator)
                    .AddClientCertificate(clientCertificate);
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(CertificateAuthenticationOnMethodController.AuthorizedGetRoute);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.True(
                            (HttpStatusCode.Unauthorized == response.StatusCode) == expected,
                            $"Response HTTP status code {(expected ? "should" : "shouldn't")} be 'Unauthorized' but was '{response.StatusCode}'");
                    }
                }
            }
        }
Пример #5
0
        public async Task AuthorizedRoute_WithCertificateAuthenticationViaConfigurationAndSecretProvider_ShouldFailWithUnauthorized_WhenAnyClientCertificateValidationDoesntSucceeds(
            string subjectValue,
            string issuerValue,
            bool expected)
        {
            // Arrange
            const string subjectKey = "subject", issuerKey = "issuer";

            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithIssuerAndSubjectName(issuerValue, subjectValue))
            {
                var options = new TestApiServerOptions()
                              .ConfigureAppConfiguration(config => config.AddInMemoryCollection(new []
                {
                    new KeyValuePair <string, string>(subjectKey, "CN=known-subject")
                }))
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.Configuration, subjectKey)
                            .WithIssuer(X509ValidationLocation.SecretProvider, issuerKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(issuerKey, "CN=known-issuername"))
                    .AddClientCertificate(clientCertificate)
                    .AddSingleton(certificateValidator)
                    .AddMvc(opt => opt.Filters.AddCertificateAuthentication());
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(NoneAuthenticationController.GetRoute);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.True(
                            (HttpStatusCode.Unauthorized == response.StatusCode) == expected,
                            $"Response HTTP status code {(expected ? "should" : "shouldn't")} be 'Unauthorized' but was '{response.StatusCode}'");
                    }
                }
            }
        }
Пример #6
0
        public async Task AuthorizedRoute_WithCertificateAuthenticationInHeader_ShouldSucceed()
        {
            // Arrange
            const string subjectKey = "subject", issuerKey = "issuer";

            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithIssuerAndSubjectName("known-issuername", "known-subject"))
            {
                var options = new TestApiServerOptions()
                              .ConfigureAppConfiguration(config => config.AddInMemoryCollection(new []
                {
                    new KeyValuePair <string, string>(subjectKey, "CN=known-subject")
                }))
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.Configuration, subjectKey)
                            .WithIssuer(X509ValidationLocation.SecretProvider, issuerKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(issuerKey, "CN=known-issuername"))
                    .AddSingleton(certificateValidator)
                    .AddMvc(opt => opt.Filters.AddCertificateAuthentication());
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    string base64String = Convert.ToBase64String(clientCertificate.Export(X509ContentType.Pkcs12), Base64FormattingOptions.None);
                    var    request      = HttpRequestBuilder
                                          .Get(NoneAuthenticationController.GetRoute)
                                          .WithHeader("X-ARR-ClientCert", base64String);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.NotEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    }
                }
            }
        }
Пример #7
0
        public async Task SharedAccessKeyAuthorizedRoute_EmitsSecurityEventsWhenRequested_RunsAuthentication(bool emitsSecurityEvents)
        {
            // Arrange
            const string issuerKey = "issuer";
            var          spySink   = new InMemorySink();
            var          options   = new TestApiServerOptions()
                                     .ConfigureServices(services =>
            {
                var certificateValidator =
                    new CertificateAuthenticationValidator(
                        new CertificateAuthenticationConfigBuilder()
                        .WithIssuer(X509ValidationLocation.SecretProvider, issuerKey)
                        .Build());

                services.AddSecretStore(stores => stores.AddInMemory(issuerKey, "CN=issuer"))
                .AddSingleton(certificateValidator)
                .AddMvc(opt => opt.Filters.AddCertificateAuthentication(authOptions =>
                {
                    authOptions.EmitSecurityEvents = emitsSecurityEvents;
                }));
            })
                                     .ConfigureHost(host => host.UseSerilog((context, config) => config.WriteTo.Sink(spySink)));

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder.Get(NoneAuthenticationController.GetRoute);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                    IEnumerable <LogEvent> logEvents = spySink.DequeueLogEvents();
                    Assert.True(emitsSecurityEvents == logEvents.Any(logEvent =>
                    {
                        string message = logEvent.RenderMessage();
                        return(message.Contains("EventType") && message.Contains("Security"));
                    }));
                }
            }
        }
Пример #8
0
        public async Task CertificateAuthorizedRoute_EmitsSecurityEventsWhenRequested_RunsAuthentication()
        {
            // Arrange
            using (X509Certificate2 clientCertificate = SelfSignedCertificate.CreateWithSubject("unrecognized-subject-name"))
            {
                var spySink = new InMemorySink();
                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.SecretProvider, SubjectKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(SubjectKey, "CN=subject"))
                    .AddClientCertificate(clientCertificate)
                    .AddSingleton(certificateValidator);
                })
                              .ConfigureHost(host => host.UseSerilog((context, config) => config.WriteTo.Sink(spySink)));

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(CertificateAuthenticationOnMethodController.AuthorizedGetRouteEmitSecurityEvents);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                        IEnumerable <LogEvent> logEvents = spySink.DequeueLogEvents();
                        Assert.Contains(logEvents, logEvent =>
                        {
                            string message = logEvent.RenderMessage();
                            return(message.Contains("EventType") && message.Contains("Security"));
                        });
                    }
                }
            }
        }
Пример #9
0
        public async Task AuthorizedRoute_WithCertificateAuthentication_ShouldFailWithUnauthorized_WhenClientCertificateThumbprintDoesntMatch(
            string thumbprintNoise,
            bool expected)
        {
            // Arrange
            using (X509Certificate2 clientCertificate = SelfSignedCertificate.Create())
            {
                const string thumbprintKey = "thumbprint";

                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithThumbprint(X509ValidationLocation.SecretProvider, thumbprintKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(thumbprintKey, clientCertificate.Thumbprint + thumbprintNoise))
                    .AddSingleton(certificateValidator)
                    .AddClientCertificate(clientCertificate)
                    .AddMvc(opt => opt.Filters.AddCertificateAuthentication());
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    var request = HttpRequestBuilder.Get(NoneAuthenticationController.GetRoute);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Assert
                        Assert.True(
                            (HttpStatusCode.Unauthorized == response.StatusCode) == expected,
                            $"Response HTTP status code {(expected ? "should" : "shouldn't")} be 'Unauthorized' but was '{response.StatusCode}'");
                    }
                }
            }
        }
Пример #10
0
        public async Task AuthorizedRoute_WithCertificateAuthenticationOnAppServiceHeader_ShouldSucceeds_WhenClientCertificateSubjectNameMatches(string actualSubject)
        {
            // Arrange
            const string expectedSubject = "known-subject";

            using (var cert = SelfSignedCertificate.CreateWithSubject(expectedSubject))
            {
                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    var certificateValidator =
                        new CertificateAuthenticationValidator(
                            new CertificateAuthenticationConfigBuilder()
                            .WithSubject(X509ValidationLocation.SecretProvider, SubjectKey)
                            .Build());

                    services.AddSecretStore(stores => stores.AddInMemory(SubjectKey, $"CN={actualSubject}"))
                    .AddSingleton(certificateValidator);
                });

                await using (var server = await TestApiServer.StartNewAsync(options, _logger))
                {
                    string clientCertificate = Convert.ToBase64String(cert.RawData);
                    var    request           = HttpRequestBuilder
                                               .Get(CertificateAuthenticationOnMethodController.AuthorizedGetRoute)
                                               .WithHeader("X-ARR-ClientCert", clientCertificate);

                    // Act
                    using (HttpResponseMessage response = await server.SendAsync(request))
                    {
                        // Arrange
                        bool equalSubject   = expectedSubject == actualSubject;
                        bool isUnauthorized = response.StatusCode == HttpStatusCode.Unauthorized;
                        Assert.True(equalSubject != isUnauthorized, "Client certificate with the same subject name should result in an OK HTTP status code");
                    }
                }
            }
        }