diff options
author | vnugent <public@vaughnnugent.com> | 2023-01-12 17:47:41 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-01-12 17:47:41 -0500 |
commit | e5bffa4bfa5a5a4a29dc5d1ccb250f37d938664e (patch) | |
tree | 0157df9ed996611908de95195cca9a4b98a06cc4 /Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens | |
parent | 47795f89123059e4d278ba299658ef663eb5d833 (diff) |
Large project reorder and consolidation
Diffstat (limited to 'Libs/VNLib.Plugins.Essentials.Oauth/src/Tokens')
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); + } + } +} |