Add methods for managing API keys

This commit is contained in:
Robert Marshall 2021-05-08 10:42:49 +01:00
parent 84ae81d411
commit 3adef125a2
4 changed files with 174 additions and 2 deletions

View file

@ -48,5 +48,129 @@ namespace Robware.Api.Auth.Tests.Controllers {
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Create("test")).Value.Should().BeEquivalentTo(expectedKey); (await controller.Create("test")).Value.Should().BeEquivalentTo(expectedKey);
} }
[Fact]
public async Task List_ReturnsAllApiKeys() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
var apiKeys = new[] {
new ApiKey {Name = "test1", Key = "test1", IssueTimestamp = DateTime.Now, Enabled = true},
new ApiKey {Name = "test2", Key = "test2", IssueTimestamp = DateTime.Now, Enabled = false},
new ApiKey {Name = "test3", Key = "test3", IssueTimestamp = DateTime.Now, Enabled = true}
};
apiKeyRepository.GetAll().Returns(apiKeys);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.List()).Value.Should().BeEquivalentTo(apiKeys);
}
[Fact]
public async Task Delete_WithSuccessfulDeletion_ReturnsNoContent() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
apiKeyRepository.Delete("test").Returns(true);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Delete("test")).Should().BeOfType<NoContentResult>();
}
[Fact]
public async Task Delete_WithUnsuccessfulDeletion_ReturnsBadRequest() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
apiKeyRepository.Delete("test").Returns(false);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Delete("test")).Should().BeOfType<BadRequestResult>();
}
[Fact]
public async Task Disable_WithSuccessfulDisablement_ReturnsNoContent() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
var apiKey = new ApiKey {
Name = "test",
Key = "test",
IssueTimestamp = DateTime.Now,
Enabled = true
};
apiKeyRepository.Get("test").Returns(apiKey);
apiKeyRepository.Update(apiKey).Returns(true);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Disable("test")).Should().BeOfType<NoContentResult>();
apiKey.Enabled.Should().BeFalse();
}
[Fact]
public async Task Disable_WithUnsuccessfulDisablement_ReturnsBadRequest() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
var apiKey = new ApiKey {
Name = "test",
Key = "test",
IssueTimestamp = DateTime.Now,
Enabled = true
};
apiKeyRepository.Get("test").Returns(apiKey);
apiKeyRepository.Update(apiKey).Returns(false);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Disable("test")).Should().BeOfType<BadRequestResult>();
}
[Fact]
public async Task Enable_WithSuccessfulEnablement_ReturnsNoContent() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
var apiKey = new ApiKey {
Name = "test",
Key = "test",
IssueTimestamp = DateTime.Now,
Enabled = false
};
apiKeyRepository.Get("test").Returns(apiKey);
apiKeyRepository.Update(apiKey).Returns(true);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Enable("test")).Should().BeOfType<NoContentResult>();
apiKey.Enabled.Should().BeTrue();
}
[Fact]
public async Task Enable_WithUnsuccessfulEnablement_ReturnsBadRequest() {
var logger = Substitute.For<ILogger<ApiController>>();
var apiKeyValidator = Substitute.For<IApiKeyValidator>();
var apiKeyRepository = Substitute.For<IApiKeys>();
var apiKey = new ApiKey {
Name = "test",
Key = "test",
IssueTimestamp = DateTime.Now,
Enabled = false
};
apiKeyRepository.Get("test").Returns(apiKey);
apiKeyRepository.Update(apiKey).Returns(false);
var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository);
(await controller.Enable("test")).Should().BeOfType<BadRequestResult>();
}
} }
} }

View file

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Robware.Auth.API; using Robware.Auth.API;
using System.Linq;
namespace Robware.Api.Auth.Controllers { namespace Robware.Api.Auth.Controllers {
[ApiController] [ApiController]
@ -24,5 +25,34 @@ namespace Robware.Api.Auth.Controllers {
[HttpPost(nameof(Create))] [HttpPost(nameof(Create))]
[Authorize] [Authorize]
public async Task<ActionResult<ApiKey>> Create(string name) => await _apiKeyRepository.Create(name); public async Task<ActionResult<ApiKey>> Create(string name) => await _apiKeyRepository.Create(name);
[HttpGet(nameof(List))]
[Authorize]
public async Task<ActionResult<ApiKey[]>> List() => (await _apiKeyRepository.GetAll()).ToArray();
[HttpDelete(nameof(Delete))]
[Authorize]
public async Task<ActionResult> Delete(string key) => await _apiKeyRepository.Delete(key) ? (ActionResult) NoContent() : BadRequest();
private async Task<ActionResult> SetEnabled(string key, bool enabled) {
try {
var apiKey = await _apiKeyRepository.Get(key);
apiKey.Enabled = enabled;
return await _apiKeyRepository.Update(apiKey) ? (ActionResult)NoContent() : BadRequest();
}
catch (ApiKeyNotFoundException) {
return NotFound();
}
}
[HttpPatch(nameof(Disable))]
[Authorize]
public async Task<ActionResult> Disable(string key) => await SetEnabled(key, false);
[HttpPatch(nameof(Enable))]
[Authorize]
public async Task<ActionResult> Enable(string key) => await SetEnabled(key, true);
} }
} }

View file

@ -1,8 +1,12 @@
using System.Threading.Tasks; using System.Collections.Generic;
using System.Threading.Tasks;
namespace Robware.Auth.API { namespace Robware.Auth.API {
public interface IApiKeys { public interface IApiKeys {
Task<ApiKey> Get(string apiKey); Task<ApiKey> Get(string apiKey);
Task<ApiKey> Create(string name); Task<ApiKey> Create(string name);
Task<IEnumerable<ApiKey>> GetAll();
Task<bool> Delete(string key);
Task<bool> Update(ApiKey apiKey);
} }
} }

View file

@ -3,6 +3,8 @@ using Robware.Auth.API;
using Robware.Data.ApiKeys; using Robware.Data.ApiKeys;
using Robware.Data.ApiKeys.State; using Robware.Data.ApiKeys.State;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Robware.Data { namespace Robware.Data {
@ -34,5 +36,17 @@ namespace Robware.Data {
return apiKey; return apiKey;
} }
public async Task<IEnumerable<ApiKey>> GetAll() => (await _collection.FindAsync(_ => true)).ToEnumerable().Select(state => new DatabaseApiKey(state));
public async Task<bool> Delete(string key) {
var deleteResult = await _collection.DeleteOneAsync(state => state.Key == key);
return deleteResult.IsAcknowledged && deleteResult.DeletedCount == 1;
}
public async Task<bool> Update(ApiKey apiKey) {
var result = await _collection.ReplaceOneAsync(state => state.Key == apiKey.Key, new ApiKeyState(apiKey));
return result.IsAcknowledged && result.ModifiedCount == 1;
}
} }
} }