From 7256e1e317eeaf2a18b8add4291a96cac030645b Mon Sep 17 00:00:00 2001 From: Tomi Tuhkanen Date: Tue, 17 May 2022 07:56:57 +0200 Subject: [PATCH] Fix basic authentication unauthorized result (#91) --- CHANGELOG.md | 1 + .../BasicAuthAuthenticationSpecs.cs | 55 +++++++++++++++++++ .../Basic/BasicAuthentication.cs | 7 ++- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 FakeServer.Test/Authentication/BasicAuthAuthenticationSpecs.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d5799a..5bf8200 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ### [Unreleased] +* FIXED: Basic Authentication unauthorized result * ADDED: API key authentication * CHANGED: For empty collections return 200 status code instead of 404 * FIXED: Swagger authentication diff --git a/FakeServer.Test/Authentication/BasicAuthAuthenticationSpecs.cs b/FakeServer.Test/Authentication/BasicAuthAuthenticationSpecs.cs new file mode 100644 index 0000000..fb73eb3 --- /dev/null +++ b/FakeServer.Test/Authentication/BasicAuthAuthenticationSpecs.cs @@ -0,0 +1,55 @@ +using System; +using System.Net.Http.Headers; +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace FakeServer.Test.Authentication +{ + [Collection("Integration collection")] + [Trait("category", "integration")] + [Trait("category", "authentication")] + public class BasicAuthAuthenticationSpecs : IDisposable + { + private readonly IntegrationFixture _fixture; + + public BasicAuthAuthenticationSpecs(IntegrationFixture fixture) + { + _fixture = fixture; + _fixture.StartServer(authenticationType: "basic"); + } + + public void Dispose() + { + _fixture.Stop(); + } + + [Fact] + public async Task GetUsers_No_Header_Unauthorized() + { + var result = await _fixture.Client.GetAsync("api/users"); + Assert.Equal(HttpStatusCode.Unauthorized, result.StatusCode); + } + + [Fact] + public async Task GetUsers_Authorized() + { + _fixture.Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "YWRtaW46cm9vdA=="); + + var result = await _fixture.Client.GetAsync("api/users"); + Assert.Equal(HttpStatusCode.OK, result.StatusCode); + } + + [Theory] + [InlineData("abbaacdc1234")] + [InlineData("")] + public async Task GetUsers_Wrong_Token_Unauthorized(string token) + { + _fixture.Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token); + + + var result = await _fixture.Client.GetAsync("api/users"); + Assert.Equal(HttpStatusCode.Unauthorized, result.StatusCode); + } + } +} \ No newline at end of file diff --git a/FakeServer/Authentication/Basic/BasicAuthentication.cs b/FakeServer/Authentication/Basic/BasicAuthentication.cs index 167a29d..22bb9be 100644 --- a/FakeServer/Authentication/Basic/BasicAuthentication.cs +++ b/FakeServer/Authentication/Basic/BasicAuthentication.cs @@ -21,6 +21,7 @@ public static void AddBasicAuthentication(this IServiceCollection services) { services.AddAuthentication(o => { + o.DefaultScheme = BasicAuthenticationDefaults.AuthenticationScheme; o.DefaultAuthenticateScheme = BasicAuthenticationDefaults.AuthenticationScheme; }) .AddBasicAuthentication(); @@ -95,6 +96,9 @@ public override void Validate() public class BasicAuthenticationHandler : AuthenticationHandler { + // "Basic " + private const int HeaderMinLength = 6; + public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } @@ -107,7 +111,7 @@ bool Authenticate(out string name) { var authenticationSettings = Context.RequestServices.GetService(typeof(IOptions)) as IOptions; - var token = authHeader.Substring("Basic ".Length).Trim(); + var token = authHeader.Substring(HeaderMinLength).Trim(); var credentialString = Encoding.UTF8.GetString(Convert.FromBase64String(token)); var credentials = credentialString.Split(':'); @@ -123,6 +127,7 @@ bool Authenticate(out string name) if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase) && + authHeader.Length > HeaderMinLength && Authenticate(out string loginName)) { var claims = new[] { new Claim("name", loginName), new Claim(ClaimTypes.Role, "Admin") };