aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-11-02 01:50:06 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-11-02 01:50:06 -0400
commit9ddece0eac4dc3718c4f9279b4695d645a3e3cef (patch)
tree85f24fe1ee6f3845ef5bbb390530ea7e8042bbf2
parent43c9196b01799e334bde92e892f0bac47759901a (diff)
also carried away
-rw-r--r--libs/VNLib.Plugins.Sessions.Cache.Client/src/GlobalCacheStore.cs10
-rw-r--r--libs/VNLib.Plugins.Sessions.Cache.Client/src/IRemoteCacheStore.cs17
-rw-r--r--libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionDataSerialzer.cs47
-rw-r--r--libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionStore.cs9
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs6
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs3
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/O2AuthenticationPluginEntry.cs29
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/O2SessionProviderEntry.cs81
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs54
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionStore.cs27
-rw-r--r--libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs2
-rw-r--r--libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionIdFactory.cs26
-rw-r--r--libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProvider.cs31
-rw-r--r--libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProviderEntry.cs61
-rw-r--r--libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionStore.cs24
-rw-r--r--plugins/SessionProvider/src/RuntimeSessionProvider.cs54
-rw-r--r--plugins/SessionProvider/src/SessionProviderEntry.cs76
17 files changed, 229 insertions, 328 deletions
diff --git a/libs/VNLib.Plugins.Sessions.Cache.Client/src/GlobalCacheStore.cs b/libs/VNLib.Plugins.Sessions.Cache.Client/src/GlobalCacheStore.cs
index 89b2b5b..1770f0a 100644
--- a/libs/VNLib.Plugins.Sessions.Cache.Client/src/GlobalCacheStore.cs
+++ b/libs/VNLib.Plugins.Sessions.Cache.Client/src/GlobalCacheStore.cs
@@ -27,6 +27,7 @@ using System.Threading;
using System.Threading.Tasks;
using VNLib.Data.Caching;
+using VNLib.Utils.Logging;
namespace VNLib.Plugins.Sessions.Cache.Client
{
@@ -40,18 +41,19 @@ namespace VNLib.Plugins.Sessions.Cache.Client
private readonly IGlobalCacheProvider _cache;
private readonly SessionDataSerialzer _serialzer;
-
+
/// <summary>
/// Initiailzes a new <see cref="GlobalCacheStore"/> with the backing <see cref="IGlobalCacheProvider"/>
/// global cache
/// </summary>
/// <param name="globalCache">The backing cache store</param>
/// <param name="bufferSize">The size of the buffer used to serialize session objects</param>
+ /// <param name="debugLog">An optional log provider for writing serializing events to</param>
/// <exception cref="ArgumentNullException"></exception>
- public GlobalCacheStore(IGlobalCacheProvider globalCache, int bufferSize)
+ public GlobalCacheStore(IGlobalCacheProvider globalCache, int bufferSize, ILogProvider? debugLog)
{
_cache = globalCache ?? throw new ArgumentNullException(nameof(globalCache));
- _serialzer = new(bufferSize);
+ _serialzer = new(bufferSize, debugLog);
}
///<inheritdoc/>
@@ -64,7 +66,7 @@ namespace VNLib.Plugins.Sessions.Cache.Client
}
///<inheritdoc/>
- public Task DeleteObjectAsync(string objectId, CancellationToken cancellationToken = default)
+ public Task<bool> DeleteObjectAsync(string objectId, CancellationToken cancellationToken = default)
{
return _cache.DeleteAsync(objectId, cancellationToken);
}
diff --git a/libs/VNLib.Plugins.Sessions.Cache.Client/src/IRemoteCacheStore.cs b/libs/VNLib.Plugins.Sessions.Cache.Client/src/IRemoteCacheStore.cs
index aa2e3a7..b876c6c 100644
--- a/libs/VNLib.Plugins.Sessions.Cache.Client/src/IRemoteCacheStore.cs
+++ b/libs/VNLib.Plugins.Sessions.Cache.Client/src/IRemoteCacheStore.cs
@@ -41,9 +41,24 @@ namespace VNLib.Plugins.Sessions.Cache.Client
/// <returns>A task that resolves the found object or null otherwise</returns>
Task<T?> GetObjectAsync<T>(string objectId, CancellationToken cancellationToken = default);
+ /// <summary>
+ /// Adds or updates an object in the cache provider by session id and optionally it's new id
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="objectId">The session id to add or update</param>
+ /// <param name="newId">The uniqe id of the item to update</param>
+ /// <param name="obj"></param>
+ /// <param name="cancellationToken"></param>
+ /// <returns></returns>
Task AddOrUpdateObjectAsync<T>(string objectId, string? newId, T obj, CancellationToken cancellationToken = default);
- Task DeleteObjectAsync(string objectId, CancellationToken cancellationToken = default);
+ /// <summary>
+ /// Deletes an object from the cache provider by session id
+ /// </summary>
+ /// <param name="objectId">The id of the item to delete</param>
+ /// <param name="cancellationToken">A token to cancel the operation</param>
+ /// <returns>A value that indicates if the item was found and deleted</returns>
+ Task<bool> DeleteObjectAsync(string objectId, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a value that determines if the remote cache store is available
diff --git a/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionDataSerialzer.cs b/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionDataSerialzer.cs
index 1cebdf6..94bb1c3 100644
--- a/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionDataSerialzer.cs
+++ b/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionDataSerialzer.cs
@@ -25,9 +25,11 @@
using System;
using System.Text;
using System.Buffers;
+using System.Diagnostics;
using System.Collections.Generic;
using VNLib.Utils.Memory;
+using VNLib.Utils.Logging;
using VNLib.Utils.Extensions;
using VNLib.Data.Caching;
@@ -38,18 +40,48 @@ namespace VNLib.Plugins.Sessions.Cache.Client
/// Very basic session data serializer memory optimized for key-value
/// string pairs
/// </summary>
- internal sealed class SessionDataSerialzer : ICacheObjectSerialzer, ICacheObjectDeserialzer
+ internal sealed class SessionDataSerialzer : ICacheObjectSerializer, ICacheObjectDeserializer
{
const string KV_DELIMITER = "\0\0";
readonly int CharBufferSize;
+ readonly ILogProvider? _debugLog;
- public SessionDataSerialzer(int charBufferSize)
+ public SessionDataSerialzer(int charBufferSize, ILogProvider? debugLog)
{
CharBufferSize = charBufferSize;
+ _debugLog = debugLog;
+ debugLog?.Warn("Sensitive session logging is enabled. This will leak session data!");
}
- T? ICacheObjectDeserialzer.Deserialze<T>(ReadOnlySpan<byte> objectData) where T : default
+ [Conditional("DEBUG")]
+ private void DebugSessionItems(IDictionary<string, string> sessionData, bool serializing)
+ {
+ if (_debugLog is null)
+ {
+ return;
+ }
+
+ StringBuilder sdBuilder = new();
+ foreach (KeyValuePair<string, string> item in sessionData)
+ {
+ sdBuilder.Append(item.Key);
+ sdBuilder.Append('=');
+ sdBuilder.Append(item.Value);
+ sdBuilder.Append(", ");
+ }
+
+ if (serializing)
+ {
+ _debugLog.Debug("Serialzing session data: {sd} ", sdBuilder);
+ }
+ else
+ {
+ _debugLog.Debug("Deserialzing session data: {sd} ", sdBuilder);
+ }
+ }
+
+ T? ICacheObjectDeserializer.Deserialize<T>(ReadOnlySpan<byte> objectData) where T : default
{
if (!typeof(T).IsAssignableTo(typeof(IDictionary<string, string>)))
{
@@ -107,18 +139,23 @@ namespace VNLib.Plugins.Sessions.Cache.Client
reader.Advance(sep + 2);
}
+ DebugSessionItems(output, false);
+
return (T?)(output as object);
}
private static int GetNextToken(ref ForwardOnlyReader<char> reader) => reader.Window.IndexOf(KV_DELIMITER);
- void ICacheObjectSerialzer.Serialize<T>(T obj, IBufferWriter<byte> finiteWriter)
+ void ICacheObjectSerializer.Serialize<T>(T obj, IBufferWriter<byte> finiteWriter)
{
if(obj is not Dictionary<string, string> dict)
{
throw new NotSupportedException("Data type is not supported by this serializer");
}
-
+
+ //Write debug info
+ DebugSessionItems(dict, true);
+
//Alloc char buffer, sessions should be under 16k
using UnsafeMemoryHandle<char> charBuffer = MemoryUtil.UnsafeAllocNearestPage<char>(CharBufferSize);
diff --git a/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionStore.cs b/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionStore.cs
index 2709a65..0797efb 100644
--- a/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionStore.cs
+++ b/libs/VNLib.Plugins.Sessions.Cache.Client/src/SessionStore.cs
@@ -29,7 +29,6 @@ using System.Collections.Generic;
using VNLib.Net.Http;
using VNLib.Utils.Logging;
-using VNLib.Data.Caching.Exceptions;
using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Sessions.Cache.Client.Exceptions;
@@ -58,7 +57,7 @@ namespace VNLib.Plugins.Sessions.Cache.Client
/// <summary>
/// The backing cache store
/// </summary>
- protected abstract IRemoteCacheStore Cache { get; }
+ protected abstract IRemoteCacheStore Cache { get; }
/// <summary>
/// The session factory, produces sessions from their initial data and session-id
@@ -307,11 +306,7 @@ namespace VNLib.Plugins.Sessions.Cache.Client
try
{
//Update the session's data async
- await Cache.DeleteObjectAsync(session.SessionID);
- }
- catch(ObjectNotFoundException)
- {
- //ingore onfe, if the session does not exist in cache
+ _ = await Cache.DeleteObjectAsync(session.SessionID);
}
catch (Exception ex)
{
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
index 77cad38..dc0530f 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/AccessTokenEndpoint.cs
@@ -46,7 +46,6 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
/// Grants authorization to OAuth2 clients to protected resources
/// with access tokens
/// </summary>
- [ConfigurationName(O2SessionProviderEntry.OAUTH2_CONFIG_KEY)]
internal sealed class AccessTokenEndpoint : ResourceEndpointBase
{
private readonly IApplicationTokenFactory TokenFactory;
@@ -60,14 +59,13 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
DisableSessionsRequired = true
};
- public AccessTokenEndpoint(PluginBase pbase, IConfigScope config)
+ public AccessTokenEndpoint(PluginBase pbase, IConfigScope config, IApplicationTokenFactory tokenFactory)
{
string? path = config["token_path"].GetString();;
InitPathAndLog(path, pbase.Log);
- //Get the session provider, as its a token factory
- TokenFactory = pbase.GetOrCreateSingleton<OAuth2SessionProvider>();
+ TokenFactory = tokenFactory;
Applications = new(pbase.GetContextOptions(), pbase.GetOrCreateSingleton<ManagedPasswordHashing>());
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
index 45a8391..bdb4e4e 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/Endpoints/RevocationEndpoint.cs
@@ -46,8 +46,7 @@ namespace VNLib.Plugins.Sessions.OAuth.Endpoints
{
//Revoke the access token, by invalidating it
entity.Session.Invalidate();
- entity.CloseResponse(System.Net.HttpStatusCode.OK);
- return VfReturnType.VirtualSkip;
+ return VirtualOk(entity);
}
}
}
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/O2AuthenticationPluginEntry.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/O2AuthenticationPluginEntry.cs
index 5cd6aaf..1d74b7e 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/O2AuthenticationPluginEntry.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/O2AuthenticationPluginEntry.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
@@ -23,9 +23,13 @@
*/
using System;
-using System.Collections.Generic;
+
+using System.ComponentModel.Design;
using VNLib.Utils.Logging;
+using VNLib.Plugins.Attributes;
+using VNLib.Plugins.Essentials.Sessions;
+using VNLib.Plugins.Extensions.Loading;
namespace VNLib.Plugins.Sessions.OAuth
{
@@ -33,19 +37,20 @@ namespace VNLib.Plugins.Sessions.OAuth
{
public override string PluginName => "Essentials.Oauth.Authentication";
- private readonly O2SessionProviderEntry SessionProvider = new();
+ private OAuth2SessionProvider? SessionProvider;
+
+
+ [ServiceConfigurator]
+ public void OnServicesLoading(IServiceContainer services)
+ {
+ //Expose the OAuth2 session provider as a service singleton
+ services.AddService<ISessionProvider>(SessionProvider!);
+ }
protected override void OnLoad()
{
- try
- {
- //Load the session provider, that will only load the endpoints
- SessionProvider.Load(this, Log);
- }
- catch(KeyNotFoundException kne)
- {
- Log.Error("Missing required configuration keys {err}", kne.Message);
- }
+ SessionProvider = this.GetOrCreateSingleton<OAuth2SessionProvider>();
+ Log.Information("Plugin loaded");
}
protected override void OnUnLoad()
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/O2SessionProviderEntry.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/O2SessionProviderEntry.cs
deleted file mode 100644
index 0437541..0000000
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/O2SessionProviderEntry.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-* Copyright (c) 2023 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Essentials.Sessions.OAuth
-* File: O2SessionProviderEntry.cs
-*
-* O2SessionProviderEntry.cs is part of VNLib.Plugins.Essentials.Sessions.OAuth which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Plugins.Essentials.Sessions.OAuth is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 3 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Plugins.Essentials.Sessions.OAuth is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Net.Http;
-using VNLib.Utils.Logging;
-using VNLib.Plugins.Sessions.OAuth.Endpoints;
-using VNLib.Plugins.Essentials.Sessions;
-using VNLib.Plugins.Extensions.Loading;
-using VNLib.Plugins.Extensions.Loading.Routing;
-
-namespace VNLib.Plugins.Sessions.OAuth
-{
-
- public sealed class O2SessionProviderEntry : ISessionProvider
- {
- public const string OAUTH2_CONFIG_KEY = "oauth2";
-
- private OAuth2SessionProvider? _sessions;
-
- public bool CanProcess(IHttpEvent entity)
- {
- //If authorization header is set try to process as oauth2 session
- return _sessions != null && _sessions.IsConnected && entity.Server.Headers.HeaderSet(System.Net.HttpRequestHeader.Authorization);
- }
-
- ValueTask<SessionHandle> ISessionProvider.GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
- {
- return _sessions!.GetSessionAsync(entity, cancellationToken);
- }
-
- public void Load(PluginBase plugin, ILogProvider localized)
- {
- IConfigScope o2Config = plugin.GetConfig(OAUTH2_CONFIG_KEY);
-
- //Access token endpoint is optional
- if (o2Config.ContainsKey("token_path"))
- {
- //Create token endpoint
- plugin.Route<AccessTokenEndpoint>();
- }
-
- //Optional revocation endpoint
- if (plugin.HasConfigForType<RevocationEndpoint>())
- {
- //Route revocation endpoint
- plugin.Route<RevocationEndpoint>();
- }
-
- //Init session provider
- _sessions = plugin.GetOrCreateSingleton<OAuth2SessionProvider>();
- _sessions.SetLog(localized);
-
- localized.Information("Session provider loaded");
- }
- }
-} \ No newline at end of file
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
index b1b97b7..99bac29 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionProvider.cs
@@ -5,8 +5,8 @@
* Package: VNLib.Plugins.Essentials.Sessions.OAuth
* File: OAuth2SessionProvider.cs
*
-* OAuth2SessionProvider.cs is part of VNLib.Plugins.Essentials.Sessions.OAuth which is part of the larger
-* VNLib collection of libraries and utilities.
+* OAuth2SessionProvider.cs is part of VNLib.Plugins.Essentials.Sessions.OAuth
+* which is part of the larger VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Essentials.Sessions.OAuth is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -31,7 +31,6 @@ using System.Collections.Generic;
using VNLib.Net.Http;
using VNLib.Utils;
using VNLib.Utils.Logging;
-using VNLib.Data.Caching.Exceptions;
using VNLib.Plugins.Essentials;
using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Essentials.Oauth.Tokens;
@@ -39,6 +38,8 @@ using VNLib.Plugins.Essentials.Oauth.Applications;
using VNLib.Plugins.Extensions.Loading;
using VNLib.Plugins.Extensions.Loading.Sql;
using VNLib.Plugins.Extensions.Loading.Events;
+using VNLib.Plugins.Extensions.Loading.Routing;
+using VNLib.Plugins.Sessions.OAuth.Endpoints;
using static VNLib.Plugins.Essentials.Oauth.OauthSessionExtensions;
namespace VNLib.Plugins.Sessions.OAuth
@@ -47,9 +48,12 @@ namespace VNLib.Plugins.Sessions.OAuth
/// <summary>
/// Provides OAuth2 session management
/// </summary>
- [ConfigurationName(O2SessionProviderEntry.OAUTH2_CONFIG_KEY)]
- internal sealed class OAuth2SessionProvider : ISessionProvider, ITokenManager, IApplicationTokenFactory, IIntervalScheduleable
- {
+ [ExternService]
+ [ConfigurationName(OAUTH2_CONFIG_KEY)]
+ public sealed class OAuth2SessionProvider : ISessionProvider, ITokenManager, IApplicationTokenFactory, IIntervalScheduleable
+ {
+ public const string OAUTH2_CONFIG_KEY = "oauth2";
+
private static readonly SessionHandle Skip = new(null, FileProcessArgs.VirtualSkip, null);
private readonly OAuth2SessionStore _sessions;
@@ -60,8 +64,6 @@ namespace VNLib.Plugins.Sessions.OAuth
private uint _waitingConnections;
- public bool IsConnected => _sessions.IsConnected;
-
public OAuth2SessionProvider(PluginBase plugin, IConfigScope config)
{
_sessions = plugin.GetOrCreateSingleton<OAuth2SessionStore>();
@@ -71,9 +73,40 @@ 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"))
+ {
+ /*
+ * 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);
+ //Create token endpoint
+ plugin.Route(tokenEndpoint);
+ }
+
+ //Optional revocation endpoint
+ if (plugin.HasConfigForType<RevocationEndpoint>())
+ {
+ //Route revocation endpoint
+ plugin.Route<RevocationEndpoint>();
+ }
}
- public void SetLog(ILogProvider log) => _sessions.SetLog(log);
+ /*
+ * Called when
+ */
+ public bool CanProcess(IHttpEvent entity)
+ {
+ //If authorization header is set try to process as oauth2 session
+ return _sessions.IsConnected && entity.Server.Headers.HeaderSet(HttpRequestHeader.Authorization);
+ }
public ValueTask<SessionHandle> GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
{
@@ -217,9 +250,6 @@ namespace VNLib.Plugins.Sessions.OAuth
//Remove tokens by thier object id from cache
await _sessions.DeleteTokenAsync(token.Id, cancellationToken);
}
- //Ignore if the object has already been removed
- catch (ObjectNotFoundException)
- {}
catch (Exception ex)
{
#pragma warning disable CA1508 // Avoid dead conditional code
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionStore.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionStore.cs
index 8c65bc8..6cf25c4 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionStore.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2SessionStore.cs
@@ -34,19 +34,25 @@ using VNLib.Plugins.Sessions.Cache.Client;
using VNLib.Plugins.Extensions.VNCache;
using VNLib.Plugins.Extensions.Loading;
-
namespace VNLib.Plugins.Sessions.OAuth
{
- [ConfigurationName(O2SessionProviderEntry.OAUTH2_CONFIG_KEY)]
+ [ConfigurationName(OAuth2SessionProvider.OAUTH2_CONFIG_KEY)]
internal sealed class OAuth2SessionStore : SessionStore<OAuth2Session>
{
const int MAX_SESSION_BUFFER_SIZE = 16 * 1024;
private ILogProvider _log;
+ ///<inheritdoc/>
protected override ISessionIdFactory IdFactory { get; }
+
+ ///<inheritdoc/>
protected override IRemoteCacheStore Cache { get; }
+
+ ///<inheritdoc/>
protected override ISessionFactory<OAuth2Session> SessionFactory { get; }
+
+ ///<inheritdoc/>
protected override ILogProvider Log => _log;
public bool IsConnected => Cache.IsConnected;
@@ -56,11 +62,16 @@ namespace VNLib.Plugins.Sessions.OAuth
OAuth2SessionConfig o2Conf = config.DeserialzeAndValidate<OAuth2SessionConfig>();
//Get global cache
- IGlobalCacheProvider cache = plugin.GetOrCreateSingleton<VnGlobalCache>()
+ IGlobalCacheProvider? cache = plugin.GetDefaultGlobalCache()?
.GetPrefixedCache(o2Conf.CachePrefix, HashAlg.SHA256);
- //Create remote cache
- Cache = new GlobalCacheStore(cache, MAX_SESSION_BUFFER_SIZE);
+ _ = cache ?? throw new MissingDependencyException("A global cache provider is required to store OAuth2 sessions. Please configure a cache provider");
+
+ //Get debug log if enabled
+ ILogProvider? sessDebugLog = plugin.HostArgs.HasArgument("--debug-sessions") ? plugin.Log.CreateScope("OAuth2-Sessions") : null;
+
+ //Create cache store from global cache
+ Cache = new GlobalCacheStore(cache, MAX_SESSION_BUFFER_SIZE, sessDebugLog);
IdFactory = plugin.GetOrCreateSingleton<OAuth2TokenFactory>();
@@ -70,12 +81,6 @@ namespace VNLib.Plugins.Sessions.OAuth
_log = plugin.Log;
}
- public void SetLog(ILogProvider log)
- {
- _log = log;
- }
-
-
public Task DeleteTokenAsync(string token, CancellationToken cancellation)
{
return Cache.DeleteObjectAsync(token, cancellation);
diff --git a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
index b452e29..b97abae 100644
--- a/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
+++ b/libs/VNLib.Plugins.Sessions.OAuth/src/OAuth2TokenFactory.cs
@@ -33,7 +33,7 @@ using VNLib.Plugins.Essentials.Extensions;
namespace VNLib.Plugins.Sessions.OAuth
{
- [ConfigurationName(O2SessionProviderEntry.OAUTH2_CONFIG_KEY)]
+ [ConfigurationName(OAuth2SessionProvider.OAUTH2_CONFIG_KEY)]
internal sealed class OAuth2TokenFactory : ISessionIdFactory, IOauthSessionIdFactory
{
private readonly OAuth2SessionConfig _config;
diff --git a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionIdFactory.cs b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionIdFactory.cs
index 03d8980..3cdf56b 100644
--- a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionIdFactory.cs
+++ b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionIdFactory.cs
@@ -38,13 +38,14 @@ namespace VNLib.Plugins.Sessions.VNCache
/// <see cref="ISessionIdFactory"/> implementation, using
/// http cookies as session id storage
/// </summary>
- [ConfigurationName(WebSessionProviderEntry.WEB_SESSION_CONFIG)]
+ [ConfigurationName(WebSessionProvider.WEB_SESSION_CONFIG)]
internal sealed class WebSessionIdFactory : ISessionIdFactory
{
public TimeSpan ValidFor { get; }
///<inheritdoc/>
public bool RegenerationSupported { get; } = true;
+
///<inheritdoc/>
public bool RegenIdOnEmptyEntry { get; } = true;
@@ -65,13 +66,14 @@ namespace VNLib.Plugins.Sessions.VNCache
_cookieSize = (int)cookieSize;
}
- public WebSessionIdFactory(PluginBase pbase, IConfigScope config)
- {
- _cookieSize = (int)config["cookie_size"].GetUInt32();
- SessionCookieName = config["cookie_name"].GetString()
- ?? throw new KeyNotFoundException($"Missing required element 'cookie_name' for config '{WebSessionProviderEntry.WEB_SESSION_CONFIG}'");
- ValidFor = config["valid_for_sec"].GetTimeSpan(TimeParseType.Seconds);
- }
+ //Create instance from config
+ public WebSessionIdFactory(PluginBase plugin, IConfigScope config):
+ this(
+ config["cookie_size"].GetUInt32(),
+ config.GetRequiredProperty("cookie_name", p => p.GetString()!),
+ config["valid_for_sec"].GetTimeSpan(TimeParseType.Seconds)
+ )
+ { }
public string RegenerateId(IHttpEvent entity)
@@ -91,17 +93,13 @@ namespace VNLib.Plugins.Sessions.VNCache
};
//Set the session id cookie
- entity.Server.SetCookie(cookie);
+ entity.Server.SetCookie(in cookie);
//return session-id value from cookie value
return sessionId;
}
- public string? TryGetSessionId(IHttpEvent entity)
- {
- //Get session cookie
- return entity.Server.RequestCookies.GetValueOrDefault(SessionCookieName);
- }
+ public string? TryGetSessionId(IHttpEvent entity) => entity.Server.RequestCookies.GetValueOrDefault(SessionCookieName);
public bool CanService(IHttpEvent entity)
{
diff --git a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProvider.cs b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProvider.cs
index 655bae8..5516fef 100644
--- a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProvider.cs
+++ b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProvider.cs
@@ -27,6 +27,7 @@ using System.Threading;
using System.Threading.Tasks;
using VNLib.Net.Http;
+using VNLib.Utils.Logging;
using VNLib.Plugins.Essentials;
using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Extensions.Loading;
@@ -34,17 +35,20 @@ using VNLib.Plugins.Extensions.Loading;
namespace VNLib.Plugins.Sessions.VNCache
{
- [ConfigurationName(WebSessionProviderEntry.WEB_SESSION_CONFIG)]
- internal sealed class WebSessionProvider : ISessionProvider
+ [ExternService]
+ [ConfigurationName(WEB_SESSION_CONFIG)]
+ public sealed class WebSessionProvider : ISessionProvider
{
+ internal const string WEB_SESSION_CONFIG = "web";
+ internal const string LOGGER_SCOPE = "WEB-SESSIONS";
+
private static readonly SessionHandle _vf = new (null, FileProcessArgs.VirtualSkip, null);
private readonly WebSessionStore _sessions;
private readonly uint _maxConnections;
private uint _waitingConnections;
-
- public bool IsConnected => _sessions.IsConnected;
+
public WebSessionProvider(PluginBase plugin, IConfigScope config)
{
@@ -52,15 +56,20 @@ namespace VNLib.Plugins.Sessions.VNCache
//Init session provider
_sessions = plugin.GetOrCreateSingleton<WebSessionStore>();
- }
- private SessionHandle PostProcess(WebSession? session)
- {
- return session == null ? SessionHandle.Empty : new SessionHandle(session, OnSessionReleases);
+ ILogProvider logger = plugin.Log.CreateScope("WEB-SESSIONS");
+
+ logger.Information("Session provider loaded");
}
- private ValueTask OnSessionReleases(ISession session, IHttpEvent entity) => _sessions.ReleaseSessionAsync((WebSession)session, entity);
+ /*
+ * This is a dynamic method captured by the session loader to determine if the
+ * current session provider can process the incoming request.
+ */
+ public bool CanProcess(IHttpEvent entity) => _sessions.IsConnected;
+
+ ///<inheritdoc/>
public ValueTask<SessionHandle> GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
{
//Limit max number of waiting clients and make sure were connected
@@ -88,6 +97,10 @@ namespace VNLib.Plugins.Sessions.VNCache
}
}
+ private SessionHandle PostProcess(WebSession? session) => session == null ? SessionHandle.Empty : new (session, OnSessionReleases);
+
+ private ValueTask OnSessionReleases(ISession session, IHttpEvent entity) => _sessions.ReleaseSessionAsync((WebSession)session, entity);
+
private async Task<SessionHandle> AwaitAsyncGet(ValueTask<WebSession?> async)
{
//Inct wait count while async waiting
diff --git a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProviderEntry.cs b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProviderEntry.cs
deleted file mode 100644
index 3b1b1ac..0000000
--- a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionProviderEntry.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-* Copyright (c) 2023 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Essentials.Sessions.VNCache
-* File: WebSessionProviderEntry.cs
-*
-* WebSessionProviderEntry.cs is part of VNLib.Plugins.Essentials.Sessions.VNCache which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Plugins.Essentials.Sessions.VNCache is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 3 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Plugins.Essentials.Sessions.VNCache is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Net.Http;
-using VNLib.Utils.Logging;
-using VNLib.Plugins.Extensions.Loading;
-using VNLib.Plugins.Essentials.Sessions;
-
-namespace VNLib.Plugins.Sessions.VNCache
-{
-
- public sealed class WebSessionProviderEntry : ISessionProvider
- {
- internal const string WEB_SESSION_CONFIG = "web";
-
- private WebSessionProvider? _sessions;
-
-
- //Web sessions can always be provided so long as cache is loaded
- public bool CanProcess(IHttpEvent entity) => _sessions != null && _sessions.IsConnected;
-
- ValueTask<SessionHandle> ISessionProvider.GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
- {
- return _sessions!.GetSessionAsync(entity, cancellationToken);
- }
-
-
- public void Load(PluginBase plugin, ILogProvider localized)
- {
- //Load session provider
- _sessions = plugin.GetOrCreateSingleton<WebSessionProvider>();
-
- localized.Information("Session provider loaded");
- }
- }
-} \ No newline at end of file
diff --git a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionStore.cs b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionStore.cs
index c0b1e5d..ec515f6 100644
--- a/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionStore.cs
+++ b/libs/VNLib.Plugins.Sessions.VNCache/src/WebSessionStore.cs
@@ -37,7 +37,7 @@ using VNLib.Plugins.Essentials.Sessions;
namespace VNLib.Plugins.Sessions.VNCache
{
- [ConfigurationName(WebSessionProviderEntry.WEB_SESSION_CONFIG)]
+ [ConfigurationName(WebSessionProvider.WEB_SESSION_CONFIG)]
internal sealed class WebSessionStore : SessionStore<WebSession>
{
const int MAX_SESSION_BUFFER_SIZE = 16 * 1024;
@@ -49,10 +49,10 @@ namespace VNLib.Plugins.Sessions.VNCache
protected override ISessionFactory<WebSession> SessionFactory { get; }
protected override ILogProvider Log => baseLog!;
- public WebSessionStore(PluginBase pbase, IConfigScope config)
+ public WebSessionStore(PluginBase plugin, IConfigScope config)
{
//Get id factory
- IdFactory = pbase.GetOrCreateSingleton<WebSessionIdFactory>();
+ IdFactory = plugin.GetOrCreateSingleton<WebSessionIdFactory>();
//Session factory
SessionFactory = new WebSessionFactory();
@@ -62,24 +62,24 @@ namespace VNLib.Plugins.Sessions.VNCache
* the config
*/
- string cachePrefix = config["cache_prefix"].GetString()
- ?? throw new KeyNotFoundException($"Missing required element 'cache_prefix' for config '{WebSessionProviderEntry.WEB_SESSION_CONFIG}'");
+ string cachePrefix = config.GetRequiredProperty("cache_prefix", p => p.GetString()!);
//Create a simple prefix cache provider
- IGlobalCacheProvider cache = pbase.GetOrCreateSingleton<VnGlobalCache>()
+ IGlobalCacheProvider? cache = plugin.GetDefaultGlobalCache()?
.GetPrefixedCache(cachePrefix, HashAlg.SHA256);
+ _ = cache ?? throw new MissingDependencyException("A global cache provider is required to store VNCache sessions. Please configure a cache provider");
+
+ //Get debug log if enabled
+ ILogProvider? sessDebugLog = plugin.HostArgs.HasArgument("--debug-sessions") ? plugin.Log.CreateScope("VNCache-Sessions") : null;
+
//Create cache store from global cache
- Cache = new GlobalCacheStore(cache, MAX_SESSION_BUFFER_SIZE);
+ Cache = new GlobalCacheStore(cache, MAX_SESSION_BUFFER_SIZE, sessDebugLog);
//Default log to plugin log
- baseLog = pbase.Log;
+ baseLog = plugin.Log.CreateScope(WebSessionProvider.LOGGER_SCOPE);
}
- public void InitLog(ILogProvider log)
- {
- baseLog = log;
- }
/// <summary>
/// A value that indicates if the remote cache client is connected
diff --git a/plugins/SessionProvider/src/RuntimeSessionProvider.cs b/plugins/SessionProvider/src/RuntimeSessionProvider.cs
index 28397c9..1058e2e 100644
--- a/plugins/SessionProvider/src/RuntimeSessionProvider.cs
+++ b/plugins/SessionProvider/src/RuntimeSessionProvider.cs
@@ -26,58 +26,28 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-using VNLib.Utils;
-using VNLib.Utils.Logging;
using VNLib.Net.Http;
-using VNLib.Plugins.Extensions.Loading;
+using VNLib.Utils.Resources;
namespace VNLib.Plugins.Essentials.Sessions
{
- internal sealed class RuntimeSessionProvider : VnDisposeable, ISessionProvider
+ internal sealed class RuntimeSessionProvider : ISessionProvider
{
- private readonly AssemblyLoader<ISessionProvider> _asm;
-
- private Func<IHttpEvent, bool> _canProcessMethod;
- private Action<PluginBase, ILogProvider> _loadMethod;
- private ISessionProvider _ref;
+ private readonly Func<IHttpEvent, bool> _canProcessMethod;
+ private readonly ISessionProvider _ref;
- public RuntimeSessionProvider(AssemblyLoader<ISessionProvider> asm)
+ public RuntimeSessionProvider(ISessionProvider externProvider)
{
- _asm = asm;
+ _ref = externProvider;
- //Store ref to the resource to avoid loads
- _ref = asm.Resource;
-
- //Get load method
- _loadMethod = asm.TryGetMethod<Action<PluginBase, ILogProvider>>("Load")
- ?? throw new MissingMethodException("Provider is missing required Load method");
-
- //Load canprocess method
- _canProcessMethod = asm.TryGetMethod<Func<IHttpEvent, bool>>("CanProcess")
- ?? throw new MissingMethodException("Provider is missing required CanProcess method");
- }
-
- public ValueTask<SessionHandle> GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken)
- {
- return _ref.GetSessionAsync(entity, cancellationToken);
- }
-
- public bool CanProcess(IHttpEvent ev)
- {
- return _canProcessMethod(ev);
+ //Load canprocess method dynamically
+ _canProcessMethod = ManagedLibrary.GetMethod<Func<IHttpEvent, bool>>(externProvider, "CanProcess");
}
- public void Load(PluginBase pbase, ILogProvider localized)
- {
- _loadMethod(pbase, localized);
- }
+ ///<inheritdoc/>
+ public ValueTask<SessionHandle> GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken) => _ref.GetSessionAsync(entity, cancellationToken);
- protected override void Free()
- {
- _asm.Dispose();
- _canProcessMethod = null!;
- _loadMethod = null!;
- _ref = null!;
- }
+ ///<inheritdoc/>
+ public bool CanProcess(IHttpEvent ev) => _canProcessMethod(ev);
}
}
diff --git a/plugins/SessionProvider/src/SessionProviderEntry.cs b/plugins/SessionProvider/src/SessionProviderEntry.cs
index 61808d1..b5ba6fa 100644
--- a/plugins/SessionProvider/src/SessionProviderEntry.cs
+++ b/plugins/SessionProvider/src/SessionProviderEntry.cs
@@ -23,7 +23,6 @@
*/
using System;
-using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -33,7 +32,6 @@ using System.ComponentModel.Design;
using VNLib.Net.Http;
using VNLib.Utils;
using VNLib.Utils.Logging;
-using VNLib.Utils.Extensions;
using VNLib.Plugins.Attributes;
using VNLib.Plugins.Extensions.Loading;
@@ -67,65 +65,46 @@ namespace VNLib.Plugins.Essentials.Sessions
{
List<RuntimeSessionProvider> providers = new();
- try
- {
- Log.Verbose("Loading all specified session providers");
+ Log.Verbose("Loading all specified session providers");
- //Get all provider names
- IEnumerable<string> providerAssemblyNames = PluginConfig.GetProperty("provider_assemblies")
+ //Get all provider names
+ IEnumerable<string> providerAssemblyNames = PluginConfig.GetProperty("provider_assemblies")
.EnumerateArray()
.Where(s => s.GetString() != null)
.Select(s => s.GetString()!);
-
-
- foreach(string asm in providerAssemblyNames)
- {
- Log.Verbose("Loading {dll} session provider", asm);
-
- //Attempt to load provider
- AssemblyLoader<ISessionProvider> prov = this.LoadAssembly<ISessionProvider>(asm);
-
- try
- {
- //Create localized log
- ILogProvider scopded = Log.CreateScope(Path.GetFileName(asm));
- RuntimeSessionProvider p = new(prov);
-
- //Call load method
- p.Load(this, scopded);
-
- //Add to list
- providers.Add(p);
- }
- catch
- {
- prov.Dispose();
- throw;
- }
- }
+ foreach (string asm in providerAssemblyNames)
+ {
+ Log.Verbose("Loading {dll} session provider", asm);
- if(providers.Count > 0)
+ try
{
- //Create array for searching for providers
- _provider = new(providers.ToArray());
+ //Attempt to load provider
+ ISessionProvider prov = this.CreateServiceExternal<ISessionProvider>(asm);
- Log.Information("Loaded {count} session providers", providers.Count);
+ //Add to list
+ providers.Add(new(prov));
}
- else
+ catch (Exception ex)
{
- Log.Information("No session providers loaded");
+ Log.Error("Failed to load session provider {dll}:\n{error}", asm, ex);
}
+ }
- Log.Information("Plugin loaded");
+ if (providers.Count > 0)
+ {
+ //Create array for searching for providers
+ _provider = new(providers.ToArray());
+
+ Log.Information("Loaded {count} session providers", providers.Count);
}
- catch
+ else
{
- //Dispose providers
- providers.ForEach(static s => s.Dispose());
- throw;
+ Log.Information("No session providers loaded");
}
+
+ Log.Information("Plugin loaded");
}
protected override void OnUnLoad()
@@ -173,16 +152,13 @@ namespace VNLib.Plugins.Essentials.Sessions
}
//Return empty session
- return new ValueTask<SessionHandle>(SessionHandle.Empty);
+ return new (SessionHandle.Empty);
}
protected override void Free()
{
//Remove current providers so we can dispose them
- RuntimeSessionProvider[] current = Interlocked.Exchange(ref ProviderArray, Array.Empty<RuntimeSessionProvider>());
-
- //Cleanup assemblies
- current.TryForeach(static p => p.Dispose());
+ ProviderArray = Array.Empty<RuntimeSessionProvider>();
}
}
}