aboutsummaryrefslogtreecommitdiff
path: root/plugins/VNLib.Plugins.Essentials.Accounts/src/MFA
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-19 13:56:27 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-19 13:56:27 -0400
commit78901f761e5b8358d02d1841bee4c60d97c94760 (patch)
treed7f6b4d268f74c422ab642249b9a92d72598c986 /plugins/VNLib.Plugins.Essentials.Accounts/src/MFA
parent9a73c170946020e6568de45e69a589d9896d565c (diff)
RestSharp version update, PKI optional login endpoint
Diffstat (limited to 'plugins/VNLib.Plugins.Essentials.Accounts/src/MFA')
-rw-r--r--plugins/VNLib.Plugins.Essentials.Accounts/src/MFA/UserMFAExtensions.cs73
1 files changed, 73 insertions, 0 deletions
diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/src/MFA/UserMFAExtensions.cs b/plugins/VNLib.Plugins.Essentials.Accounts/src/MFA/UserMFAExtensions.cs
index 28eb804..079c904 100644
--- a/plugins/VNLib.Plugins.Essentials.Accounts/src/MFA/UserMFAExtensions.cs
+++ b/plugins/VNLib.Plugins.Essentials.Accounts/src/MFA/UserMFAExtensions.cs
@@ -23,7 +23,9 @@
*/
using System;
+using System.Text;
using System.Linq;
+using System.Buffers;
using System.Text.Json;
using System.Collections.Generic;
using System.Security.Cryptography;
@@ -47,6 +49,8 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
public const string PGP_PUB_KEY = "mfa.pgpp";
public const string SESSION_SIG_KEY = "mfa.sig";
+ public const string USER_PKI_ENTRY = "mfa.pki";
+
/// <summary>
/// Determines if the user account has an
/// </summary>
@@ -188,6 +192,75 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
#endregion
+ #region PKI
+ const int JWK_KEY_BUFFER_SIZE = 2048;
+
+ /// <summary>
+ /// Gets a value that determines if the user has PKI enabled
+ /// </summary>
+ /// <param name="user"></param>
+ /// <returns>True if the user has a PKI key stored in their user account</returns>
+ public static bool PKIEnabled(this IUser user) => !string.IsNullOrWhiteSpace(user[USER_PKI_ENTRY]);
+
+ /// <summary>
+ /// Verifies a PKI login JWT against the user's stored login key data
+ /// </summary>
+ /// <param name="user">The user requesting a login</param>
+ /// <param name="jwt">The login jwt to verify</param>
+ /// <param name="keyId">The id of the key that generated the request, it must match the id of the stored key</param>
+ /// <returns>True if the user has PKI enabled, the key was recovered, the key id matches, and the JWT signature is verified</returns>
+ public static bool PKIVerifyUserJWT(this IUser user, JsonWebToken jwt, string keyId)
+ {
+ //Recover key data from user, it may not be enabled
+ using ReadOnlyJsonWebKey? jwk = RecoverKey(user);
+
+ if(jwk == null)
+ {
+ return false;
+ }
+
+ //Confim the key id matches
+ if(!keyId.Equals(jwk.KeyId, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ //verify the jwt
+ return jwt.VerifyFromJwk(jwk);
+ }
+
+ public static void PKISetUserKey(this IUser user, IReadOnlyDictionary<string, string>? keyData)
+ {
+ //Store key data
+ user.SetObject(USER_PKI_ENTRY, keyData);
+ }
+
+ private static ReadOnlyJsonWebKey? RecoverKey(IUser user)
+ {
+ string? keyData = user[USER_PKI_ENTRY];
+
+ if(string.IsNullOrEmpty(keyData))
+ {
+ return null;
+ }
+
+ //Get buffer to recover the key data from
+ byte[] buffer = ArrayPool<byte>.Shared.Rent(JWK_KEY_BUFFER_SIZE);
+ try
+ {
+ //Recover bytes and get the jwk from the data
+ int encoded = Encoding.UTF8.GetBytes(keyData, buffer);
+ return new ReadOnlyJsonWebKey(buffer.AsSpan(0, encoded));
+ }
+ finally
+ {
+ MemoryUtil.InitializeBlock(buffer.AsSpan());
+ ArrayPool<byte>.Shared.Return(buffer);
+ }
+ }
+
+ #endregion
+
#region pgp
private class PgpMfaCred