diff --git a/API/Controller/Tokens/TokenController.cs b/API/Controller/Tokens/TokenController.cs index 9aa13a1b..9ca8b883 100644 --- a/API/Controller/Tokens/TokenController.cs +++ b/API/Controller/Tokens/TokenController.cs @@ -1,14 +1,8 @@ using System.ComponentModel.DataAnnotations; -using System.Net; using System.Net.Mime; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using OpenShock.API.Models.Response; -using OpenShock.API.Utils; -using OpenShock.Common; -using OpenShock.Common.Authentication; -using OpenShock.Common.Authentication.Attributes; using OpenShock.Common.Constants; using OpenShock.Common.Errors; using OpenShock.Common.Models; @@ -72,30 +66,6 @@ public async Task GetTokenById([FromRoute] Guid tokenId) return Ok(apiToken); } - /// - /// Revoke a token from the current user - /// - /// - /// Successfully deleted token - /// The token does not exist or you do not have access to it. - [HttpDelete("{tokenId}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound, MediaTypeNames.Application.ProblemJson)] // ApiTokenNotFound - public async Task DeleteToken([FromRoute] Guid tokenId) - { - var apiToken = await _db.ApiTokens - .Where(x => x.Id == tokenId) - .WhereIsUserOrPrivileged(x => x.User, CurrentUser) - .ExecuteDeleteAsync(); - - if (apiToken <= 0) - { - return Problem(ApiTokenError.ApiTokenNotFound); - } - - return Ok(); - } - /// /// Create a new token /// diff --git a/API/Controller/Tokens/TokenDeleteController.cs b/API/Controller/Tokens/TokenDeleteController.cs new file mode 100644 index 00000000..aad10584 --- /dev/null +++ b/API/Controller/Tokens/TokenDeleteController.cs @@ -0,0 +1,70 @@ +using System.Net.Mime; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using OpenShock.Common; +using OpenShock.Common.Authentication; +using OpenShock.Common.Authentication.ControllerBase; +using OpenShock.Common.Errors; +using OpenShock.Common.OpenShockDb; +using OpenShock.Common.Problems; +using OpenShock.Common.Utils; + +namespace OpenShock.API.Controller.Tokens; + +[ApiController] +[Route("/{version:apiVersion}/tokens")] +[Authorize(AuthenticationSchemes = OpenShockAuthSchemas.UserSessionApiTokenCombo)] +public sealed class TokenDeleteController : AuthenticatedSessionControllerBase +{ + private readonly OpenShockContext _db; + private readonly ILogger _logger; + + public TokenDeleteController(OpenShockContext db, ILogger logger) + { + _db = db; + _logger = logger; + } + + /// + /// Revoke a token + /// + /// + /// Successfully deleted token + /// The token does not exist or you do not have access to it. + [HttpDelete("{tokenId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound, + MediaTypeNames.Application.ProblemJson)] // ApiTokenNotFound + public async Task DeleteToken([FromRoute] Guid tokenId) + { + var auth = HttpContext.GetAuthenticationMethod(); + + var query = _db.ApiTokens.Where(x => x.Id == tokenId); + + + switch (auth) + { + case OpenShockAuthSchemas.UserSessionCookie: + query = query.WhereIsUserOrPrivileged(x => x.User, CurrentUser); + break; + case OpenShockAuthSchemas.ApiToken: + { + var requestTokenId = Guid.Parse(HttpContext.User.Claims.First(x => x.Type == OpenShockAuthClaims.ApiTokenId).Value); + if (requestTokenId != tokenId) return Problem(ApiTokenError.ApiTokenCanOnlyDelete); + break; + } + default: + throw new Exception("Unknown auth method"); + } + + var apiToken = await query.ExecuteDeleteAsync(); + + if (apiToken <= 0) + { + return Problem(ApiTokenError.ApiTokenNotFound); + } + + return Ok(); + } +} \ No newline at end of file diff --git a/Common/Errors/ApiTokenError.cs b/Common/Errors/ApiTokenError.cs index 53160133..fa80e97b 100644 --- a/Common/Errors/ApiTokenError.cs +++ b/Common/Errors/ApiTokenError.cs @@ -6,4 +6,5 @@ namespace OpenShock.Common.Errors; public static class ApiTokenError { public static OpenShockProblem ApiTokenNotFound => new("ApiToken.NotFound", "Api token not found", HttpStatusCode.NotFound); + public static OpenShockProblem ApiTokenCanOnlyDelete => new("ApiToken.CanOnlyDelete own", "You can only delete your own api token in token authentication scope", HttpStatusCode.Forbidden); } \ No newline at end of file diff --git a/Common/Utils/AuthUtils.cs b/Common/Utils/AuthUtils.cs index adb89d80..1a1f4006 100644 --- a/Common/Utils/AuthUtils.cs +++ b/Common/Utils/AuthUtils.cs @@ -1,5 +1,6 @@ using OpenShock.Common.Constants; using System.Diagnostics.CodeAnalysis; +using System.Security.Claims; namespace OpenShock.Common.Utils; @@ -89,4 +90,15 @@ public static bool TryGetDeviceTokenFromHeader(this HttpContext context, [NotNul return false; } + public static string GetAuthenticationMethod(this HttpContext context) + { + var authMethodClaim = context.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.AuthenticationMethod); + if (authMethodClaim == null) + { + throw new Exception("No authentication method claim found, this should not happen and is a bug!"); + } + + return authMethodClaim.Value; + } + }