Skip to content

Commit b20ca69

Browse files
committed
Refactor authentication and update dependencies
Replaced `FirebaseAuthenticationMiddleware` with the new `JwtOrApiKeyAuthenticationMiddleware` to support dual authentication modes (API key and JWT). Added `AuthenticateController` for authentication validation and user info retrieval. Updated `Program.cs` to use the new middleware and added authentication configuration in `appsettings.json`. Updated package versions: - `Roslynator.Analyzers` to 4.14.1 - `Polly` to 8.6.4 - `OpenTelemetry` packages to 1.13.0 - `Yarp.ReverseProxy` to 2.3.0 Enhanced XML documentation in `FirebaseAuthorizedController`. Introduced response models for authentication. Performed general refactoring and cleanup to improve code structure.
1 parent fa9c440 commit b20ca69

File tree

12 files changed

+242
-24
lines changed

12 files changed

+242
-24
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<ItemGroup>
2929

30-
<PackageReference Include="Roslynator.Analyzers" Version="4.14.0">
30+
<PackageReference Include="Roslynator.Analyzers" Version="4.14.1">
3131
<PrivateAssets>all</PrivateAssets>
3232
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3333
</PackageReference>

src/Genocs.Auth/FirebaseAuthenticationMiddleware.cs renamed to src/Genocs.Auth/JwtOrApiKeyAuthenticationMiddleware.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ namespace Genocs.Auth;
1010
/// Middleware for handling JWT authentication and API key authentication.
1111
/// </summary>
1212
/// <remarks>
13+
/// <para>
1314
/// This middleware supports dual authentication modes:
15+
/// </para>
16+
/// <para>
1417
/// 1. API Key authentication via x-gnx-apikey header for system-to-system communication
18+
/// </para>
19+
/// <para>
1520
/// 2. JWT Bearer token authentication for user authentication
21+
/// </para>
22+
/// <para>
1623
/// When API key is provided, it bypasses JWT validation and sets up API key-based claims.
24+
/// </para>
1725
/// </remarks>
18-
public class JWTOrApiKeyAuthenticationMiddleware(RequestDelegate next, IConfiguration configuration)
26+
public class JwtOrApiKeyAuthenticationMiddleware(RequestDelegate next, IConfiguration configuration)
1927
{
2028
private readonly RequestDelegate _next = next;
2129
private readonly IConfiguration _configuration = configuration;

src/Genocs.HTTP/Genocs.HTTP.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
<ItemGroup>
3333
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
34-
<PackageReference Include="Polly" Version="8.6.2" />
34+
<PackageReference Include="Polly" Version="8.6.4" />
3535
</ItemGroup>
3636

3737
</Project>

src/Genocs.MessageBrokers.RabbitMQ/Genocs.MessageBrokers.RabbitMQ.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
<ItemGroup>
3232
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
33-
<PackageReference Include="Polly" Version="8.6.3" />
33+
<PackageReference Include="Polly" Version="8.6.4" />
3434
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" />
3535
</ItemGroup>
3636

src/Genocs.OpenTelemetry/Genocs.OpenTelemetry.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030

3131
<ItemGroup>
3232
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
33-
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
34-
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
35-
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
33+
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.13.0" />
34+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.13.0" />
35+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.13.0" />
3636
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
3737
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
3838
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />

src/Genocs.Tracing/Genocs.Tracing.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828

2929
<ItemGroup>
3030
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
31-
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
32-
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
33-
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
31+
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.13.0" />
32+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.13.0" />
33+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.13.0" />
3434
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
3535
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
3636
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />

src/apps/apigateway/APIGateway.WebApi/APIGateway.WebApi.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
</ItemGroup>
3535

3636
<ItemGroup>
37-
<PackageReference Include="Yarp.ReverseProxy" Version="2.2.0" />
37+
<PackageReference Include="Yarp.ReverseProxy" Version="2.3.0" />
3838
</ItemGroup>
3939

4040
<ItemGroup>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
namespace Genocs.Core.Demo.WebApi.Controllers;
2+
3+
/// <summary>
4+
/// Response model for authentication validation.
5+
/// </summary>
6+
/// <remarks>
7+
/// Contains authentication status information and user details.
8+
/// Includes authentication type to distinguish between API key and JWT authentication.
9+
/// Provides comprehensive claim information for debugging and integration testing.
10+
/// </remarks>
11+
public class AuthenticationResponse
12+
{
13+
/// <summary>
14+
/// Indicates whether the user is authenticated.
15+
/// </summary>
16+
public bool IsAuthenticated { get; set; }
17+
18+
/// <summary>
19+
/// The type of authentication used (apikey, firebase, etc.).
20+
/// </summary>
21+
public string? AuthenticationType { get; set; }
22+
23+
/// <summary>
24+
/// The authenticated user's unique identifier.
25+
/// </summary>
26+
public string? UserId { get; set; }
27+
28+
/// <summary>
29+
/// The authenticated user's display name.
30+
/// </summary>
31+
public string? UserName { get; set; }
32+
33+
/// <summary>
34+
/// List of all claims associated with the authenticated user.
35+
/// </summary>
36+
public List<ClaimInfo> Claims { get; set; } = [];
37+
}
38+
39+
/// <summary>
40+
/// Response model for user information.
41+
/// </summary>
42+
/// <remarks>
43+
/// Contains basic user information extracted from JWT token.
44+
/// Used for standard authenticated user operations.
45+
/// </remarks>
46+
public class UserInfoResponse
47+
{
48+
/// <summary>
49+
/// The user's unique identifier.
50+
/// </summary>
51+
public string? UserId { get; set; }
52+
53+
/// <summary>
54+
/// The user's display name.
55+
/// </summary>
56+
public string? UserName { get; set; }
57+
58+
/// <summary>
59+
/// The authentication method used.
60+
/// </summary>
61+
public string? AuthenticationType { get; set; }
62+
}
63+
64+
/// <summary>
65+
/// Represents a security claim with type and value.
66+
/// </summary>
67+
/// <remarks>
68+
/// Used for debugging and integration testing to examine all available claims.
69+
/// Provides insight into the authentication context and available user information.
70+
/// </remarks>
71+
public class ClaimInfo
72+
{
73+
/// <summary>
74+
/// The claim type identifier.
75+
/// </summary>
76+
public string Type { get; set; } = default!;
77+
78+
/// <summary>
79+
/// The claim value.
80+
/// </summary>
81+
public string Value { get; set; } = default!;
82+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using Genocs.Auth.Attributes;
2+
using Microsoft.AspNetCore.Authorization;
3+
using Microsoft.AspNetCore.Mvc;
4+
using System.Security.Claims;
5+
6+
namespace Genocs.Core.Demo.WebApi.Controllers;
7+
8+
/// <summary>
9+
/// Authentication controller for API key and token validation.
10+
/// </summary>
11+
/// <remarks>
12+
/// Provides endpoints for authentication validation and user information retrieval.
13+
/// Supports both API key authentication via x-gnx-apikey header and JWT Bearer token authentication.
14+
/// Used for authentication testing, token validation, and system integration verification.
15+
/// The authenticate endpoint is accessible with API key authentication without additional restrictions.
16+
/// </remarks>
17+
[Produces("application/json")]
18+
[Route("[controller]")]
19+
public class AuthenticateController : ControllerBase
20+
{
21+
/// <summary>
22+
/// Validate authentication and return user information.
23+
/// </summary>
24+
/// <remarks>
25+
/// <para>
26+
/// Authenticate endpoint with no auth restriction when API key is provided.
27+
/// This endpoint validates the current authentication state and returns user information.
28+
/// Supports both API key authentication (via x-gnx-apikey header) and JWT Bearer token authentication.
29+
/// When API key is provided, bypasses standard JWT validation requirements.
30+
/// Returns different user information based on the authentication method used.
31+
/// Essential for system integration testing and authentication verification workflows.
32+
/// </para>
33+
/// <para>
34+
/// Authentication Methods:
35+
/// 1. API Key: Include 'x-gnx-apikey' header with valid API key
36+
/// 2. JWT Token: Include 'Authorization: Bearer {token}' header
37+
/// </para>
38+
/// </remarks>
39+
/// <response code="200">Authentication successful with user information.</response>
40+
/// <response code="401">Authentication failed or missing credentials.</response>
41+
/// <returns>Authentication status and user information based on the authentication method.</returns>
42+
[ApiKeyOrJwtAuthorize]
43+
[HttpGet]
44+
[ProducesResponseType(typeof(AuthenticationResponse), StatusCodes.Status200OK)]
45+
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
46+
public IActionResult Authenticate()
47+
{
48+
var user = HttpContext.User;
49+
50+
if (user.Identity?.IsAuthenticated != true)
51+
{
52+
return Unauthorized("Authentication required");
53+
}
54+
55+
string authType = user.FindFirst("auth_type")?.Value ?? "unknown";
56+
string? userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
57+
string? userName = user.FindFirst(ClaimTypes.Name)?.Value;
58+
59+
var response = new AuthenticationResponse
60+
{
61+
IsAuthenticated = true,
62+
AuthenticationType = authType,
63+
UserId = userId,
64+
UserName = userName,
65+
Claims = [.. user.Claims.Select(c => new ClaimInfo
66+
{
67+
Type = c.Type,
68+
Value = c.Value
69+
})]
70+
};
71+
72+
return Ok(response);
73+
}
74+
75+
/// <summary>
76+
/// Get current user information (requires standard JWT authentication).
77+
/// </summary>
78+
/// <remarks>
79+
/// Get user information with standard JWT authentication requirement.
80+
/// This endpoint requires valid JWT Bearer token authentication and does not accept API key authentication.
81+
/// Returns detailed user information from the JWT token claims.
82+
/// Used for user profile access and authenticated user operations.
83+
/// Demonstrates standard authorization requirements compared to the flexible authenticate endpoint.
84+
/// </remarks>
85+
/// <response code="200">User information retrieved successfully.</response>
86+
/// <response code="401">JWT authentication required.</response>
87+
/// <returns>Current user information from JWT token.</returns>
88+
[Authorize]
89+
[HttpGet("me")]
90+
[ProducesResponseType(typeof(UserInfoResponse), StatusCodes.Status200OK)]
91+
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
92+
public IActionResult GetUserInfo()
93+
{
94+
var user = HttpContext.User;
95+
string? authType = user.Identity.AuthenticationType;
96+
97+
// Only allow JWT authentication for this endpoint
98+
if (authType != "AuthenticationTypes.Federation")
99+
{
100+
return Unauthorized("JWT Bearer token authentication required");
101+
}
102+
103+
var response = new UserInfoResponse
104+
{
105+
UserId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value,
106+
UserName = user.FindFirst(ClaimTypes.Name)?.Value,
107+
AuthenticationType = authType
108+
};
109+
110+
return Ok(response);
111+
}
112+
}

src/demo/Genocs.Core.Demo.WebApi/Controllers/AuthorizedController.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@ public class FirebaseAuthorizedController(ILogger<FirebaseAuthorizedController>
2626
/// Retrieves authorization information for the authenticated user.
2727
/// </summary>
2828
/// <remarks>
29+
/// <para>
2930
/// This endpoint demonstrates Firebase authorization by returning the authorization header
3031
/// from the authenticated request. It serves as a simple test to verify that Firebase
3132
/// authentication is working correctly.
32-
///
33-
/// **Important:** This endpoint requires the user to have the 'Editor' role.
34-
///
35-
/// Sample request:
36-
///
33+
/// </para>
34+
/// <para>**Important:** This endpoint requires the user to have the 'Editor' role.</para>
35+
/// <para>Sample request:</para>
36+
/// <para>
3737
/// GET /FirebaseAuthorized
3838
/// Authorization: Bearer your-firebase-jwt-token-here
39+
/// </para>
3940
///
4041
/// </remarks>
4142
/// <returns>A string containing the authorization header value from the request.</returns>
@@ -58,21 +59,24 @@ public async Task<IActionResult> GetAuthorizedAsync()
5859
/// Retrieves detailed user information and roles for debugging purposes.
5960
/// </summary>
6061
/// <remarks>
62+
/// <para>
6163
/// This endpoint returns detailed information about the authenticated user including
6264
/// all claims and roles assigned by the Firebase middleware. Useful for debugging
6365
/// authentication and authorization issues.
64-
///
66+
/// </para>
67+
/// <para>
6568
/// Returns information such as:
6669
/// - Authentication status
6770
/// - User ID and email
6871
/// - Email verification status
6972
/// - Assigned roles
7073
/// - All JWT claims
71-
///
72-
/// Sample request:
73-
///
74+
/// </para>
75+
/// <para>Sample request:</para>
76+
/// <para>
7477
/// GET /FirebaseAuthorized/user-info
7578
/// Authorization: Bearer your-firebase-jwt-token-here
79+
/// </para>
7680
///
7781
/// </remarks>
7882
/// <returns>An object containing user details and assigned roles.</returns>
@@ -107,13 +111,15 @@ public IActionResult GetUserInfo()
107111
/// Submits a request to join a team.
108112
/// </summary>
109113
/// <remarks>
114+
/// <para>
110115
/// This endpoint allows authenticated users to submit a request to join a team.
111116
/// The request is logged and can be processed by team administrators.
112-
///
113-
/// Sample request:
114-
///
117+
/// </para>
118+
/// <para>Sample request:</para>
119+
/// <para>
115120
/// GET /FirebaseAuthorized/join-request
116121
/// Authorization: Bearer your-firebase-jwt-token-here
122+
/// </para>
117123
///
118124
/// </remarks>
119125
/// <returns>A confirmation message indicating the join request was submitted.</returns>

0 commit comments

Comments
 (0)