aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VNLib.Plugins.Essentials.Accounts.Admin/VNLib.Plugins.Essentials.Accounts.Admin.csproj2
-rw-r--r--VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs13
-rw-r--r--VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs5
-rw-r--r--VNLib.Plugins.Essentials.Accounts/Endpoints/LoginEndpoint.cs19
-rw-r--r--VNLib.Plugins.Essentials.Accounts/Endpoints/LogoutEndpoint.cs7
-rw-r--r--VNLib.Plugins.Essentials.Accounts/MFA/MFAConfig.cs3
-rw-r--r--VNLib.Plugins.Essentials.Accounts/MFA/MFAType.cs2
-rw-r--r--VNLib.Plugins.Essentials.Accounts/MFA/UserMFAExtensions.cs55
-rw-r--r--VNLib.Plugins.Essentials.Accounts/VNLib.Plugins.Essentials.Accounts.csproj2
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/Endpoints/Auth0.cs45
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/Endpoints/DiscordOauth.cs30
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/Endpoints/GitHubOauth.cs37
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/OauthClientConfig.cs14
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/SocialOauthBase.cs6
-rw-r--r--VNLib.Plugins.Essentials.SocialOauth/VNLib.Plugins.Essentials.SocialOauth.csproj2
15 files changed, 119 insertions, 123 deletions
diff --git a/VNLib.Plugins.Essentials.Accounts.Admin/VNLib.Plugins.Essentials.Accounts.Admin.csproj b/VNLib.Plugins.Essentials.Accounts.Admin/VNLib.Plugins.Essentials.Accounts.Admin.csproj
index 00afb08..53cc189 100644
--- a/VNLib.Plugins.Essentials.Accounts.Admin/VNLib.Plugins.Essentials.Accounts.Admin.csproj
+++ b/VNLib.Plugins.Essentials.Accounts.Admin/VNLib.Plugins.Essentials.Accounts.Admin.csproj
@@ -27,7 +27,7 @@
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\..\VNLib\Essentials\VNLib.Plugins.Essentials.csproj" />
+ <ProjectReference Include="..\..\..\VNLib\Essentials\src\VNLib.Plugins.Essentials.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Data\VNLib.Plugins.Extensions.Data.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Loading.Sql\VNLib.Plugins.Extensions.Loading.Sql.csproj" />
<ProjectReference Include="..\..\PluginBase\VNLib.Plugins.PluginBase.csproj" />
diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs
index 56c7f37..238ae37 100644
--- a/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs
+++ b/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs
@@ -65,17 +65,18 @@ namespace VNLib.Plugins.Essentials.Accounts.Registration
//Load oauth secrets from vault
- Task<string?> oauth2ClientID = pbase.TryGetSecretAsync("oauth2_client_id");
- Task<string?> oauth2Password = pbase.TryGetSecretAsync("oauth2_client_secret");
+ Task<SecretResult?> oauth2ClientID = pbase.TryGetSecretAsync("oauth2_client_id");
+ Task<SecretResult?> oauth2Password = pbase.TryGetSecretAsync("oauth2_client_secret");
//Lazy cred loaded, tasks should be loaded before this method will ever get called
Credential lazyCredentialGet()
{
//Load the results
- string cliendId = oauth2ClientID.Result ?? throw new KeyNotFoundException("Missing required oauth2 client id");
- string password = oauth2Password.Result ?? throw new KeyNotFoundException("Missing required oauth2 client secret");
+ SecretResult cliendId = oauth2ClientID.Result ?? throw new KeyNotFoundException("Missing required oauth2 client id");
+ SecretResult password = oauth2Password.Result ?? throw new KeyNotFoundException("Missing required oauth2 client secret");
- return Credential.Create(cliendId, password);
+ //Creat credential
+ return Credential.Create(cliendId.Result, password.Result);
}
@@ -113,6 +114,8 @@ namespace VNLib.Plugins.Essentials.Accounts.Registration
{
authenticator.Dispose();
RestClientPool.Dispose();
+ oauth2ClientID.Dispose();
+ oauth2Password.Dispose();
}
//register password cleanup
diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs
index 1e983cb..b56cb3c 100644
--- a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs
+++ b/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs
@@ -100,8 +100,9 @@ namespace VNLib.Plugins.Essentials.Accounts.Registration.Endpoints
//Begin the async op to get the signature key from the vault
RegSignatureKey = plugin.TryGetSecretAsync("reg_sig_key").ContinueWith((ts) => {
- _ = ts.Result ?? throw new KeyNotFoundException("Missing required key 'reg_sig_key' in 'registration' configuration");
- return Convert.FromBase64String(ts.Result);
+ using SecretResult? sr = ts.Result ?? throw new KeyNotFoundException("Missing required key 'reg_sig_key' in 'registration' configuration");
+ return ts.Result.GetFromBase64();
+
}, TaskScheduler.Default);
//Register timeout for cleanup
diff --git a/VNLib.Plugins.Essentials.Accounts/Endpoints/LoginEndpoint.cs b/VNLib.Plugins.Essentials.Accounts/Endpoints/LoginEndpoint.cs
index a4254de..4100620 100644
--- a/VNLib.Plugins.Essentials.Accounts/Endpoints/LoginEndpoint.cs
+++ b/VNLib.Plugins.Essentials.Accounts/Endpoints/LoginEndpoint.cs
@@ -68,9 +68,6 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints
private readonly uint MaxFailedLogins;
private readonly TimeSpan FailedCountTimeout;
- ///<inheritdoc/>
- protected override ProtectionSettings EndpointProtectionSettings { get; } = new();
-
public LoginEndpoint(PluginBase pbase, IReadOnlyDictionary<string, JsonElement> config)
{
string? path = config["path"].GetString();
@@ -298,15 +295,19 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints
return VfReturnType.VirtualSkip;
}
- //Wipe session signature
- entity.Session.MfaUpgradeSignature(null);
+ bool locked = UserLoginLocked(user);
//Make sure the account has not been locked out
- if (!webm.Assert(!UserLoginLocked(user), LOCKED_ACCOUNT_MESSAGE))
+ if (!webm.Assert(locked == false, LOCKED_ACCOUNT_MESSAGE))
{
//process mfa login
LoginMfa(entity, user, request, upgrade, webm);
}
+ else
+ {
+ //Locked, so clear stored signature
+ entity.Session.MfaUpgradeSignature(null);
+ }
//Update user on clean process
await user.ReleaseAsync();
@@ -338,7 +339,7 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints
//Valid, complete
}
break;
- case MFAType.GPG:
+ case MFAType.PGP:
{ }
break;
default:
@@ -347,6 +348,10 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints
}
return;
}
+
+ //Wipe session signature
+ entity.Session.MfaUpgradeSignature(null);
+
//build login message from upgrade
LoginMessage loginMessage = new()
{
diff --git a/VNLib.Plugins.Essentials.Accounts/Endpoints/LogoutEndpoint.cs b/VNLib.Plugins.Essentials.Accounts/Endpoints/LogoutEndpoint.cs
index f5d12ec..cc36609 100644
--- a/VNLib.Plugins.Essentials.Accounts/Endpoints/LogoutEndpoint.cs
+++ b/VNLib.Plugins.Essentials.Accounts/Endpoints/LogoutEndpoint.cs
@@ -34,12 +34,7 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints
{
[ConfigurationName("logout_endpoint")]
internal class LogoutEndpoint : ProtectedWebEndpoint
- {
- //Use default ep protection (most strict)
-
- ///<inheritdoc/>
- protected override ProtectionSettings EndpointProtectionSettings { get; } = new();
-
+ {
public LogoutEndpoint(PluginBase pbase, IReadOnlyDictionary<string, JsonElement> config)
{
diff --git a/VNLib.Plugins.Essentials.Accounts/MFA/MFAConfig.cs b/VNLib.Plugins.Essentials.Accounts/MFA/MFAConfig.cs
index f04693e..03d5a20 100644
--- a/VNLib.Plugins.Essentials.Accounts/MFA/MFAConfig.cs
+++ b/VNLib.Plugins.Essentials.Accounts/MFA/MFAConfig.cs
@@ -29,12 +29,13 @@ using System.Collections.Generic;
using VNLib.Hashing;
using VNLib.Utils.Extensions;
+using VNLib.Hashing.IdentityUtility;
namespace VNLib.Plugins.Essentials.Accounts.MFA
{
internal class MFAConfig
{
- public byte[]? MFASecret { get; set; }
+ public ReadOnlyJsonWebKey? MFASecret { get; set; }
public bool TOTPEnabled { get; }
public string? IssuerName { get; }
diff --git a/VNLib.Plugins.Essentials.Accounts/MFA/MFAType.cs b/VNLib.Plugins.Essentials.Accounts/MFA/MFAType.cs
index 3ace3e6..208eea3 100644
--- a/VNLib.Plugins.Essentials.Accounts/MFA/MFAType.cs
+++ b/VNLib.Plugins.Essentials.Accounts/MFA/MFAType.cs
@@ -26,6 +26,6 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
{
public enum MFAType
{
- TOTP, FIDO, GPG
+ TOTP, FIDO, PGP
}
}
diff --git a/VNLib.Plugins.Essentials.Accounts/MFA/UserMFAExtensions.cs b/VNLib.Plugins.Essentials.Accounts/MFA/UserMFAExtensions.cs
index 6675a31..4fa76ef 100644
--- a/VNLib.Plugins.Essentials.Accounts/MFA/UserMFAExtensions.cs
+++ b/VNLib.Plugins.Essentials.Accounts/MFA/UserMFAExtensions.cs
@@ -34,7 +34,6 @@ using System.Runtime.CompilerServices;
using VNLib.Hashing;
using VNLib.Utils;
using VNLib.Utils.Memory;
-using VNLib.Utils.Logging;
using VNLib.Utils.Extensions;
using VNLib.Hashing.IdentityUtility;
using VNLib.Plugins.Essentials.Users;
@@ -122,16 +121,6 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
private static bool VerifyTOTP(uint totpCode, ReadOnlySpan<byte> userSecret, MFAConfig config)
{
- //Calc hash size for allocating bufffer
- int hashSize = config.TOTPAlg switch
- {
- HashAlg.MD5 => (160 / 8),
- HashAlg.SHA1 => (160 / 8),
- HashAlg.SHA512 => (512 / 8),
- HashAlg.SHA384 => (384 / 8),
- HashAlg.SHA256 => (256 / 8),
- _ => throw new ArgumentException("Invalid hash algorithm"),
- };
//A basic attempt at a constant time TOTP verification, run the calculation a fixed number of times, regardless of the resutls
bool codeMatches = false;
@@ -140,7 +129,7 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
//Start the current window with the minimum window
int currenStep = -config.TOTPTimeWindowSteps;
Span<byte> stepBuffer = stackalloc byte[sizeof(long)];
- Span<byte> hashBuffer = stackalloc byte[hashSize];
+ Span<byte> hashBuffer = stackalloc byte[(int)config.TOTPAlg];
//Run the loop at least once to allow a 0 step tight window
do
{
@@ -159,7 +148,7 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
//try to compute the hash of the time step
if (result < 1)
{
- throw new OutOfMemoryException("Failed to compute TOTP time step hash because the buffer was too small");
+ throw new InternalBufferTooSmallException("Failed to compute TOTP time step hash because the buffer was too small");
}
//Hash bytes
ReadOnlySpan<byte> hash = hashBuffer[..(int)result];
@@ -230,9 +219,10 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
//Recover secret from config and dangerous 'lazy load'
_ = pbase.DeferTask(async () =>
{
- string? secret = await pbase.TryGetSecretAsync("mfa_secret");
- mfa.MFASecret = secret != null ? Convert.FromBase64String(secret) : null;
- });
+ using SecretResult? secret = await pbase.TryGetSecretAsync("mfa_secret");
+ mfa.MFASecret = secret != null ? secret.GetJsonWebKey() : null;
+
+ },50);
return mfa;
}
@@ -276,12 +266,6 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
#endregion
#region webauthn
-
- private static readonly IReadOnlyDictionary<string, string> JWTHeader = new Dictionary<string, string>
- {
- { "alg", "HS384" },
- { "typ" , "JWT"}
- };
#endregion
@@ -294,10 +278,10 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
/// <param name="upgrade">The recovered upgrade</param>
/// <param name="base64sessionSig">The stored base64 encoded signature from the session that requested an upgrade</param>
/// <returns>True if the upgrade was verified, not expired, and was recovered from the signed message, false otherwise</returns>
- public static bool RecoverUpgrade(this MFAConfig config, string upgradeJwtString, string base64sessionSig, [NotNullWhen(true)] out MFAUpgrade? upgrade)
+ public static bool RecoverUpgrade(this MFAConfig config, ReadOnlySpan<char> upgradeJwtString, ReadOnlySpan<char> base64sessionSig, [NotNullWhen(true)] out MFAUpgrade? upgrade)
{
//Verifies a jwt stored signature against the actual signature
- static bool VerifyStoredSig(string base64string, ReadOnlySpan<byte> signature)
+ static bool VerifyStoredSig(ReadOnlySpan<char> base64string, ReadOnlySpan<byte> signature)
{
using UnsafeMemoryHandle<byte> buffer = Memory.UnsafeAlloc<byte>(base64string.Length, true);
//Recover base64
@@ -310,15 +294,13 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
_ = config.MFASecret ?? throw new InvalidOperationException("MFA config is missing required upgrade signing key");
upgrade = null;
+
//Parse jwt
using JsonWebToken jwt = JsonWebToken.Parse(upgradeJwtString);
- //Verify the upgrade jwt
- using (HMACSHA384 hmac = new(config.MFASecret))
+
+ if (!jwt.VerifyFromJwk(config.MFASecret))
{
- if (!jwt.Verify(hmac))
- {
- return false;
- }
+ return false;
}
if(!VerifyStoredSig(base64sessionSig, jwt.SignatureData))
@@ -382,13 +364,13 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
return null;
}
- private static Tuple<string, string> GetUpgradeMessage(MFAUpgrade upgrade, byte[] secret, TimeSpan expires)
+ private static Tuple<string, string> GetUpgradeMessage(MFAUpgrade upgrade, ReadOnlyJsonWebKey secret, TimeSpan expires)
{
//Add some random entropy to the upgrade message, to help prevent forgery
string entropy = RandomHash.GetRandomBase32(16);
//Init jwt
using JsonWebToken upgradeJwt = new();
- upgradeJwt.WriteHeader(JWTHeader);
+ upgradeJwt.WriteHeader(secret.JwtHeader);
//Write claims
upgradeJwt.InitPayloadClaim()
.AddClaim("iat", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
@@ -397,11 +379,10 @@ namespace VNLib.Plugins.Essentials.Accounts.MFA
.AddClaim("expires", expires.TotalSeconds)
.AddClaim("a", entropy)
.CommitClaims();
- //Sign
- using (HMACSHA384 hmc = new(secret))
- {
- upgradeJwt.Sign(hmc);
- }
+
+ //Sign with jwk
+ upgradeJwt.SignFromJwk(secret);
+
//compile and return jwt upgrade
return new(upgradeJwt.Compile(), Convert.ToBase64String(upgradeJwt.SignatureData));
}
diff --git a/VNLib.Plugins.Essentials.Accounts/VNLib.Plugins.Essentials.Accounts.csproj b/VNLib.Plugins.Essentials.Accounts/VNLib.Plugins.Essentials.Accounts.csproj
index 719f8df..15ac5e5 100644
--- a/VNLib.Plugins.Essentials.Accounts/VNLib.Plugins.Essentials.Accounts.csproj
+++ b/VNLib.Plugins.Essentials.Accounts/VNLib.Plugins.Essentials.Accounts.csproj
@@ -40,7 +40,7 @@
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\..\VNLib\Essentials\VNLib.Plugins.Essentials.csproj" />
+ <ProjectReference Include="..\..\..\VNLib\Essentials\src\VNLib.Plugins.Essentials.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Loading.Sql\VNLib.Plugins.Extensions.Loading.Sql.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Validation\VNLib.Plugins.Extensions.Validation.csproj" />
<ProjectReference Include="..\..\PluginBase\VNLib.Plugins.PluginBase.csproj" />
diff --git a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/Auth0.cs b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/Auth0.cs
index 8518ea0..c7512b7 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/Auth0.cs
+++ b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/Auth0.cs
@@ -40,46 +40,51 @@ using VNLib.Plugins.Essentials.Accounts;
using VNLib.Plugins.Extensions.Loading;
using VNLib.Plugins.Extensions.Loading.Users;
-#nullable enable
-
namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
{
[ConfigurationName("auth0")]
- internal class Auth0 : SocialOauthBase
+ internal sealed class Auth0 : SocialOauthBase
{
+
protected override OauthClientConfig Config { get; }
- private readonly Task<JsonDocument> RsaCertificate;
+ private readonly Task<JsonDocument> Auth0VerificationJwk;
- public Auth0(PluginBase plugin, IReadOnlyDictionary<string, JsonElement> config)
+ public Auth0(PluginBase plugin, IReadOnlyDictionary<string, JsonElement> config) : base()
{
- //Get id/secret
- Task<string?> secret = plugin.TryGetSecretAsync("auth0_client_secret");
- Task<string?> clientId = plugin.TryGetSecretAsync("auth0_client_id");
+ string keyUrl = config["key_url"].GetString() ?? throw new KeyNotFoundException("Missing Auth0 'key_url' from config");
- //Wait sync
- Task.WaitAll(secret, clientId);
+ Uri keyUri = new(keyUrl);
+
+ //Get certificate on background thread
+ Auth0VerificationJwk = Task.Run(() => GetRsaCertificate(keyUri));
Config = new("auth0", config)
{
- //get gh client secret and id
- ClientID = clientId.Result ?? throw new KeyNotFoundException("Missing Auth0 client id from config or vault"),
- ClientSecret = secret.Result ?? throw new KeyNotFoundException("Missing Auth0 client secret from config or vault"),
-
Passwords = plugin.GetPasswords(),
Users = plugin.GetUserManager(),
};
- string keyUrl = config["key_url"].GetString() ?? throw new KeyNotFoundException("Missing Auth0 'key_url' from config");
+ InitPathAndLog(Config.EndpointPath, plugin.Log);
- Uri keyUri = new(keyUrl);
+ //Load secrets
+ _ = plugin.DeferTask(async () =>
+ {
+ //Get id/secret
+ Task<SecretResult?> secretTask = plugin.TryGetSecretAsync("auth0_client_secret");
+ Task<SecretResult?> clientIdTask = plugin.TryGetSecretAsync("auth0_client_id");
- //Get certificate on background thread
- RsaCertificate = Task.Run(() => GetRsaCertificate(keyUri));
+ await Task.WhenAll(secretTask, clientIdTask);
- InitPathAndLog(Config.EndpointPath, plugin.Log);
+ using SecretResult? secret = await secretTask;
+ using SecretResult? clientId = await clientIdTask;
+
+ Config.ClientID = clientId?.Result.ToString() ?? throw new KeyNotFoundException("Missing Auth0 client id from config or vault");
+ Config.ClientSecret = secret?.Result.ToString() ?? throw new KeyNotFoundException("Missing the Auth0 client secret from config or vault");
+
+ }, 100);
}
@@ -154,7 +159,7 @@ namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
using JsonWebToken jwt = JsonWebToken.Parse(clientAccess.IdToken);
//Verify the token against the first signing key
- if (!jwt.VerifyFromJwk(RsaCertificate.Result.RootElement.GetProperty("keys").EnumerateArray().First()))
+ if (!jwt.VerifyFromJwk(Auth0VerificationJwk.Result.RootElement.GetProperty("keys").EnumerateArray().First()))
{
return EmptyLoginData;
}
diff --git a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/DiscordOauth.cs b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/DiscordOauth.cs
index 6ee7683..d8b2394 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/DiscordOauth.cs
+++ b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/DiscordOauth.cs
@@ -39,7 +39,6 @@ using VNLib.Plugins.Essentials.Accounts;
using VNLib.Plugins.Extensions.Loading;
using VNLib.Plugins.Extensions.Loading.Users;
-#nullable enable
namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
{
@@ -50,26 +49,33 @@ namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
public DiscordOauth(PluginBase plugin, IReadOnlyDictionary<string, JsonElement> config) : base()
{
- //Get id/secret
- Task<string?> secret = plugin.TryGetSecretAsync("discord_client_secret");
- Task<string?> clientId = plugin.TryGetSecretAsync("discord_client_id");
-
- //Wait sync
- Task.WaitAll(secret, clientId);
-
Config = new("discord", config)
{
- //get gh client secret and id
- ClientID = clientId.Result ?? throw new KeyNotFoundException("Missing Discord client id from config or vault"),
- ClientSecret = secret.Result ?? throw new KeyNotFoundException("Missing the Discord client secret from config or vault"),
-
Passwords = plugin.GetPasswords(),
Users = plugin.GetUserManager(),
};
InitPathAndLog(Config.EndpointPath, plugin.Log);
+
+ //Load secrets
+ _ = plugin.DeferTask(async () =>
+ {
+ //Get id/secret
+ Task<SecretResult?> clientIdTask = plugin.TryGetSecretAsync("discord_client_id");
+ Task<SecretResult?> secretTask = plugin.TryGetSecretAsync("discord_client_secret");
+
+ await Task.WhenAll(secretTask, clientIdTask);
+
+ using SecretResult? secret = await secretTask;
+ using SecretResult? clientId = await clientIdTask;
+
+ Config.ClientID = clientId?.Result.ToString() ?? throw new KeyNotFoundException("Missing Discord client id from config or vault");
+ Config.ClientSecret = secret?.Result.ToString() ?? throw new KeyNotFoundException("Missing the Discord client secret from config or vault");
+
+ }, 100);
}
+
private static string GetUserIdFromPlatform(string userName)
{
return ManagedHash.ComputeHash($"discord|{userName}", HashAlg.SHA1, HashEncodingMode.Hexadecimal);
diff --git a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/GitHubOauth.cs b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/GitHubOauth.cs
index 0b4fc0f..676f2bb 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/Endpoints/GitHubOauth.cs
+++ b/VNLib.Plugins.Essentials.SocialOauth/Endpoints/GitHubOauth.cs
@@ -39,8 +39,6 @@ using VNLib.Plugins.Essentials.Accounts;
using VNLib.Plugins.Extensions.Loading;
using VNLib.Plugins.Extensions.Loading.Users;
-#nullable enable
-
namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
{
[ConfigurationName("github")]
@@ -49,32 +47,38 @@ namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
private const string GITHUB_V3_ACCEPT = "application/vnd.github.v3+json";
private readonly string UserEmailUrl;
-
+
protected override OauthClientConfig Config { get; }
public GitHubOauth(PluginBase plugin, IReadOnlyDictionary<string, JsonElement> config) : base()
{
- //Get id/secret
- Task<string?> secret = plugin.TryGetSecretAsync("github_client_secret");
- Task<string?> clientId = plugin.TryGetSecretAsync("github_client_id");
-
- //Wait sync
- Task.WaitAll(secret, clientId);
+
+ UserEmailUrl = config["user_email_url"].GetString() ?? throw new KeyNotFoundException("Missing required key 'user_email_url' for github configuration");
- Config = new(configName: "github", config)
+ Config = new("github", config)
{
- //get gh client secret and id
- ClientID = clientId.Result ?? throw new KeyNotFoundException("Missing Github client id from config or vault"),
- ClientSecret = secret.Result ?? throw new KeyNotFoundException("Missing Github client secret from config or vault"),
-
Passwords = plugin.GetPasswords(),
Users = plugin.GetUserManager(),
};
+ InitPathAndLog(Config.EndpointPath, plugin.Log);
- UserEmailUrl = config["user_email_url"].GetString() ?? throw new KeyNotFoundException("Missing required key 'user_email_url' for github configuration");
+ //Load secrets
+ _ = plugin.DeferTask(async () =>
+ {
+ //Get id/secret
+ Task<SecretResult?> clientIdTask = plugin.TryGetSecretAsync("github_client_id");
+ Task<SecretResult?> secretTask = plugin.TryGetSecretAsync("github_client_secret");
- InitPathAndLog(Config.EndpointPath, plugin.Log);
+ await Task.WhenAll(secretTask, clientIdTask);
+
+ using SecretResult? secret = await secretTask;
+ using SecretResult? clientId = await clientIdTask;
+
+ Config.ClientID = clientId?.Result.ToString() ?? throw new KeyNotFoundException("Missing Github client id from config or vault");
+ Config.ClientSecret = secret?.Result.ToString() ?? throw new KeyNotFoundException("Missing the Github client secret from config or vault");
+
+ }, 100);
}
protected override void StaticClientPoolInitializer(RestClient client)
@@ -211,6 +215,5 @@ namespace VNLib.Plugins.Essentials.SocialOauth.Endpoints
return accountData;
}
-
}
} \ No newline at end of file
diff --git a/VNLib.Plugins.Essentials.SocialOauth/OauthClientConfig.cs b/VNLib.Plugins.Essentials.SocialOauth/OauthClientConfig.cs
index 6e30802..9caf705 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/OauthClientConfig.cs
+++ b/VNLib.Plugins.Essentials.SocialOauth/OauthClientConfig.cs
@@ -29,9 +29,7 @@ using System.Collections.Generic;
using VNLib.Utils.Extensions;
using VNLib.Plugins.Essentials.Users;
using VNLib.Plugins.Essentials.Accounts;
-using VNLib.Net.Rest.Client;
-#nullable enable
namespace VNLib.Plugins.Essentials.SocialOauth
{
@@ -61,15 +59,13 @@ namespace VNLib.Plugins.Essentials.SocialOauth
NonceByteSize = config["nonce_size"].GetUInt32();
RandomPasswordSize = config["password_size"].GetInt32();
}
+
-
- public RestClientPool ClientPool { get; }
-
- public string ClientID { get; init; }
+ public string ClientID { get; set; } = string.Empty;
- public string ClientSecret { get; init; }
+ public string ClientSecret { get; set; } = string.Empty;
+
-
/// <summary>
/// The user-account origin value. Specifies that the user account
/// was created outside of the local account system
@@ -96,7 +92,7 @@ namespace VNLib.Plugins.Essentials.SocialOauth
/// <summary>
/// The user store to create/get users from
/// </summary>
- public IUserManager Users { get; init; }
+ public IUserManager Users { get; init; }
public PasswordHashing Passwords { get; init; }
diff --git a/VNLib.Plugins.Essentials.SocialOauth/SocialOauthBase.cs b/VNLib.Plugins.Essentials.SocialOauth/SocialOauthBase.cs
index 5728992..6815bf3 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/SocialOauthBase.cs
+++ b/VNLib.Plugins.Essentials.SocialOauth/SocialOauthBase.cs
@@ -75,7 +75,7 @@ namespace VNLib.Plugins.Essentials.SocialOauth
* Disable cross site checking because the OAuth2 flow requires
* cross site when redirecting the client back
*/
- CrossSiteDenied = false
+ DisableCrossSiteDenied = true
};
/// <summary>
@@ -283,7 +283,7 @@ namespace VNLib.Plugins.Essentials.SocialOauth
return VfReturnType.VirtualSkip;
}
//Try to get the claim from the state parameter
- if (ClaimStore.TryGetOrEvictRecord(state, out LoginClaim claim) < 1)
+ if (ClaimStore.TryGetOrEvictRecord(state, out LoginClaim? claim) < 1)
{
entity.Redirect(RedirectType.Temporary, $"{Path}?result=expired");
return VfReturnType.VirtualSkip;
@@ -361,7 +361,7 @@ namespace VNLib.Plugins.Essentials.SocialOauth
return VfReturnType.VirtualSkip;
}
//Recover the access token
- if (AuthorizationStore.TryGetOrEvictRecord(base32Nonce!, out OAuthAccessState token) < 1)
+ if (AuthorizationStore.TryGetOrEvictRecord(base32Nonce!, out OAuthAccessState? token) < 1)
{
webm.Result = AUTH_ERROR_MESSAGE;
entity.CloseResponse(webm);
diff --git a/VNLib.Plugins.Essentials.SocialOauth/VNLib.Plugins.Essentials.SocialOauth.csproj b/VNLib.Plugins.Essentials.SocialOauth/VNLib.Plugins.Essentials.SocialOauth.csproj
index bbe9185..56e3068 100644
--- a/VNLib.Plugins.Essentials.SocialOauth/VNLib.Plugins.Essentials.SocialOauth.csproj
+++ b/VNLib.Plugins.Essentials.SocialOauth/VNLib.Plugins.Essentials.SocialOauth.csproj
@@ -32,7 +32,7 @@
<AnalysisLevel>latest-all</AnalysisLevel>
</PropertyGroup>
<ItemGroup>
- <ProjectReference Include="..\..\..\VNLib\Essentials\VNLib.Plugins.Essentials.csproj" />
+ <ProjectReference Include="..\..\..\VNLib\Essentials\src\VNLib.Plugins.Essentials.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Loading\VNLib.Plugins.Extensions.Loading.csproj" />
<ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Validation\VNLib.Plugins.Extensions.Validation.csproj" />
<ProjectReference Include="..\..\PluginBase\VNLib.Plugins.PluginBase.csproj" />