aboutsummaryrefslogtreecommitdiff
path: root/libs/VNLib.Plugins.Sessions.OAuth
diff options
context:
space:
mode:
Diffstat (limited to 'libs/VNLib.Plugins.Sessions.OAuth')
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs10
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs4
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs9
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionConfig.cs5
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs18
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs51
6 files changed, 56 insertions, 41 deletions
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
index b73a7eb..ef5ff5c 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
@@ -58,7 +58,7 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
public AccessTokenEndpoint(PluginBase pbase, IConfigScope config, IApplicationTokenFactory tokenFactory)
{
- string? path = config["token_path"].GetString();;
+ string? path = config.GetRequiredProperty("token_path", p => p.GetString()!);
InitPathAndLog(path, pbase.Log);
@@ -111,14 +111,14 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
}
}
- entity.CloseResponseError(HttpStatusCode.BadRequest, ErrorType.InvalidClient, "Invalid grant type");
//Default to bad request
+ entity.CloseResponseError(HttpStatusCode.BadRequest, ErrorType.InvalidClient, "Invalid grant type");
return VfReturnType.VirtualSkip;
}
private async Task<VfReturnType> GenerateTokenAsync(HttpEntity entity, UserApplication? app)
{
- if (app == null)
+ if (app is null)
{
//App was not found or the credentials do not match
entity.CloseResponseError(HttpStatusCode.UnprocessableEntity, ErrorType.InvalidClient, "The credentials are invalid or do not exist");
@@ -127,9 +127,9 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
IOAuth2TokenResult? result = await TokenFactory.CreateAccessTokenAsync(entity, app, entity.EventCancellation);
- if (result == null)
+ if (result is null)
{
- entity.CloseResponseError(HttpStatusCode.TooManyRequests, ErrorType.TemporarilyUnabavailable, "You have reached the maximum number of valid tokens for this application");
+ entity.CloseResponseError(HttpStatusCode.TooManyRequests, ErrorType.TemporarilyUnavailable, "You have reached the maximum number of valid tokens for this application");
return VfReturnType.VirtualSkip;
}
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
index bdb4e4e..d21761c 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -38,7 +38,7 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
public RevocationEndpoint(PluginBase pbase, IConfigScope config)
{
- string? path = config["path"].GetString();
+ string? path = config.GetRequiredProperty("path", p => p.GetString()!);
InitPathAndLog(path, pbase.Log);
}
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs
index 6c9f3ab..1281afa 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2Session.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -36,12 +36,9 @@ namespace VNLib.Plugins.Sessions.OAuth
/// <summary>
/// The implementation of the OAuth2 session container for HTTP sessions
/// </summary>
- internal sealed class OAuth2Session : RemoteSession
+ internal sealed class OAuth2Session(string sessionId, IDictionary<string, string> data, bool isNew)
+ : RemoteSession(sessionId, data, isNew)
{
- public OAuth2Session(string sessionId, IDictionary<string, string> data, bool isNew)
- : base(sessionId, data, isNew)
- {}
-
public void InitNewSession(IHttpEvent entity)
{
SessionType = SessionType.OAuth2;
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionConfig.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionConfig.cs
index 5eb9c0c..9e612d5 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionConfig.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionConfig.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -44,6 +44,9 @@ namespace VNLib.Plugins.Sessions.OAuth
[JsonPropertyName("cache_prefix")]
public string CachePrefix { get; set; } = "oauth2";
+ [JsonPropertyName("access_token_type")]
+ public string TokenType { get; set; } = "Bearer";
+
public void Validate()
{
if (MaxTokensPerApp < 1)
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
index 20a429b..bc06052 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -74,19 +74,17 @@ namespace VNLib.Plugins.Sessions.OAuth
//Schedule interval
plugin.ScheduleInterval(this, TimeSpan.FromMinutes(2));
- IConfigScope o2Config = plugin.GetConfig(OAUTH2_CONFIG_KEY);
-
/*
* Route built-in oauth2 endpoints
*/
- if (o2Config.ContainsKey("token_path"))
+ if (config.ContainsKey("token_path"))
{
/*
* Access token endpoint requires this instance as a token manager
* which would cause a circular dependency, so it needs to be routed
* manually
*/
- AccessTokenEndpoint tokenEndpoint = new(plugin, o2Config, this);
+ AccessTokenEndpoint tokenEndpoint = new(plugin, config, this);
//Create token endpoint
plugin.Route(tokenEndpoint);
}
@@ -100,7 +98,8 @@ namespace VNLib.Plugins.Sessions.OAuth
}
/*
- * Called when
+ * Called in SessionProvider.dll to check if the current request can be processed
+ * as an oauth2 session
*/
public bool CanProcess(IHttpEvent entity)
{
@@ -108,6 +107,7 @@ namespace VNLib.Plugins.Sessions.OAuth
return _sessions.IsConnected && entity.Server.Headers.HeaderSet(HttpRequestHeader.Authorization);
}
+ ///<inheritdoc/>
public ValueTask<SessionHandle> GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
{
//Limit max number of waiting clients and make sure were connected
@@ -156,7 +156,7 @@ namespace VNLib.Plugins.Sessions.OAuth
private SessionHandle PostProcess(OAuth2Session? session)
{
- if (session == null)
+ if (session is null)
{
return SessionHandle.Empty;
}
@@ -252,9 +252,7 @@ namespace VNLib.Plugins.Sessions.OAuth
}
catch (Exception ex)
{
-#pragma warning disable CA1508 // Avoid dead conditional code
- errors ??= new();
-#pragma warning restore CA1508 // Avoid dead conditional code
+ errors ??= [];
errors.Add(ex);
}
}
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
index b97abae..6d055df 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -23,26 +23,21 @@
*/
using System;
+using System.Net;
+using System.Diagnostics.CodeAnalysis;
using VNLib.Hashing;
using VNLib.Net.Http;
using VNLib.Plugins.Sessions.Cache.Client;
using VNLib.Plugins.Extensions.Loading;
-using VNLib.Plugins.Essentials.Extensions;
-
namespace VNLib.Plugins.Sessions.OAuth
{
[ConfigurationName(OAuth2SessionProvider.OAUTH2_CONFIG_KEY)]
- internal sealed class OAuth2TokenFactory : ISessionIdFactory, IOauthSessionIdFactory
+ internal sealed class OAuth2TokenFactory(PluginBase plugin, IConfigScope config)
+ : ISessionIdFactory, IOauthSessionIdFactory
{
- private readonly OAuth2SessionConfig _config;
-
- public OAuth2TokenFactory(PluginBase plugin, IConfigScope config)
- {
- //Get the oauth2 config
- _config = config.DeserialzeAndValidate<OAuth2SessionConfig>();
- }
+ private readonly OAuth2SessionConfig _config = config.DeserialzeAndValidate<OAuth2SessionConfig>();
/*
* ID Regeneration is always false as OAuth2 sessions
@@ -68,13 +63,10 @@ namespace VNLib.Plugins.Sessions.OAuth
TimeSpan IOauthSessionIdFactory.SessionValidFor => TimeSpan.FromSeconds(_config.TokenLifeTimeSeconds);
///<inheritdoc/>
- string IOauthSessionIdFactory.TokenType => "Bearer";
+ string IOauthSessionIdFactory.TokenType => _config.TokenType;
///<inheritdoc/>
- bool ISessionIdFactory.CanService(IHttpEvent entity)
- {
- return entity.Server.HasAuthorization(out _);
- }
+ bool ISessionIdFactory.CanService(IHttpEvent entity) => HasBearerToken(entity.Server, out _);
///<inheritdoc/>
public GetTokenResult GenerateTokensAndId()
@@ -93,7 +85,32 @@ namespace VNLib.Plugins.Sessions.OAuth
string? ISessionIdFactory.TryGetSessionId(IHttpEvent entity)
{
- return entity.Server.HasAuthorization(out string? token) ? token : null;
+ return HasBearerToken(entity.Server, out string ? token) ? token : null;
+ }
+
+ /// <summary>
+ /// Gets the bearer token from an authorization header
+ /// </summary>
+ /// <param name="ci"></param>
+ /// <param name="token">The token stored in the user's authorization header</param>
+ /// <returns>True if the authorization header was set, has a Bearer token value</returns>
+ private bool HasBearerToken(IConnectionInfo ci, [NotNullWhen(true)] out string? token)
+ {
+ //Get auth header value
+ string? authorization = ci.Headers[HttpRequestHeader.Authorization];
+
+ //Check if its set
+ if (!string.IsNullOrWhiteSpace(authorization))
+ {
+ int bearerIndex = authorization.IndexOf(_config.TokenType, StringComparison.OrdinalIgnoreCase);
+
+ //Calc token offset, get token, and trim any whitespace
+ token = authorization.AsSpan(bearerIndex + _config.TokenType.Length).Trim().ToString();
+ return true;
+ }
+
+ token = null;
+ return false;
}
}
} \ No newline at end of file