From 3bd7effc15d0b87adce01281b073aa1db67d3cba Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 6 Jan 2024 18:06:01 -0500 Subject: social portal conversion, pull provider libraries & include some prebuilts --- .../src/ClientClaimManager.cs | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 plugins/VNLib.Plugins.Essentials.Auth.Social/src/ClientClaimManager.cs (limited to 'plugins/VNLib.Plugins.Essentials.Auth.Social/src/ClientClaimManager.cs') diff --git a/plugins/VNLib.Plugins.Essentials.Auth.Social/src/ClientClaimManager.cs b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/ClientClaimManager.cs new file mode 100644 index 0000000..0c4f9ba --- /dev/null +++ b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/ClientClaimManager.cs @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Essentials.Auth.Social +* File: ClientClaimManager.cs +* +* ClientClaimManager.cs is part of VNLib.Plugins.Essentials.Auth.Social which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Essentials.Auth.Social 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.Auth.Social 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.Diagnostics.CodeAnalysis; + +using VNLib.Hashing; +using VNLib.Hashing.IdentityUtility; +using VNLib.Utils; +using VNLib.Utils.Memory; +using VNLib.Utils.Extensions; +using VNLib.Plugins.Essentials.Accounts; +using VNLib.Plugins.Essentials.Extensions; + +namespace VNLib.Plugins.Essentials.Auth.Social +{ + internal sealed record class ClientClaimManager(ICookieController Cookies) + { + const string SESSION_SIG_KEY_NAME = "soa.sig"; + const int SIGNING_KEY_SIZE = 32; + + public bool VerifyAndGetClaim(HttpEntity entity, [NotNullWhen(true)] out LoginClaim? claim) + { + claim = null; + + string? cookieValue = Cookies.GetCookie(entity); + + //Try to get the cookie + if (cookieValue == null) + { + return false; + } + + //Recover the signing key from the user's session + string sigKey = entity.Session[SESSION_SIG_KEY_NAME]; + Span key = stackalloc byte[SIGNING_KEY_SIZE + 16]; + + ERRNO keySize = VnEncoding.Base64UrlDecode(sigKey, key); + + if (keySize < 1) + { + return false; + } + + try + { + //Try to parse the jwt + using JsonWebToken jwt = JsonWebToken.Parse(cookieValue); + + //Verify the jwt + if (!jwt.Verify(key[..(int)keySize], HashAlg.SHA256)) + { + return false; + } + + //Recover the clam from the jwt + claim = jwt.GetPayload(); + + //Verify the expiration time + return claim.ExpirationSeconds > entity.RequestedTimeUtc.ToUnixTimeSeconds(); + } + catch (FormatException) + { + //JWT was corrupted and could not be parsed + return false; + } + finally + { + MemoryUtil.InitializeBlock(key); + } + } + + public void ClearClaimData(HttpEntity entity) + { + //Remove the upgrade cookie + Cookies.ExpireCookie(entity, false); + + //Clear the signing key from the session + entity.Session[SESSION_SIG_KEY_NAME] = null!; + } + + public void SignAndSetCookie(HttpEntity entity, LoginClaim claim) + { + //Setup Jwt + using JsonWebToken jwt = new(); + + //Write claim body, we dont need a header + jwt.WritePayload(claim, Statics.SR_OPTIONS); + + //Generate signing key + byte[] sigKey = RandomHash.GetRandomBytes(SIGNING_KEY_SIZE); + + //Sign the jwt + jwt.Sign(sigKey, HashAlg.SHA256); + + Cookies.SetCookie(entity, jwt.Compile()); + + //Encode and store the signing key in the clien't session + entity.Session[SESSION_SIG_KEY_NAME] = VnEncoding.ToBase64UrlSafeString(sigKey, false); + + //Clear the signing key + MemoryUtil.InitializeBlock(sigKey.AsSpan()); + } + } +} -- cgit