Skip to content

Commit

Permalink
Fixed failed authentication on wrong authentication header scheme. Gi…
Browse files Browse the repository at this point in the history
…ving a different auth scheme in the header would before result in failed authentication. Now it will (correctly) result in NoResult. (#13)

Also updated dependencies.
  • Loading branch information
dnmh-psc committed May 15, 2023
1 parent 8a79086 commit e170760
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Samples/Dnmh.Security.ApiKeyAuthentication.Sample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

Expand Down
8 changes: 4 additions & 4 deletions Source/AuthenticationHandler/ApiKeyAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
/// <inheritdoc/>
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.Headers["WWW-Authenticate"] = Scheme.Name;
Response.Headers[HeaderNames.WWWAuthenticate] = Scheme.Name;
await base.HandleChallengeAsync(properties);
}

Expand Down Expand Up @@ -115,14 +115,15 @@ private bool TryExtractFromHeader(HttpRequest request, [MaybeNullWhen(false)] ou
return false;
}

headerValue = authenticationHeaderValue.Parameter;

var schemeName = Options.UseSchemeNameInAuthorizationHeader ? Scheme.Name : Options.AuthorizationSchemeInHeader;
if (!schemeName.Equals(authenticationHeaderValue.Scheme, StringComparison.OrdinalIgnoreCase))
{
// Not correct scheme authentication header
headerValue = default;
return false;
}

headerValue = authenticationHeaderValue.Parameter;
}
else
{
Expand All @@ -136,7 +137,6 @@ private bool TryExtractFromHeader(HttpRequest request, [MaybeNullWhen(false)] ou
headerValue = request.Headers[Options.HeaderKey]!;
}


return true;
}

Expand Down
3 changes: 1 addition & 2 deletions Source/Dnmh.Security.ApiKeyAuthentication.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/DetNordjyskeMediehus/Dnmh.Security.ApiKeyAuthentication</PackageProjectUrl>
<Title>.Net ApiKey Authentication</Title>
<Version>2.0.0</Version>
<Version>2.0.1</Version>
<PackageReadmeFile>README.md</PackageReadmeFile>
<Description>A .NET Core library that provides API key authentication for your web applications. With this library, you can require API keys to access your API endpoints and secure your application against unauthorized access. The library can also be integrated with Swagger UI to provide a seamless authentication experience.</Description>
<PackageTags>authentication dotnet .Net dotnetcore .NetCore apikey apikey-authentication swagger swagger-ui</PackageTags>
Expand All @@ -26,7 +26,6 @@

<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.5.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

Expand Down
42 changes: 41 additions & 1 deletion Tests/AuthenticationHandler/ApiKeyAuthenticationHandlerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,30 @@ public async Task TestOptionsWithAuthorizationHeaderAndCustomSchemeKeySuccessful
}

[Fact]
public async Task TestOptionsWithAuthorizationHeaderKeyNoBearerWillFail()
public async Task TestOptionsWithAuthorizationHeaderAndCustomSchemeKeyButWrongSchemeShouldFail()
{
// Arrange
var optionsMock = MockHelpers.CreateMockOptionsMonitor<ApiKeyAuthenticationOptions>(options =>
{
options.AllowApiKeyInQuery = false;
options.AllowApiKeyInRequestHeader = true;
options.UseAuthorizationHeaderKey = true;
options.AuthorizationSchemeInHeader = "ApiKey";
});
var handler = MockHelpers.CreateApiKeyAuthenticationHandler(optionsMock.Object);
var mockHttpContext = MockHelpers.CreateMockHttpContextWithRequestHeaders(new Dictionary<string, StringValues> { { HeaderNames.Authorization, "Bearer key" } });
await handler.InitializeWithSchemeNameAsync(mockHttpContext.Object);

// Act
var result = await handler.AuthenticateAsync();

// Assert
result.Should().NotBeNull();
result.Succeeded.Should().BeFalse();
}

[Fact]
public async Task TestOptionsWithAuthorizationHeaderKeyNoBearerShouldFail()
{
// Arrange
var optionsMock = MockHelpers.CreateMockOptionsMonitor<ApiKeyAuthenticationOptions>(options =>
Expand Down Expand Up @@ -129,6 +152,23 @@ public async Task TestDefaultOptionsQueryKeySuccessfully()
result.Succeeded.Should().BeTrue();
}

[Fact]
public async Task TestDefaultOptionsWrongQueryKeyShouldFail()
{
// Arrange
var optionsMock = MockHelpers.CreateMockOptionsMonitor<ApiKeyAuthenticationOptions>();
var handler = MockHelpers.CreateApiKeyAuthenticationHandler(optionsMock.Object);
var mockHttpContext = MockHelpers.CreateMockHttpContextWithRequestQueryParams(new Dictionary<string, StringValues> { { "jwt", "key" } });
await handler.InitializeWithSchemeNameAsync(mockHttpContext.Object);

// Act
var result = await handler.AuthenticateAsync();

// Assert
result.Should().NotBeNull();
result.Succeeded.Should().BeFalse();
}

[Fact]
public async Task TestOptionsWithCustomQueryKeySuccessfully()
{
Expand Down
4 changes: 2 additions & 2 deletions Tests/Dnmh.Security.ApiKeyAuthentication.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down

0 comments on commit e170760

Please sign in to comment.