From fdb055f4687c59c5bd0859388dace05766f7ce06 Mon Sep 17 00:00:00 2001 From: vman Date: Fri, 4 Nov 2022 22:12:55 -0400 Subject: Jwt/jwk support, runtime provider updates --- .../MemorySessionStore.cs | 91 ++++++++++------------ 1 file changed, 40 insertions(+), 51 deletions(-) (limited to 'Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs') diff --git a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs index 15c3002..388f998 100644 --- a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs +++ b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; -using VNLib.Hashing; using VNLib.Net.Http; using VNLib.Net.Sessions; using VNLib.Utils; @@ -11,10 +10,10 @@ using VNLib.Utils.Async; using VNLib.Utils.Extensions; using VNLib.Plugins.Essentials.Extensions; +#nullable enable namespace VNLib.Plugins.Essentials.Sessions.Memory { - /// /// An for in-process-memory backed sessions /// @@ -23,11 +22,13 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory private readonly Dictionary SessionsStore; internal readonly MemorySessionConfig Config; + internal readonly SessionIdFactory IdFactory; public MemorySessionStore(MemorySessionConfig config) { Config = config; SessionsStore = new(config.MaxAllowedSessions, StringComparer.Ordinal); + IdFactory = new(config.SessionIdSizeBytes, config.SessionCookieID, config.SessionTimeout); } /// @@ -36,11 +37,11 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory static ValueTask SessionHandleClosedAsync(ISession session, IHttpEvent ev) { - return (session as MemorySession).UpdateAndRelease(true, ev); + return (session as MemorySession)!.UpdateAndRelease(true, ev); } - //Check for previous session cookie - if (entity.Server.RequestCookies.TryGetNonEmptyValue(Config.SessionCookieID, out string sessionId)) + //Try to get the id for the session + if (IdFactory.TryGetSessionId(entity, out string? sessionId)) { //Try to get the old record or evict it ERRNO result = SessionsStore.TryGetOrEvictRecord(sessionId, out MemorySession session); @@ -50,63 +51,51 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory await session.WaitOneAsync(cancellationToken); return new (session, SessionHandleClosedAsync); } - //Continue creating a new session + else + { + //try to cleanup expired records + GC(); + //Make sure there is enough room to add a new session + if (SessionsStore.Count >= Config.MaxAllowedSessions) + { + entity.Server.SetNoCache(); + //Set 503 when full + entity.CloseResponse(System.Net.HttpStatusCode.ServiceUnavailable); + //Cannot service new session + return new(null, FileProcessArgs.VirtualSkip, null); + } + //Initialze a new session + session = new(sessionId, entity.Server.GetTrustedIp(), UpdateSessionId); + //Increment the semaphore + (session as IWaitHandle).WaitOne(); + //store the session in cache while holding semaphore, and set its expiration + SessionsStore.StoreRecord(session.SessionID, session, Config.SessionTimeout); + //Init new session handle + return new (session, SessionHandleClosedAsync); + } } - - //Dont service non browsers for new sessions - if (!entity.Server.IsBrowser()) + else { return SessionHandle.Empty; } - - //try to cleanup expired records - SessionsStore.CollectRecords(); - //Make sure there is enough room to add a new session - if (SessionsStore.Count >= Config.MaxAllowedSessions) - { - entity.Server.SetNoCache(); - //Set 503 when full - entity.CloseResponse(System.Net.HttpStatusCode.ServiceUnavailable); - //Cannot service new session - return new(null, FileProcessArgs.VirtualSkip, null); - } - //Initialze a new session - MemorySession ms = new(entity.Server.GetTrustedIp(), this); - //Set session cookie - SetSessionCookie(entity, ms); - //Increment the semaphore - (ms as IWaitHandle).WaitOne(); - //store the session in cache while holding semaphore, and set its expiration - SessionsStore.StoreRecord(ms.SessionID, ms, Config.SessionTimeout); - //Init new session handle - return new SessionHandle(ms, SessionHandleClosedAsync); } - /// - /// Gets a new unique sessionid for sessions - /// - internal string NewSessionID => RandomHash.GetRandomHex((int)Config.SessionIdSizeBytes); - - internal void UpdateRecord(string newSessId, MemorySession session) + private string UpdateSessionId(IHttpEvent entity, string oldId) { + //Generate and set a new sessionid + string newid = IdFactory.GenerateSessionId(entity); + //Aquire lock on cache lock (SessionsStore) { - //Remove old record from the store - SessionsStore.Remove(session.SessionID); - //Insert the new session - SessionsStore.Add(newSessId, session); + //Change the cache lookup id + if (SessionsStore.Remove(oldId, out MemorySession? session)) + { + SessionsStore.Add(newid, session); + } } + return newid; } - /// - /// Sets a standard session cookie for an entity/connection - /// - /// The entity to set the cookie on - /// The session attached to the - internal void SetSessionCookie(IHttpEvent entity, MemorySession session) - { - //Set session cookie - entity.Server.SetCookie(Config.SessionCookieID, session.SessionID, null, "/", Config.SessionTimeout, CookieSameSite.Lax, true, true); - } + /// /// Evicts all sessions from the current store /// -- cgit