diff --git a/docs/authentication.md b/docs/authentication.md index f79c51e..c3489d0 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -62,8 +62,8 @@ tokens.CreateApiToken(user, DateTime.MaxValue); This creates a new api token that is valid until the provided DateTime has passed. Note that in the database and the token model the `CreatedAt` property represents the expiration date on an api token. For security reasons the api token by default -has no permissions. This allows you to create tokens that are just permitted to perform a single action. Note that a token -associated to a user can also have more permissions than the user itself so make sure to properly secure the creation process. +has no permissions. This allows you to create tokens that are just permitted to perform a single action. Note that an api token +can **never** have more permissions than the user associated with it. ### Add permissions to an api token diff --git a/src/HopFrame.Database/Repositories/ITokenRepository.cs b/src/HopFrame.Database/Repositories/ITokenRepository.cs index 2c1192c..9447994 100644 --- a/src/HopFrame.Database/Repositories/ITokenRepository.cs +++ b/src/HopFrame.Database/Repositories/ITokenRepository.cs @@ -5,7 +5,7 @@ namespace HopFrame.Database.Repositories; public interface ITokenRepository { Task GetToken(string content); Task CreateToken(int type, User owner); - Task DeleteUserTokens(User owner); + Task DeleteUserTokens(User owner, bool includeApiTokens = false); Task DeleteToken(Token token); Task CreateApiToken(User owner, DateTime expirationDate); } \ No newline at end of file diff --git a/src/HopFrame.Database/Repositories/Implementation/PermissionRepository.cs b/src/HopFrame.Database/Repositories/Implementation/PermissionRepository.cs index 6d55bc0..3156361 100644 --- a/src/HopFrame.Database/Repositories/Implementation/PermissionRepository.cs +++ b/src/HopFrame.Database/Repositories/Implementation/PermissionRepository.cs @@ -5,6 +5,10 @@ namespace HopFrame.Database.Repositories.Implementation; internal sealed class PermissionRepository(TDbContext context, IGroupRepository groupRepository) : IPermissionRepository where TDbContext : HopDbContextBase { public async Task HasPermission(IPermissionOwner owner, params string[] permissions) { + if (owner is Token { Type: Token.ApiTokenType } token) { + if (!await HasPermission(token.Owner, permissions)) return false; + } + var perms = (await GetFullPermissions(owner)).ToArray(); foreach (var permission in permissions) { @@ -27,6 +31,8 @@ internal sealed class PermissionRepository(TDbContext context, IGrou }else if (owner is Token token) { if (token.Type != Token.ApiTokenType) throw new ArgumentException("Only API tokens can have permissions!"); + if (!await HasPermission(token.Owner, permission)) + throw new ArgumentException("An api token cannot have more permissions than the owner has!"); entry.Token = token; } diff --git a/src/HopFrame.Database/Repositories/Implementation/TokenRepository.cs b/src/HopFrame.Database/Repositories/Implementation/TokenRepository.cs index b44dc43..29deaab 100644 --- a/src/HopFrame.Database/Repositories/Implementation/TokenRepository.cs +++ b/src/HopFrame.Database/Repositories/Implementation/TokenRepository.cs @@ -29,11 +29,16 @@ internal sealed class TokenRepository(TDbContext context) : ITokenRe return token; } - public async Task DeleteUserTokens(User owner) { + public async Task DeleteUserTokens(User owner, bool includeApiTokens = false) { var tokens = await context.Tokens .Include(t => t.Owner) .Where(t => t.Owner.Id == owner.Id) .ToListAsync(); + + if (!includeApiTokens) + tokens = tokens + .Where(t => t.Type != Token.ApiTokenType) + .ToList(); context.Tokens.RemoveRange(tokens); await context.SaveChangesAsync();