From 682dcecb93b16e8cc3577bed8ca9c3967e0c8d3b Mon Sep 17 00:00:00 2001 From: Neil South Date: Wed, 14 Dec 2022 14:33:19 +0000 Subject: [PATCH 1/2] fix for basic auth Signed-off-by: Neil South --- src/Authentication/Middleware/BasicAuthorizationMiddleware.cs | 4 +++- .../Tests/EndpointAuthorizationMiddlewareTest.cs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs b/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs index 19965a6..58a6a5f 100755 --- a/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs +++ b/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs @@ -49,7 +49,8 @@ public BasicAuthorizationMiddleware( public async Task InvokeAsync(HttpContext httpContext) { - if (_options.Value.BasicAuthEnabled(_logger) is false) + if ((_options.Value.BypassAuthentication.HasValue && _options.Value.BypassAuthentication.Value is true) + || _options.Value.BasicAuthEnabled(_logger) is false) { await _next(httpContext).ConfigureAwait(false); return; @@ -70,6 +71,7 @@ public async Task InvokeAsync(HttpContext httpContext) var identity = new ClaimsIdentity(claims, "Basic"); var claimsPrincipal = new ClaimsPrincipal(identity); httpContext.User = claimsPrincipal; + await _next(httpContext).ConfigureAwait(false); return; } } diff --git a/src/Authentication/Tests/EndpointAuthorizationMiddlewareTest.cs b/src/Authentication/Tests/EndpointAuthorizationMiddlewareTest.cs index 4ad2c08..016d933 100755 --- a/src/Authentication/Tests/EndpointAuthorizationMiddlewareTest.cs +++ b/src/Authentication/Tests/EndpointAuthorizationMiddlewareTest.cs @@ -165,6 +165,7 @@ public async Task GivenConfigurationFileWithBasicConfigured_WhenUserIsAuthentica Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode); } + [Fact] public async Task GivenConfigurationFileWithBasicConfigured_WhenHeaderIsInvalid_ExpectToDenyRequest() { From d13f6163ff81e6748913d20ef771b51aa7c9d77a Mon Sep 17 00:00:00 2001 From: Neil South Date: Wed, 14 Dec 2022 14:47:42 +0000 Subject: [PATCH 2/2] tidy up tests Signed-off-by: Neil South --- .../BasicAuthorizationMiddleware.cs | 1 - .../Tests/BasicAuthorizationMiddlewareTest.cs | 138 ++++++++++++++++++ .../Tests/MockJwtTokenHandler.cs | 0 ...eploy.Security.Authentication.Tests.csproj | 2 + .../Tests/test.basicbypass.json | 9 ++ 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100755 src/Authentication/Tests/BasicAuthorizationMiddlewareTest.cs mode change 100644 => 100755 src/Authentication/Tests/MockJwtTokenHandler.cs mode change 100644 => 100755 src/Authentication/Tests/Monai.Deploy.Security.Authentication.Tests.csproj create mode 100755 src/Authentication/Tests/test.basicbypass.json diff --git a/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs b/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs index 58a6a5f..cc5433d 100755 --- a/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs +++ b/src/Authentication/Middleware/BasicAuthorizationMiddleware.cs @@ -22,7 +22,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Monai.Deploy.Security.Authentication.Configurations; -using Monai.Deploy.Security.Authentication.Extensions; namespace Monai.Deploy.Security.Authentication.Middleware { diff --git a/src/Authentication/Tests/BasicAuthorizationMiddlewareTest.cs b/src/Authentication/Tests/BasicAuthorizationMiddlewareTest.cs new file mode 100755 index 0000000..eaca22f --- /dev/null +++ b/src/Authentication/Tests/BasicAuthorizationMiddlewareTest.cs @@ -0,0 +1,138 @@ +/* + * Copyright 2022 MONAI Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Net; +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.TestHost; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using Monai.Deploy.Security.Authentication.Configurations; +using Monai.Deploy.Security.Authentication.Extensions; + +namespace Monai.Deploy.Security.Authentication.Tests +{ + public partial class BasicAuthorizationMiddlewareTest + { + + + [Fact] + public async Task GivenConfigurationFileToBypassAuthentication_ExpectToBypassAuthentication() + { + using var host = await new HostBuilder().ConfigureWebHost(SetupWebServer("test.basicbypass.json")).StartAsync().ConfigureAwait(false); + + var server = host.GetTestServer(); + server.BaseAddress = new Uri("https://example.com/"); + + var client = server.CreateClient(); + var responseMessage = await client.GetAsync("api/Test").ConfigureAwait(false); + + Assert.True(responseMessage.IsSuccessStatusCode); + } + + + + [Fact] + public async Task GivenConfigurationFileWithBasicConfigured_WhenUserIsNotAuthenticated_ExpectToDenyRequest() + { + using var host = await new HostBuilder().ConfigureWebHost(SetupWebServer("test.basic.json")).StartAsync().ConfigureAwait(false); + + var server = host.GetTestServer(); + server.BaseAddress = new Uri("https://example.com/"); + + var client = server.CreateClient(); + var responseMessage = await client.GetAsync("api/Test").ConfigureAwait(false); + + Assert.Equal(HttpStatusCode.Unauthorized, responseMessage.StatusCode); + } + + [Fact] + public async Task GivenConfigurationFileWithBasicConfigured_WhenUserIsAuthenticated_ExpectToAllowRequest() + { + using var host = await new HostBuilder().ConfigureWebHost(SetupWebServer("test.basic.json")).StartAsync().ConfigureAwait(false); + + var server = host.GetTestServer(); + server.BaseAddress = new Uri("https://example.com/"); + + var client = server.CreateClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"))}"); + var responseMessage = await client.GetAsync("api/Test").ConfigureAwait(false); + + Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode); + } + + [Fact] + public async Task GivenConfigurationFileWithBasicConfigured_WhenHeaderIsInvalid_ExpectToDenyRequest() + { + using var host = await new HostBuilder().ConfigureWebHost(SetupWebServer("test.basic.json")).StartAsync().ConfigureAwait(false); + + var server = host.GetTestServer(); + server.BaseAddress = new Uri("https://example.com/"); + + var client = server.CreateClient(); + client.DefaultRequestHeaders.Add("Authorization", $"BasicBad {Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"))}"); + var responseMessage = await client.GetAsync("api/Test").ConfigureAwait(false); + + Assert.Equal(HttpStatusCode.Unauthorized, responseMessage.StatusCode); + } + + private static Action SetupWebServer(string configFile) => webBuilder => + { + webBuilder + .ConfigureAppConfiguration((builderContext, config) => + { + config.Sources.Clear(); + config.AddJsonFile(configFile, optional: false); + _ = config.Build(); + }) + .ConfigureLogging((hostContext, logging) => + { + logging.AddDebug(); + logging.AddConsole(); + }) + .ConfigureServices((hostContext, services) => + { + services.AddOptions().Bind(hostContext.Configuration.GetSection("MonaiDeployAuthentication")); + + services.AddControllers(); + services.AddMonaiAuthentication(); + + services.Configure(JwtBearerDefaults.AuthenticationScheme, op => + { + var config = new OpenIdConnectConfiguration() + { + Issuer = Guid.NewGuid().ToString(), + }; + + config.SigningKeys.Add(EndpointAuthorizationMiddlewareTest.MockJwtTokenHandler.SecurityKey); + op.Configuration = config; + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseEndpointAuthorizationMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + }) + .UseTestServer(); + }; + } +} diff --git a/src/Authentication/Tests/MockJwtTokenHandler.cs b/src/Authentication/Tests/MockJwtTokenHandler.cs old mode 100644 new mode 100755 diff --git a/src/Authentication/Tests/Monai.Deploy.Security.Authentication.Tests.csproj b/src/Authentication/Tests/Monai.Deploy.Security.Authentication.Tests.csproj old mode 100644 new mode 100755 index 8c8c8f3..b1e4abd --- a/src/Authentication/Tests/Monai.Deploy.Security.Authentication.Tests.csproj +++ b/src/Authentication/Tests/Monai.Deploy.Security.Authentication.Tests.csproj @@ -57,4 +57,6 @@ + + diff --git a/src/Authentication/Tests/test.basicbypass.json b/src/Authentication/Tests/test.basicbypass.json new file mode 100755 index 0000000..7e391a4 --- /dev/null +++ b/src/Authentication/Tests/test.basicbypass.json @@ -0,0 +1,9 @@ +{ + "MonaiDeployAuthentication": { + "BypassAuthentication": true, + "basicAuth": { + "userName": "user", + "password": "pass" + } + } +} \ No newline at end of file