Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 7 additions & 31 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,27 @@ name: Main

on:
push:
branches: [ main, feature/*, hotfix/* ]
branches:
- main
pull_request:
branches: [ main, feature/*, hotfix/* ]
branches:
- main

jobs:

build:
code-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 9.0.x
- name: Restore dependencies
- name: Restore
run: dotnet restore --property NuGetAudit=true --property NuGetAuditMode=All --property NuGetAuditLevel=Moderate
- name: Build
run: dotnet build --no-restore

test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal

analisys:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 9.0.x
- name: Generate coverage report
run: dotnet test /p:CollectCoverage=true /p:ExcludeByAttribute="GeneratedCodeAttribute" /p:ExcludeByAttribute="CompilerGeneratedAttribute" /p:CoverletOutputFormat=\"json,cobertura\" /p:CoverletOutput=../../coverage/ /p:MergeWith=../../coverage/coverage.json
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace AuthorizationInterceptor.Extensions.Abstractions.Json;
/// <summary>
/// A Json Serializer for the <see cref="AuthorizationHeaders"/> class. Used to print or save in a format where data loss does not occur.
/// </summary>
public class AuthorizationHeadersJsonSerializer
public static class AuthorizationHeadersJsonSerializer
{
/// <summary>
/// Custom converter used to print or save in a format where data loss does not occur.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.3.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal sealed class HybridCacheAuthorizationInterceptor(Microsoft.Extensions.C
public async ValueTask<AuthorizationHeaders?> GetHeadersAsync(string name, CancellationToken cancellationToken)
{
var data = await hybridCache.GetOrCreateAsync(string.Format(CacheKey, name),
_ => ValueTask.FromResult((string?)null),
_ => ValueTask.FromResult<string?>(null),
new HybridCacheEntryOptions { Flags = HybridCacheEntryFlags.DisableLocalCacheWrite | HybridCacheEntryFlags.DisableDistributedCacheWrite },
cancellationToken: cancellationToken);
return string.IsNullOrEmpty(data) ? null : AuthorizationHeadersJsonSerializer.Deserialize(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal class MemoryCacheInterceptor(IMemoryCache memoryCache) : IAuthorization
cancellationToken.ThrowIfCancellationRequested();

var headers = memoryCache.Get<AuthorizationHeaders?>(string.Format(CacheKey, name));
return new(headers);
return new ValueTask<AuthorizationHeaders?>(headers);
}

public ValueTask UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using AuthorizationInterceptor.Extensions.Abstractions.Handlers;
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Log;
using AuthorizationInterceptor.Strategies;
using AuthorizationInterceptor.Utils;
using Microsoft.Extensions.Logging;

namespace AuthorizationInterceptor.Handlers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class AuthorizationInterceptorOptions : IAuthorizationInterceptorOptions
/// Adds a custom interceptor to the interceptor sequence. Note that the interceptor addition sequence interferes with the headers query sequence.
/// </summary>
/// <typeparam name="T">Implementation class of type <see cref="IAuthorizationInterceptor"/></typeparam>
/// <param name="func">Access to <see cref="IServiceCollection"/> if necessary inject some dependencies</param>
public void UseCustomInterceptor<T>(Func<IServiceCollection, IServiceCollection>? func = null) where T : IAuthorizationInterceptor
=> Interceptors.Add((typeof(T), func));
/// <param name="services">Access to <see cref="IServiceCollection"/> if necessary to inject some dependencies</param>
public void UseCustomInterceptor<T>(Func<IServiceCollection, IServiceCollection>? services = null) where T : IAuthorizationInterceptor
=> Interceptors.Add((typeof(T), services));
}

Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
using AuthorizationInterceptor.Extensions.Abstractions.Handlers;
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Extensions.Abstractions.Interceptors;
using AuthorizationInterceptor.Log;
using AuthorizationInterceptor.Utils;
using Microsoft.Extensions.Logging;

namespace AuthorizationInterceptor.Strategies;

internal class AuthorizationInterceptorStrategy : IAuthorizationInterceptorStrategy
internal class AuthorizationInterceptorStrategy(ILoggerFactory loggerFactory, IAuthorizationInterceptor[] interceptors)
: IAuthorizationInterceptorStrategy
{
private readonly IAuthorizationInterceptor[] _interceptors;
private readonly ILogger _logger;

public AuthorizationInterceptorStrategy(ILoggerFactory loggerFactory, IAuthorizationInterceptor[] interceptors)
{
_logger = loggerFactory.CreateLogger("AuthorizationInterceptorStrategy");
_interceptors = interceptors;
}
private readonly ILogger _logger = loggerFactory.CreateLogger("AuthorizationInterceptorStrategy");

public async ValueTask<AuthorizationHeaders?> GetHeadersAsync(string name, IAuthenticationHandler authenticationHandler, CancellationToken cancellationToken)
{
Expand All @@ -24,37 +18,37 @@ public AuthorizationInterceptorStrategy(ILoggerFactory loggerFactory, IAuthoriza
AuthorizationHeaders? headers = null;
int index;

for (index = 0; index < _interceptors.Length; index++)
for (index = 0; index < interceptors.Length; index++)
{
try
{
LogDebug("Getting headers from interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
LogDebug("Getting headers from interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);

cancellationToken.ThrowIfCancellationRequested();

headers = await _interceptors[index].GetHeadersAsync(name, cancellationToken);
headers = await interceptors[index].GetHeadersAsync(name, cancellationToken);
if (headers == null)
continue;

LogDebug("Headers found in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
LogDebug("Headers found in interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);

if (headers.IsHeadersValid())
{
LogDebug("Headers still valid in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
LogDebug("Headers still valid in interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);
return await UpdateHeadersInInterceptorsAsync(name, index, headers, cancellationToken);
}

LogDebug("Headers is expired in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
LogDebug("Headers is expired in interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);
break;
}
catch (OperationCanceledException)
{
_logger.LogOperationCanceledInInterceptor(_interceptors[index].GetType().Name, name);
_logger.LogOperationCanceledInInterceptor(interceptors[index].GetType().Name, name);
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting headers from interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
_logger.LogError(ex, "Error getting headers from interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);
}
}

Expand All @@ -74,7 +68,7 @@ public AuthorizationInterceptorStrategy(ILoggerFactory loggerFactory, IAuthoriza
return null;
}

return await UpdateHeadersInInterceptorsAsync(name, _interceptors.Length, newHeaders, cancellationToken);
return await UpdateHeadersInInterceptorsAsync(name, interceptors.Length, newHeaders, cancellationToken);
}

private async ValueTask<AuthorizationHeaders?> UpdateHeadersInInterceptorsAsync(string name, int startIndex, AuthorizationHeaders? headers, CancellationToken cancellationToken)
Expand All @@ -88,20 +82,20 @@ public AuthorizationInterceptorStrategy(ILoggerFactory loggerFactory, IAuthoriza
{
try
{
LogDebug("Updating headers in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
LogDebug("Updating headers in interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);

cancellationToken.ThrowIfCancellationRequested();

await _interceptors[index].UpdateHeadersAsync(name, null, headers, cancellationToken);
await interceptors[index].UpdateHeadersAsync(name, null, headers, cancellationToken);
}
catch (OperationCanceledException)
{
_logger.LogOperationCanceledInInterceptor(_interceptors[index].GetType().Name, name);
_logger.LogOperationCanceledInInterceptor(interceptors[index].GetType().Name, name);
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating headers in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
_logger.LogError(ex, "Error updating headers in interceptor '{interceptor}' with integration '{name}'", interceptors[index].GetType().Name, name);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Microsoft.Extensions.Logging;
using System.Diagnostics.CodeAnalysis;

namespace AuthorizationInterceptor.Log;
namespace AuthorizationInterceptor.Utils;

public static partial class AuthorizationInterceptorLogDifinitions
[ExcludeFromCodeCoverage]
public static partial class AuthorizationInterceptorLogDefinitions
{
[LoggerMessage(EventId = 1, Level = LogLevel.Warning, Message = "No interceptor was configured for HttpClient `{httpClientName}`. A Runtime interceptor was used instead. It is recommended to use at least the MemoryCache interceptor.")]
public static partial void LogNoInterceptorUsed(this ILogger logger, string httpClientName);
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<LangVersion>13</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>5.0.0-preview-1</Version>
<Version>5.0.0</Version>
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<Title>Authorization Interceptor</Title>
<Authors>Adolfok3</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void AddAuthorizationInterceptorHandler_WithOptions_ShouldBuildServicePro
services.AddHttpClient("Test")
.AddAuthorizationInterceptorHandler<MockAuthorizationInterceptorAuthenticationHandler>(options =>
{
options.UseCustomInterceptor<MockAuthorizationInterceptor>();
options.UseCustomInterceptor<MockAuthorizationInterceptor>(func => func.AddSingleton<MockAuthorizationInterceptor>());
});

// Act
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using AuthorizationInterceptor.Extensions.Abstractions.Handlers;
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Handlers;
using AuthorizationInterceptor.Log;
using AuthorizationInterceptor.Strategies;
using AuthorizationInterceptor.Tests.Utils;
using AuthorizationInterceptor.Utils;
using Microsoft.Extensions.Logging;

namespace AuthorizationInterceptor.Tests.Handlers;
Expand Down
Loading