aboutsummaryrefslogtreecommitdiff
path: root/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-01-12 17:47:41 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-01-12 17:47:41 -0500
commite5bffa4bfa5a5a4a29dc5d1ccb250f37d938664e (patch)
tree0157df9ed996611908de95195cca9a4b98a06cc4 /Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens
parent47795f89123059e4d278ba299658ef663eb5d833 (diff)
Large project reorder and consolidation
Diffstat (limited to 'Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens')
-rw-r--r--Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ActiveToken.cs40
-rw-r--r--Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/IOAuth2TokenResult.cs38
-rw-r--r--Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ITokenManager.cs51
-rw-r--r--Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/TokenStore.cs195
4 files changed, 324 insertions, 0 deletions
diff --git a/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ActiveToken.cs b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ActiveToken.cs
new file mode 100644
index 0000000..3f4ad8b
--- /dev/null
+++ b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ActiveToken.cs
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2022 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.Oauth
+* File: ActiveToken.cs
+*
+* ActiveToken.cs is part of VNLib.Plugins.Essentials.Oauth which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.Oauth is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.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
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Plugins.Essentials.Oauth. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+
+using VNLib.Plugins.Extensions.Data;
+
+namespace VNLib.Plugins.Essentials.Oauth.Tokens
+{
+ public class ActiveToken : DbModelBase
+ {
+ public override string Id { get; set; } = string.Empty;
+ public override DateTime Created { get; set; }
+ public override DateTime LastModified { get; set; }
+
+ public string? ApplicationId { get; set; }
+ public string? RefreshToken { get; set; }
+ }
+}
diff --git a/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/IOAuth2TokenResult.cs b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/IOAuth2TokenResult.cs
new file mode 100644
index 0000000..8b237df
--- /dev/null
+++ b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/IOAuth2TokenResult.cs
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2022 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.Oauth
+* File: IOAuth2TokenResult.cs
+*
+* IOAuth2TokenResult.cs is part of VNLib.Plugins.Essentials.Oauth which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.Oauth is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.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
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Plugins.Essentials.Oauth. If not, see http://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Plugins.Essentials.Oauth.Tokens
+{
+ /// <summary>
+ /// The result of an OAuth2Token creation
+ /// </summary>
+ public interface IOAuth2TokenResult
+ {
+ string? IdentityToken { get; }
+ string? AccessToken { get; }
+ string? RefreshToken { get; }
+ string? TokenType { get; }
+ int ExpiresSeconds { get; }
+ }
+} \ No newline at end of file
diff --git a/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ITokenManager.cs b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ITokenManager.cs
new file mode 100644
index 0000000..3adcc5d
--- /dev/null
+++ b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/ITokenManager.cs
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2022 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.Oauth
+* File: ITokenManager.cs
+*
+* ITokenManager.cs is part of VNLib.Plugins.Essentials.Oauth which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.Oauth is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.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
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Plugins.Essentials.Oauth. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace VNLib.Plugins.Essentials.Oauth.Tokens
+{
+ /// <summary>
+ /// Provides token creation and revocation
+ /// </summary>
+ public interface ITokenManager
+ {
+ /// <summary>
+ /// Revokes a colleciton of toke
+ /// </summary>
+ /// <param name="tokens">A collection of tokens to revoke</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>A task that completes when the tokens have been revoked</returns>
+ Task RevokeTokensAsync(IReadOnlyCollection<string> tokens, CancellationToken cancellation = default);
+ /// <summary>
+ /// Attempts to revoke tokens that belong to a specified application
+ /// </summary>
+ /// <param name="appId">The application to revoke tokens for</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>A task that completes when the work is complete</returns>
+ Task RevokeTokensForAppAsync(string appId, CancellationToken cancellation = default);
+ }
+} \ No newline at end of file
diff --git a/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/TokenStore.cs b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/TokenStore.cs
new file mode 100644
index 0000000..d139357
--- /dev/null
+++ b/Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens/TokenStore.cs
@@ -0,0 +1,195 @@
+/*
+* Copyright (c) 2022 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.Oauth
+* File: TokenStore.cs
+*
+* TokenStore.cs is part of VNLib.Plugins.Essentials.Oauth which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.Oauth is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.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
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Plugins.Essentials.Oauth. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.EntityFrameworkCore;
+
+using VNLib.Utils;
+using VNLib.Plugins.Essentials.Oauth.Applications;
+
+namespace VNLib.Plugins.Essentials.Oauth.Tokens
+{
+ /// <summary>
+ /// Represents a database backed <see cref="ITokenManager"/>
+ /// that allows for communicating token information to
+ /// plugins
+ /// </summary>
+ public sealed class TokenStore : ITokenManager
+ {
+ private readonly DbContextOptions Options;
+
+ /// <summary>
+ /// Initializes a new <see cref="TokenStore"/> that will make quries against
+ /// the supplied <see cref="DbContextOptions"/>
+ /// </summary>
+ /// <param name="options">The DB connection context</param>
+ public TokenStore(DbContextOptions options) => Options = options;
+
+ /// <summary>
+ /// Inserts a new token into the table for a specified application id. Also determines if
+ /// the user has reached the maximum number of allowed tokens
+ /// </summary>
+ /// <param name="token">The token (or session id)</param>
+ /// <param name="appId">The applicaiton the token belongs to</param>
+ /// <param name="refreshToken">The tokens refresh token</param>
+ /// <param name="maxTokens">The maxium number of allowed tokens for a given application</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>
+ /// <see cref="ERRNO.SUCCESS"/> if the opreation succeeds (aka 0x01),
+ /// <see cref="ERRNO.E_FAIL"/> if the operation fails, or the number
+ /// of active tokens if the maximum has been reached.
+ /// </returns>
+ public async Task<ERRNO> InsertTokenAsync(string token, string appId, string? refreshToken, int maxTokens, CancellationToken cancellation)
+ {
+ await using UserAppContext ctx = new (Options);
+ await ctx.OpenTransactionAsync(cancellation);
+
+ //Check active token count
+ int count = await (from t in ctx.OAuthTokens
+ where t.ApplicationId == appId
+ select t)
+ .CountAsync(cancellation);
+ //Check count
+ if(count >= maxTokens)
+ {
+ return count;
+ }
+
+ //Try to add the new token
+ ActiveToken newToken = new()
+ {
+ ApplicationId = appId,
+ Id = token,
+ RefreshToken = refreshToken,
+ Created = DateTime.UtcNow,
+ LastModified = DateTime.UtcNow
+ };
+ //Add token to store
+ ctx.OAuthTokens.Add(newToken);
+ //commit changes
+ ERRNO result = await ctx.SaveChangesAsync(cancellation);
+ if (result)
+ {
+ //End transaction
+ await ctx.CommitTransactionAsync(cancellation);
+ }
+ else
+ {
+ await ctx.RollbackTransctionAsync(cancellation);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Revokes/removes a single token from the store by its ID
+ /// </summary>
+ /// <param name="token">The token to remove</param>
+ /// <param name="cancellation"></param>
+ /// <returns>A task that revolves when the token is removed from the table if it exists</returns>
+ public async Task RevokeTokenAsync(string token, CancellationToken cancellation)
+ {
+ await using UserAppContext ctx = new (Options);
+ await ctx.OpenTransactionAsync(cancellation);
+ //Get the token from the db if it exists
+ ActiveToken? at = await (from t in ctx.OAuthTokens
+ where t.Id == token
+ select t)
+ .FirstOrDefaultAsync(cancellation);
+ if(at == null)
+ {
+ return;
+ }
+ //delete token
+ ctx.OAuthTokens.Remove(at);
+ //Save changes
+ await ctx.SaveChangesAsync(cancellation);
+ await ctx.CommitTransactionAsync(cancellation);
+ }
+ /// <summary>
+ /// Removes all token entires that were created before the specified time
+ /// </summary>
+ /// <param name="validAfter">The time before which all tokens are invaid</param>
+ /// <param name="cancellation">A token the cancel the operation</param>
+ /// <returns>A task that resolves to a collection of tokens that were removed</returns>
+ public async Task<IReadOnlyCollection<ActiveToken>> CleanupExpiredTokensAsync(DateTime validAfter, CancellationToken cancellation)
+ {
+ await using UserAppContext ctx = new (Options);
+ await ctx.OpenTransactionAsync(cancellation);
+ //Get the token from the db if it exists
+ ActiveToken[] at = await (from t in ctx.OAuthTokens
+ where t.Created < validAfter
+ select t)
+ .ToArrayAsync(cancellation);
+
+ //delete token
+ ctx.OAuthTokens.RemoveRange(at);
+ //Save changes
+ int count = await ctx.SaveChangesAsync(cancellation);
+ await ctx.CommitTransactionAsync(cancellation);
+ return at;
+ }
+ ///<inheritdoc/>
+ public async Task RevokeTokensAsync(IReadOnlyCollection<string> tokens, CancellationToken cancellation = default)
+ {
+ await using UserAppContext ctx = new (Options);
+ await ctx.OpenTransactionAsync(cancellation);
+ //Get all tokenes that are contained in the collection
+ ActiveToken[] at = await (from t in ctx.OAuthTokens
+ where tokens.Contains(t.Id)
+ select t)
+ .ToArrayAsync(cancellation);
+
+ //delete token
+ ctx.OAuthTokens.RemoveRange(at);
+ //Save changes
+ await ctx.SaveChangesAsync(cancellation);
+ await ctx.CommitTransactionAsync(cancellation);
+ }
+ ///<inheritdoc/>
+ async Task ITokenManager.RevokeTokensForAppAsync(string appId, CancellationToken cancellation)
+ {
+ await using UserAppContext ctx = new (Options);
+ await ctx.OpenTransactionAsync(cancellation);
+ //Get the token from the db if it exists
+ ActiveToken[] at = await (from t in ctx.OAuthTokens
+ where t.ApplicationId == appId
+ select t)
+ .ToArrayAsync(cancellation);
+ //Set created time to 0 to invalidate the token
+ foreach(ActiveToken t in at)
+ {
+ //Expire token so next cleanup round will wipe tokens
+ t.Created = DateTime.MinValue;
+ }
+ //Save changes
+ await ctx.SaveChangesAsync(cancellation);
+ await ctx.CommitTransactionAsync(cancellation);
+ }
+ }
+}