public async Task SharedAccessKeyAuthorizedRoute_DoesntEmitSecurityEventsByDefault_RunsAuthentication()
        {
            // Arrange
            var spySink = new InMemorySink();
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddSecretStore(stores => stores.AddInMemory(SecretName, $"secret-{Guid.NewGuid()}")))
                          .ConfigureHost(host => host.UseSerilog((context, config) =>
                                                                 config.WriteTo.Sink(spySink)));

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

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                    IEnumerable <LogEvent> logEvents = spySink.DequeueLogEvents();
                    Assert.DoesNotContain(logEvents, logEvent =>
                    {
                        string message = logEvent.RenderMessage();
                        return(message.Contains("EventType") && message.Contains("Security"));
                    });
                }
            }
        }
        public async Task SendRequest_WithSerilogCorrelationEnrichment_ReturnsOkWithEnrichedCorrelationLogProperties()
        {
            // Arrange
            var spySink = new InMemorySink();
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddHttpCorrelation())
                          .PreConfigure(app => app.UseHttpCorrelation())
                          .ConfigureHost(host => host.UseSerilog((context, serviceProvider, config) =>
                                                                 config.Enrich.WithHttpCorrelationInfo(serviceProvider)
                                                                 .WriteTo.Sink(spySink)));

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

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    CorrelationInfo correlationInfo = await AssertAppCorrelationInfoAsync(response);

                    AssertLoggedCorrelationProperties(spySink, correlationInfo);
                }
            }
        }
예제 #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);
                }
            }
        }
        public async Task GetHealthWithCorrectBearerToken_WithAzureManagedIdentityAuthorization_ReturnsOk()
        {
            // Arrange
            string issuer     = _bogusGenerator.Internet.Url();
            string authority  = _bogusGenerator.Internet.Url();
            string privateKey = GenerateRandomPrivateKey();

            await using (var testOpenIdServer = await TestOpenIdServer.StartNewAsync(_logger))
            {
                var options = new TestApiServerOptions()
                              .ConfigureServices(services =>
                {
                    TokenValidationParameters tokenValidationParameters = testOpenIdServer.GenerateTokenValidationParametersWithValidAudience(issuer, authority, privateKey);
                    var reader = new JwtTokenReader(tokenValidationParameters, testOpenIdServer.OpenIdAddressConfiguration);
                    services.AddMvc(opt => opt.Filters.AddJwtTokenAuthorization(jwt => jwt.JwtTokenReader = reader));
                });

                await using (var testApiServer = await TestApiServer.StartNewAsync(options, _logger))
                {
                    string accessToken = testOpenIdServer.RequestSecretToken(issuer, authority, privateKey, daysValid: 7);
                    var    request     = HttpRequestBuilder
                                         .Get(HealthController.GetRoute)
                                         .WithHeader(JwtTokenAuthorizationOptions.DefaultHeaderName, accessToken);

                    // Act
                    using (HttpResponseMessage response = await testApiServer.SendAsync(request))
                    {
                        // Assert
                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    }
                }
            }
        }
        public async Task IncomingText_WithoutOnlyAllowJsonFormatting_Succeeds()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddMvc(opt =>
            {
                opt.InputFormatters.Add(new PlainTextInputFormatter());
            }));

            string sentence = BogusGenerator.Lorem.Sentence();

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(CountryController.GetPlainTextRoute)
                              .WithTextBody(sentence);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Equal("text/plain", response.Content.Headers.ContentType.MediaType);
                    string actual = await response.Content.ReadAsStringAsync();

                    Assert.Equal(sentence, actual);
                }
            }
        }
        public async Task IncomingModel_WithConfigureJsonFormattingOnEnums_SerializeAsStrings()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddMvc(mvcOptions =>
            {
                mvcOptions.ConfigureJsonFormatting(jsonOptions => jsonOptions.Converters.Add(new JsonStringEnumConverter()));
            }));

            var country = new Country
            {
                Name = BogusGenerator.Address.Country(),
                Code = BogusGenerator.Random.Enum <CountryCode>()
            };

            string json = JsonSerializer.Serialize(country);

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(CountryController.GetJsonRoute)
                              .WithJsonBody(json);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    string actual = await response.Content.ReadAsStringAsync();

                    Assert.Contains(country.Code.ToString(), actual);
                }
            }
        }
        public async Task SharedAccessKeyAuthorizedRoute_EmitsSecurityEventsWhenRequested_RunsAuthentication(bool emitsSecurityEvents)
        {
            // Arrange
            var spySink = new InMemorySink();
            var options = new TestApiServerOptions()
                          .ConfigureServices(services =>
            {
                services.AddSecretStore(stores => stores.AddInMemory(SecretName, $"secret-{Guid.NewGuid()}"))
                .AddMvc(opt => opt.Filters.AddSharedAccessKeyAuthenticationOnHeader(HeaderName, SecretName, 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(HealthController.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"));
                    }));
                }
            }
        }
        public async Task IncomingText_WithOnlyAllowJsonFormatting_Fails()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddMvc(opt =>
            {
                opt.InputFormatters.Add(new PlainTextInputFormatter());
                opt.OnlyAllowJsonFormatting();
            }));

            string sentence = BogusGenerator.Lorem.Sentence();

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(CountryController.GetPlainTextRoute)
                              .WithTextBody(sentence);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.UnsupportedMediaType, response.StatusCode);
                }
            }
        }
        public async Task SendRequest_WithCorrelateOptionsUpstreamServiceCustomOperationParentIHeaderName_UsesUpstreamOperationId(bool extractFromRequest)
        {
            // Arrange
            var operationId                 = Guid.NewGuid().ToString();
            var operationParentId           = $"|{operationId}.{Guid.NewGuid()}";
            var operationParentIdHeaderName = "My-Request-Id";
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddHttpCorrelation(opt =>
            {
                opt.UpstreamService.ExtractFromRequest          = extractFromRequest;
                opt.UpstreamService.OperationParentIdHeaderName = operationParentIdHeaderName;
            }))
                          .PreConfigure(app => app.UseHttpCorrelation());

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(CorrelationController.GetRoute)
                              .WithHeader(operationParentIdHeaderName, operationParentId);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    string actualOperationId = GetResponseHeader(response, DefaultOperationId);
                    Assert.Equal(extractFromRequest, operationId == actualOperationId);
                }
            }
        }
        public async Task SendRequestWithCorrelateInfo_SetsCorrelationInfo_ResponseWithUpdatedCorrelationInfo()
        {
            // Arrange
            var correlationInfo = new CorrelationInfo($"operation-{Guid.NewGuid()}", $"transaction-{Guid.NewGuid()}");
            var options         = new TestApiServerOptions()
                                  .ConfigureServices(services => services.AddHttpCorrelation())
                                  .PreConfigure(app => app.UseHttpCorrelation());

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder.Post(CorrelationController.SetCorrelationRoute)
                              .WithHeader(DefaultOperationId, correlationInfo.OperationId)
                              .WithHeader(DefaultTransactionId, correlationInfo.TransactionId);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    string actualOperationId   = GetResponseHeader(response, DefaultOperationId);
                    string actualTransactionId = GetResponseHeader(response, DefaultTransactionId);

                    Assert.Equal(correlationInfo.OperationId, actualOperationId);
                    Assert.Equal(correlationInfo.TransactionId, actualTransactionId);
                }
            }
        }
        public async Task SendRequest_WithRequestIdHeader_ResponseWithDifferentRequestIdHeader()
        {
            // Arrange
            string expected = $"operation-{Guid.NewGuid()}";
            var    options  = new TestApiServerOptions()
                              .ConfigureServices(services => services.AddHttpCorrelation())
                              .PreConfigure(app => app.UseHttpCorrelation());

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(CorrelationController.GetRoute)
                              .WithHeader(DefaultOperationId, expected);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    string actual = GetResponseHeader(response, DefaultOperationId);
                    Assert.NotEqual(expected, actual);
                }
            }
        }
        public async Task SendRequest_WithCorrelateOptionsCustomGenerateOperationId_ResponseWitCustomGeneratedOperationId()
        {
            // Arrange
            var expectedOperationId = $"operation-{Guid.NewGuid():N}";
            var options             = new TestApiServerOptions()
                                      .ConfigureServices(services => services.AddHttpCorrelation(opt => opt.Operation.GenerateId = () => expectedOperationId))
                                      .PreConfigure(app => app.UseTraceIdentifier(opt => opt.EnableTraceIdentifier = false)
                                                    .UseHttpCorrelation());

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

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Contains(response.Headers, header => header.Key == DefaultTransactionId);

                    string actualOperationId = GetResponseHeader(response, DefaultOperationId);
                    Assert.Equal(expectedOperationId, actualOperationId);
                }
            }
        }
        public async Task SendRequest_WithoutCorrelationHeaders_ResponseWithCorrelationHeadersAndCorrelationAccess()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddHttpCorrelation())
                          .PreConfigure(app => app.UseHttpCorrelation());

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

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    string correlationId = GetResponseHeader(response, DefaultTransactionId);
                    string requestId     = GetResponseHeader(response, DefaultOperationId);

                    string json = await response.Content.ReadAsStringAsync();

                    var content = JsonConvert.DeserializeAnonymousType(json, new { TransactionId = "", OperationId = "" });
                    Assert.False(String.IsNullOrWhiteSpace(content.TransactionId), "Accessed 'X-Transaction-ID' cannot be blank");
                    Assert.False(String.IsNullOrWhiteSpace(content.OperationId), "Accessed 'X-Operation-ID' cannot be blank");

                    Assert.Equal(correlationId, content.TransactionId);
                    Assert.Equal(requestId, content.OperationId);
                }
            }
        }
        public async Task GetHealthWithCorrectBearerToken_WithInjectedAzureManagedIdentityAuthorization_ReturnsOk()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services =>
            {
                services.AddMvc(opt =>
                {
                    opt.Filters.AddJwtTokenAuthorization(jwt => jwt.AddJwtTokenReader <IgnoredJwtTokenReader>());
                });
            });

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var accessToken = $"Bearer {_bogusGenerator.Random.AlphaNumeric(10)}.{_bogusGenerator.Random.AlphaNumeric(50)}.{_bogusGenerator.Random.AlphaNumeric(40)}";
                var request     = HttpRequestBuilder
                                  .Get(HealthController.GetRoute)
                                  .WithHeader(JwtTokenAuthorizationOptions.DefaultHeaderName, accessToken);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }
            }
        }
        public async Task JwtAuthorizedRoute_EmitSecurityEventsWhenRequested_RunsAuthorization(bool emitSecurityEvents)
        {
            // Arrange
            var spySink = new InMemorySink();
            var options = new TestApiServerOptions()
                          .ConfigureServices(services =>
            {
                services.AddMvc(opt => opt.Filters.AddJwtTokenAuthorization(jwt => jwt.EmitSecurityEvents = emitSecurityEvents));
            })
                          .ConfigureHost(host => host.UseSerilog((context, config) => config.WriteTo.Sink(spySink)));

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                string accessToken = $"Bearer {_bogusGenerator.Random.AlphaNumeric(10)}.{_bogusGenerator.Random.AlphaNumeric(50)}";
                var    request     = HttpRequestBuilder
                                     .Get(HealthController.GetRoute)
                                     .WithHeader(JwtTokenAuthorizationOptions.DefaultHeaderName, accessToken);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                    IEnumerable <LogEvent> logEvents = spySink.DequeueLogEvents();
                    Assert.True(emitSecurityEvents == logEvents.Any(logEvent =>
                    {
                        string message = logEvent.RenderMessage();
                        return(message.Contains("EventType") && message.Contains("Security"));
                    }));
                }
            }
        }
예제 #16
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);
                    }
                }
            }
        }
예제 #17
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);
                    }
                }
            }
        }
        public async Task SetupApi_WithoutApplicationVersion_Throws()
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .Configure(app => app.UseVersionTracking());

            // Act / Assert
            await Assert.ThrowsAsync <InvalidOperationException>(() => TestApiServer.StartNewAsync(options, _logger));
        }
        public async Task AuthenticationOperationFilter_ShouldNotIncludeSecurityDefinitionResponses_OnNonAuthorizedOperations()
        {
            // Arrange
            string assemblyName = typeof(AuthenticationOperationFilterTests).Assembly.GetName().Name;
            var    options      = new TestApiServerOptions()
                                  .ConfigureServices(services =>
            {
                var openApiInformation = new OpenApiInfo {
                    Title = assemblyName, Version = "v1"
                };
                services.AddSwaggerGen(swagger =>
                {
                    swagger.SwaggerDoc("v1", openApiInformation);
                    swagger.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, assemblyName + ".Open-Api.xml"));
                    swagger.OperationFilter <OAuthAuthorizeOperationFilter>(new object[] { new[] { "myApiScope" } });
                    swagger.OperationFilter <SharedAccessKeyAuthenticationOperationFilter>("sharedaccesskey", SecuritySchemeType.ApiKey);
                    swagger.OperationFilter <CertificateAuthenticationOperationFilter>("certificate", SecuritySchemeType.ApiKey);
                });
            })
                                  .Configure(app =>
            {
                app.UseSwagger();
                app.UseSwaggerUI(swagger =>
                {
                    swagger.SwaggerEndpoint("v1/swagger.json", assemblyName);
                    swagger.DocumentTitle = assemblyName;
                });
            });

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder.Get("/swagger/v1/swagger.json");
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    OpenApiDocument swagger = await ReadSwaggerOpenAPiDocumentAsync(response);

                    Assert.True(swagger.Paths.TryGetValue("/" + AuthenticationController.NoneRoute, out OpenApiPathItem path),
                                $"Cannot find /{AuthenticationController.NoneRoute} none authorized path in Open API spec file");

                    Assert.True(path.Operations.TryGetValue(OperationType.Get, out OpenApiOperation operation),
                                "Cannot find GET operation in Open API spec file");

                    OpenApiResponses operationResponses = operation.Responses;
                    Assert.DoesNotContain(operationResponses, r => r.Key == "401");
                    Assert.DoesNotContain(operationResponses, r => r.Key == "403");
                }
            }
        }
        public async Task SendRequest_WithVersionTrackingForBlankVersion_DoesntAddApplicationVersionToResponse(string version)
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddAppVersion(provider => new StubAppVersion(version)))
                          .Configure(app => app.UseVersionTracking());

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder.Get(HealthController.GetRoute);
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.False(response.Headers.Contains(DefaultHeaderName));
                }
            }
        }
예제 #21
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}'");
                    }
                }
            }
        }
예제 #22
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}'");
                    }
                }
            }
        }
        public async Task JwtAuthorizedRoute_WithBypassAttribute_SkipsAuthorization(string route)
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddMvc(opt => opt.Filters.AddJwtTokenAuthorization()));

            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);
                }
            }
        }
        public async Task SendRequest_WithCorrelationInfoOptionsNotGenerateTransactionId_ResponseWithoutTransactionId()
        {
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddHttpCorrelation(opt => opt.Transaction.GenerateWhenNotSpecified = false))
                          .PreConfigure(app => app.UseHttpCorrelation());

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder.Get(CorrelationController.GetRoute);
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.Contains(response.Headers, header => header.Key == DefaultOperationId);
                    Assert.DoesNotContain(response.Headers, header => header.Key == DefaultTransactionId);
                }
            }
        }
        public async Task SharedAccessKeyAuthorizedRoute_WithBypassAttributeOnMethod_SkipsAuthentication(string route)
        {
            // Arrange
            var options = new TestApiServerOptions()
                          .ConfigureServices(services => services.AddMvc(opt => opt.Filters.AddSharedAccessKeyAuthenticationOnHeader(HeaderName, SecretName)));

            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);
                }
            }
        }
예제 #26
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);
                    }
                }
            }
        }
        public async Task AuthorizedRoute_WithSharedAccessKey_ShouldFailWithKeyNotFoundException_WhenNoSecretProviderWasRegistered()
        {
            // Arrange
            string secretValue = $"secret-{Guid.NewGuid()}";
            var    options     = new TestApiServerOptions();

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                // Act
                var request = HttpRequestBuilder
                              .Get(SharedAccessKeyAuthenticationController.AuthorizedGetRoute)
                              .WithHeader(HeaderName, secretValue);

                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
                }
            }
        }
예제 #28
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"));
                    }));
                }
            }
        }
        public async Task AuthorizedRoute_WithSharedAccessKey_ShouldFailWithUnauthorized(string headerName, string headerValue)
        {
            // Arrange
            string secretValue = $"secret-{Guid.NewGuid()}";
            var    options     = new TestApiServerOptions()
                                 .ConfigureServices(services => services.AddSecretStore(stores => stores.AddInMemory(SecretName, secretValue)));

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                var request = HttpRequestBuilder
                              .Get(SharedAccessKeyAuthenticationController.AuthorizedGetRouteHeader)
                              .WithHeader(headerName, headerValue);

                // Act
                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Assert
                    Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
                }
            }
        }
        public async Task AuthorizedRoute_WithSharedAccessKey_RegisteredWithSecretProvider_ShouldNotFailWithUnauthorized(Type secretProviderType, string headerName)
        {
            // Arrange
            string secretValue = $"secret-{Guid.NewGuid()}";
            var    options     = new TestApiServerOptions()
                                 .ConfigureServices(services => services.AddSingleton(secretProviderType, new InMemorySecretProvider(SecretName, secretValue)));

            await using (var server = await TestApiServer.StartNewAsync(options, _logger))
            {
                // Act
                var request = HttpRequestBuilder
                              .Get(SharedAccessKeyAuthenticationController.AuthorizedGetRouteHeader)
                              .WithHeader(headerName, secretValue);

                using (HttpResponseMessage response = await server.SendAsync(request))
                {
                    // Act
                    Assert.NotEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                }
            }
        }