diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-01-23 11:41:42 +0100 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-01-23 14:33:05 +0100 |
| commit | ce86d103039b22695b04714ee85e9ef3e1e032b5 (patch) | |
| tree | 557455780de06ceb95dd556ca5ffca0208a1f8ba /src/server/Api | |
| parent | 89816382424e59ad953b433fbf82c925741b3136 (diff) | |
| download | bookmark-thing-ce86d103039b22695b04714ee85e9ef3e1e032b5.tar.xz bookmark-thing-ce86d103039b22695b04714ee85e9ef3e1e032b5.zip | |
feat(auth): Implements first draft of basic auth gen/validation
Diffstat (limited to 'src/server/Api')
| -rw-r--r-- | src/server/Api/Internal/Account/CreateTokenRequest.cs | 6 | ||||
| -rw-r--r-- | src/server/Api/Internal/Account/CreateTokenRoute.cs | 28 | ||||
| -rw-r--r-- | src/server/Api/V1/BaseV1Route.cs | 21 | ||||
| -rw-r--r-- | src/server/Api/V1/Entries/CreateEntryRoute.cs | 4 | ||||
| -rw-r--r-- | src/server/Api/V1/Entries/DeleteEntryRoute.cs | 4 | ||||
| -rw-r--r-- | src/server/Api/V1/Entries/GetEntriesRoute.cs | 4 | ||||
| -rw-r--r-- | src/server/Api/V1/Entries/UpdateEntryRoute.cs | 5 |
7 files changed, 62 insertions, 10 deletions
diff --git a/src/server/Api/Internal/Account/CreateTokenRequest.cs b/src/server/Api/Internal/Account/CreateTokenRequest.cs index 399bdfc..6839092 100644 --- a/src/server/Api/Internal/Account/CreateTokenRequest.cs +++ b/src/server/Api/Internal/Account/CreateTokenRequest.cs @@ -2,5 +2,9 @@ namespace IOL.BookmarkThing.Server.Api.Internal.Account; public class CreateTokenRequest { - public string Name { get; set; } + public bool AllowRead { get; set; } + public bool AllowCreate { get; set; } + public bool AllowUpdate { get; set; } + public bool AllowDelete { get; set; } + public DateTime ExpiryDate { get; set; } } diff --git a/src/server/Api/Internal/Account/CreateTokenRoute.cs b/src/server/Api/Internal/Account/CreateTokenRoute.cs index ea0e01f..0b30cc0 100644 --- a/src/server/Api/Internal/Account/CreateTokenRoute.cs +++ b/src/server/Api/Internal/Account/CreateTokenRoute.cs @@ -1,11 +1,17 @@ +using System.Text; + namespace IOL.BookmarkThing.Server.Api.Internal.Account; public class CreateTokenRoute : RouteBaseInternalSync.WithRequest<CreateTokenRequest>.WithActionResult { private readonly AppDbContext _context; + private readonly IConfiguration _configuration; + private readonly ILogger<CreateTokenRoute> _logger; - public CreateTokenRoute(AppDbContext context) { + public CreateTokenRoute(AppDbContext context, IConfiguration configuration, ILogger<CreateTokenRoute> logger) { _context = context; + _configuration = configuration; + _logger = logger; } [ApiVersionNeutral] @@ -17,18 +23,24 @@ public class CreateTokenRoute : RouteBaseInternalSync.WithRequest<CreateTokenReq return NotFound(new ErrorResult("User does not exist")); } - if (request.Name.IsNullOrWhiteSpace()) { - return BadRequest(new ErrorResult("Token name is required")); + var token_entropy = _configuration.GetValue<string>("TOKEN_ENTROPY"); + if (token_entropy.IsNullOrWhiteSpace()) { + _logger.LogWarning("No token entropy is available in env:TOKEN_ENTROPY, Basic auth is disabled"); + return NotFound(); } - var token = new AccessToken { + var access_token = new AccessToken { Id = Guid.NewGuid(), - Name = request.Name, - User = user + User = user, + ExpiryDate = request.ExpiryDate.ToUniversalTime(), + AllowCreate = request.AllowCreate, + AllowRead = request.AllowRead, + AllowDelete = request.AllowDelete, + AllowUpdate = request.AllowUpdate }; - _context.AccessTokens.Add(token); + _context.AccessTokens.Add(access_token); _context.SaveChanges(); - return Ok(token); + return Ok(Convert.ToBase64String(Encoding.UTF8.GetBytes(access_token.Id.ToString().EncryptWithAes(token_entropy)))); } } diff --git a/src/server/Api/V1/BaseV1Route.cs b/src/server/Api/V1/BaseV1Route.cs index ba7d978..b1e2128 100644 --- a/src/server/Api/V1/BaseV1Route.cs +++ b/src/server/Api/V1/BaseV1Route.cs @@ -1,3 +1,5 @@ +using System.Net.Http.Headers; + namespace IOL.BookmarkThing.Server.Api.V1; /// <inheritdoc /> @@ -14,4 +16,23 @@ public class BaseV1Route : ControllerBase Username = User.Identity?.Name, Id = User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value.ToGuid() ?? default }; + + protected bool IsApiCall() { + if (!Request.Headers.ContainsKey("Authorization")) return false; + try { + var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); + if (authHeader.Parameter == null) return false; + } catch (Exception e) { + return false; + } + + return true; + } + + protected bool HasApiPermission(string permission_key) { + var permission_claim = User.Claims.SingleOrDefault(c => c.Type == permission_key); + return permission_claim is { + Value: "True" + }; + } } diff --git a/src/server/Api/V1/Entries/CreateEntryRoute.cs b/src/server/Api/V1/Entries/CreateEntryRoute.cs index ebe49fc..b502e4a 100644 --- a/src/server/Api/V1/Entries/CreateEntryRoute.cs +++ b/src/server/Api/V1/Entries/CreateEntryRoute.cs @@ -21,6 +21,10 @@ public class CreateEntryRoute : RouteBaseV1Sync.WithRequest<CreateEntryRequest>. [ApiVersion(ApiSpecV1.VERSION_STRING)] [HttpPost("~/v{version:apiVersion}/entries/create")] public override ActionResult<EntryDto> Handle(CreateEntryRequest entry) { + if (IsApiCall() && !HasApiPermission(Constants.TOKEN_ALLOW_CREATE)) { + return StatusCode(403, "Your token does not permit access to this resource"); + } + var errors = entry.GetErrors(); if (errors.Count != 0) { return BadRequest(errors); diff --git a/src/server/Api/V1/Entries/DeleteEntryRoute.cs b/src/server/Api/V1/Entries/DeleteEntryRoute.cs index fc79049..c979c1f 100644 --- a/src/server/Api/V1/Entries/DeleteEntryRoute.cs +++ b/src/server/Api/V1/Entries/DeleteEntryRoute.cs @@ -18,6 +18,10 @@ public class DeleteEntryRoute : RouteBaseV1Sync.WithRequest<Guid>.WithActionResu [ApiVersion(ApiSpecV1.VERSION_STRING)] [HttpDelete("~/v{version:apiVersion}/entries/{entryId:guid}")] public override ActionResult Handle(Guid entryId) { + if (IsApiCall() && !HasApiPermission(Constants.TOKEN_ALLOW_DELETE)) { + return StatusCode(403, "Your token does not permit access to this resource"); + } + var entry = _context.Entries.SingleOrDefault(c => c.Id == entryId && c.UserId == LoggedInUser.Id); if (entry == default) { return NotFound(new ErrorResult("Entry does not exist")); diff --git a/src/server/Api/V1/Entries/GetEntriesRoute.cs b/src/server/Api/V1/Entries/GetEntriesRoute.cs index adadf01..27905a2 100644 --- a/src/server/Api/V1/Entries/GetEntriesRoute.cs +++ b/src/server/Api/V1/Entries/GetEntriesRoute.cs @@ -16,6 +16,10 @@ public class GetEntriesRoute : RouteBaseV1Sync.WithoutRequest.WithActionResult<L [ApiVersion(ApiSpecV1.VERSION_STRING)] [HttpGet("~/v{version:apiVersion}/entries")] public override ActionResult<List<EntryDto>> Handle() { + if (IsApiCall() && !HasApiPermission(Constants.TOKEN_ALLOW_READ)) { + return StatusCode(403, "Your token does not permit access to this resource"); + } + return Ok(_context.Entries.Where(c => c.UserId == LoggedInUser.Id).Select(c => new EntryDto(c))); } } diff --git a/src/server/Api/V1/Entries/UpdateEntryRoute.cs b/src/server/Api/V1/Entries/UpdateEntryRoute.cs index 96c60fe..919364d 100644 --- a/src/server/Api/V1/Entries/UpdateEntryRoute.cs +++ b/src/server/Api/V1/Entries/UpdateEntryRoute.cs @@ -1,4 +1,3 @@ -using System.Security.Cryptography; using IOL.BookmarkThing.Server.Api.V1.Entries.Dtos; namespace IOL.BookmarkThing.Server.Api.V1.Entries; @@ -24,6 +23,10 @@ public class UpdateEntryRoute : RouteBaseV1Sync.WithRequest<UpdateEntryRequest>. [ApiVersion(ApiSpecV1.VERSION_STRING)] [HttpPost("~/v{version:apiVersion}/entries/update")] public override ActionResult<EntryDto> Handle(UpdateEntryRequest entryToUpdate) { + if (IsApiCall() && !HasApiPermission(Constants.TOKEN_ALLOW_UPDATE)) { + return StatusCode(403, "Your token does not permit access to this resource"); + } + var entry = _context.Entries.SingleOrDefault(c => c.Id == entryToUpdate.Id && c.UserId == LoggedInUser.Id); if (entry == default) { return NotFound(new ErrorResult("Entry does not exist")); |
