Skip to content

Commit

Permalink
#563 Allow to use multiple authentication methods (#575)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matasx authored Dec 8, 2024
1 parent 0571d47 commit 2b63c74
Show file tree
Hide file tree
Showing 5 changed files with 394 additions and 5 deletions.
10 changes: 5 additions & 5 deletions Modules/Authentication/GenHTTP.Modules.Authentication.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<Version>9.3.0</Version>

<Authors>Andreas Nägeli</Authors>
<Company/>
<Company />

<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl>https://genhttp.org/</PackageProjectUrl>
Expand All @@ -35,20 +35,20 @@

<ItemGroup>

<None Include="..\..\LICENSE" Pack="true" PackagePath="\"/>
<None Include="..\..\Resources\icon.png" Pack="true" PackagePath="\"/>
<None Include="..\..\LICENSE" Pack="true" PackagePath="\" />
<None Include="..\..\Resources\icon.png" Pack="true" PackagePath="\" />

</ItemGroup>

<ItemGroup>

<ProjectReference Include="..\..\API\GenHTTP.Api.csproj"/>
<ProjectReference Include="..\..\API\GenHTTP.Api.csproj" />

<ProjectReference Include="..\Reflection\GenHTTP.Modules.Reflection.csproj" />

<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.2.1" />

<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />

<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />

Expand Down
83 changes: 83 additions & 0 deletions Modules/Authentication/Multi/MultiAuthenticationConcern.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using GenHTTP.Api.Content;
using GenHTTP.Api.Protocol;

namespace GenHTTP.Modules.Authentication.Multi;

public sealed class MultiAuthenticationConcern : IConcern
{
#region Get-/Setters

public IHandler Content { get; }

private readonly IConcern[] _delegatingConcerns;

#endregion

#region Initialization

public MultiAuthenticationConcern(IHandler content, IConcern[] delegatingConcerns)
{
Content = content;
_delegatingConcerns = delegatingConcerns;
}

#endregion

#region Functionality

public async ValueTask<IResponse?> HandleAsync(IRequest request)
{
ResponseOrException? lastResponse = null;
foreach (var concern in _delegatingConcerns)
{
lastResponse?.Dispose();

try
{
lastResponse = new(await concern.HandleAsync(request));
}
catch (ProviderException e)
{
lastResponse = new(Exception: e);
}

if (lastResponse.Status != ResponseStatus.Unauthorized)
{
return lastResponse.Get();
}
}

return lastResponse?.Get() ??
request.Respond()
.Status(ResponseStatus.Unauthorized)
.Build();
}

public ValueTask PrepareAsync() => Content.PrepareAsync();

#endregion

#region Helper structure

private sealed record ResponseOrException(IResponse? Response = null, ProviderException? Exception = null) : IDisposable
{
public IResponse? Get()
{
if (Exception != null)
{
throw Exception;
}

return Response;
}

public void Dispose()
{
Response?.Dispose();
}

public ResponseStatus? Status => Exception?.Status ?? Response?.Status.KnownStatus;
}

#endregion
}
88 changes: 88 additions & 0 deletions Modules/Authentication/Multi/MultiAuthenticationConcernBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using GenHTTP.Api.Content;
using GenHTTP.Api.Infrastructure;
using GenHTTP.Modules.Authentication.ApiKey;
using GenHTTP.Modules.Authentication.Basic;
using GenHTTP.Modules.Authentication.Bearer;
using GenHTTP.Modules.Authentication.ClientCertificate;

namespace GenHTTP.Modules.Authentication.Multi;

/// <summary>
/// Builder for creating a multi-concern authentication handler.
/// </summary>
public sealed class MultiAuthenticationConcernBuilder : IConcernBuilder
{
#region Fields

private readonly List<IConcernBuilder> _delegatingConcernsBuilders = [];

#endregion

#region Private add functionality

private MultiAuthenticationConcernBuilder AddIfNotNull(IConcernBuilder concernBuilder)
{
if (concernBuilder == null) return this;

_delegatingConcernsBuilders.Add(concernBuilder);
return this;
}

#endregion

#region Functionality

/// <summary>
/// Add nested API concern builder to this multi concern.
/// </summary>
/// <param name="apiKeyBuilder">Nested API key concern builder</param>
public MultiAuthenticationConcernBuilder Add(ApiKeyConcernBuilder apiKeyBuilder)
=> AddIfNotNull(apiKeyBuilder);

/// <summary>
/// Add nested API concern builder to this multi concern.
/// </summary>
/// <param name="basicBuilder">Nested Basic concern builder</param>
public MultiAuthenticationConcernBuilder Add(BasicAuthenticationConcernBuilder basicBuilder)
=> AddIfNotNull(basicBuilder);

/// <summary>
/// Add nested API concern builder to this multi concern.
/// </summary>
/// <param name="basicKnownUsersBuilder">Nested Basic Known Users concern builder</param>
public MultiAuthenticationConcernBuilder Add(BasicAuthenticationKnownUsersBuilder basicKnownUsersBuilder)
=> AddIfNotNull(basicKnownUsersBuilder);

/// <summary>
/// Add nested API concern builder to this multi concern.
/// </summary>
/// <param name="bearerBuilder">Nested Bearer concern builder</param>
public MultiAuthenticationConcernBuilder Add(BearerAuthenticationConcernBuilder bearerBuilder)
=> AddIfNotNull(bearerBuilder);

/// <summary>
/// Add nested API concern builder to this multi concern.
/// </summary>
/// <param name="clientCertificateBuilder">Nested Client Certificate concern builder</param>
public MultiAuthenticationConcernBuilder Add(ClientCertificateAuthenticationBuilder clientCertificateBuilder)
=> AddIfNotNull(clientCertificateBuilder);

/// <summary>
/// Construct the multi concern.
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public IConcern Build(IHandler content)
{
var delegatingConcerns = _delegatingConcernsBuilders.Select(x => x.Build(content)).ToArray();
if (delegatingConcerns.Length == 0) throw new BuilderMissingPropertyException("Concerns");

return new MultiAuthenticationConcern(
content,
delegatingConcerns
);
}

#endregion

}
16 changes: 16 additions & 0 deletions Modules/Authentication/MultiAuthentication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using GenHTTP.Modules.Authentication.Multi;

namespace GenHTTP.Modules.Authentication;

public static class MultiAuthentication
{
#region Builder

/// <summary>
/// Creates a authentication handler that will use
/// underlying handlers to authenticate the request.
/// </summary>
public static MultiAuthenticationConcernBuilder Create() => new();

#endregion
}
Loading

0 comments on commit 2b63c74

Please sign in to comment.