mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 14:22:40 +01:00
A api key can always revoke itself, add a route to delete any api key
This commit is contained in:
parent
39a8c3fe47
commit
6d7b57ea3b
5 changed files with 69 additions and 43 deletions
|
@ -27,5 +27,13 @@ namespace BTCPayServer.Client
|
||||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
|
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
|
||||||
HandleResponse(response);
|
HandleResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task RevokeAPIKey(string apikey, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (apikey == null)
|
||||||
|
throw new ArgumentNullException(nameof(apikey));
|
||||||
|
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/api-keys/{apikey}", null, HttpMethod.Delete), token);
|
||||||
|
HandleResponse(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace BTCPayServer.Tests
|
||||||
var user = tester.NewAccount();
|
var user = tester.NewAccount();
|
||||||
user.GrantAccess();
|
user.GrantAccess();
|
||||||
await user.MakeAdmin();
|
await user.MakeAdmin();
|
||||||
var client = await user.CreateClient(Policies.Unrestricted);
|
var client = await user.CreateClient(Policies.CanViewProfile);
|
||||||
var clientBasic = await user.CreateClient();
|
var clientBasic = await user.CreateClient();
|
||||||
//Get current api key
|
//Get current api key
|
||||||
var apiKeyData = await client.GetCurrentAPIKeyInfo();
|
var apiKeyData = await client.GetCurrentAPIKeyInfo();
|
||||||
|
@ -57,7 +57,7 @@ namespace BTCPayServer.Tests
|
||||||
}
|
}
|
||||||
[Fact(Timeout = TestTimeout)]
|
[Fact(Timeout = TestTimeout)]
|
||||||
[Trait("Integration", "Integration")]
|
[Trait("Integration", "Integration")]
|
||||||
public async Task CanCreateAPIKeyViaAPI()
|
public async Task CanCreateAndDeleteAPIKeyViaAPI()
|
||||||
{
|
{
|
||||||
using (var tester = ServerTester.Create())
|
using (var tester = ServerTester.Create())
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,9 @@ namespace BTCPayServer.Tests
|
||||||
Label = "Hello world2",
|
Label = "Hello world2",
|
||||||
Permissions = new Permission[] { Permission.Create(Policies.CanViewProfile) }
|
Permissions = new Permission[] { Permission.Create(Policies.CanViewProfile) }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
await unrestricted.RevokeAPIKey(apiKey.ApiKey);
|
||||||
|
await AssertHttpError(404, async () => await unrestricted.RevokeAPIKey(apiKey.ApiKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,17 +56,28 @@ namespace BTCPayServer.Controllers.GreenField
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("~/api/v1/api-keys/current")]
|
[HttpDelete("~/api/v1/api-keys/current")]
|
||||||
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.GreenfieldAPIKeys)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.GreenfieldAPIKeys)]
|
||||||
public async Task<IActionResult> RevokeKey()
|
public Task<IActionResult> RevokeCurrentKey()
|
||||||
{
|
{
|
||||||
if (!ControllerContext.HttpContext.GetAPIKey(out var apiKey))
|
if (!ControllerContext.HttpContext.GetAPIKey(out var apiKey))
|
||||||
{
|
{
|
||||||
return NotFound();
|
// Should be impossible (we force apikey auth)
|
||||||
|
return Task.FromResult<IActionResult>(BadRequest());
|
||||||
}
|
}
|
||||||
await _apiKeyRepository.Remove(apiKey, _userManager.GetUserId(User));
|
return RevokeKey(apiKey);
|
||||||
return Ok();
|
|
||||||
}
|
}
|
||||||
|
[HttpDelete("~/api/v1/api-keys/{apikey}", Order = 1)]
|
||||||
|
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
public async Task<IActionResult> RevokeKey(string apikey)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(apikey))
|
||||||
|
return BadRequest();
|
||||||
|
if (await _apiKeyRepository.Remove(apikey, _userManager.GetUserId(User)))
|
||||||
|
return Ok();
|
||||||
|
else
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
private static ApiKeyData FromModel(APIKeyData data)
|
private static ApiKeyData FromModel(APIKeyData data)
|
||||||
{
|
{
|
||||||
return new ApiKeyData()
|
return new ApiKeyData()
|
||||||
|
|
|
@ -53,15 +53,18 @@ namespace BTCPayServer.Security.GreenField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Remove(string id, string getUserId)
|
public async Task<bool> Remove(string id, string getUserId)
|
||||||
{
|
{
|
||||||
using (var context = _applicationDbContextFactory.CreateContext())
|
using (var context = _applicationDbContextFactory.CreateContext())
|
||||||
{
|
{
|
||||||
var key = await EntityFrameworkQueryableExtensions.SingleOrDefaultAsync(context.ApiKeys,
|
var key = await EntityFrameworkQueryableExtensions.SingleOrDefaultAsync(context.ApiKeys,
|
||||||
data => data.Id == id && data.UserId == getUserId);
|
data => data.Id == id && data.UserId == getUserId);
|
||||||
|
if (key == null)
|
||||||
|
return false;
|
||||||
context.ApiKeys.Remove(key);
|
context.ApiKeys.Remove(key);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class APIKeyQuery
|
public class APIKeyQuery
|
||||||
|
|
|
@ -188,23 +188,48 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/api-keys/{apikey}": {
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"API Keys"
|
||||||
|
],
|
||||||
|
"summary": "Revoke an API Key",
|
||||||
|
"description": "Revoke the current API key so that it cannot be used anymore",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "apikey",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"description": "The API Key to revoke",
|
||||||
|
"schema": { "type": "string" }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The key has been deleted"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The key is not found for this user"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"API Key": [ "unrestricted" ],
|
||||||
|
"Basic": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/api-keys/current": {
|
"/api/v1/api-keys/current": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"API Keys"
|
"API Keys"
|
||||||
],
|
],
|
||||||
"summary": "Get current API Key information",
|
"summary": "Get the current API Key information",
|
||||||
"description": "View information about the current API key",
|
"description": "View information about the current API key",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Information about the current api key",
|
"description": "The key has been deleted"
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/ApiKeyData"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -233,7 +258,7 @@
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"API Key": [ "unrestricted" ]
|
"API Key": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -289,30 +314,6 @@
|
||||||
"Basic": []
|
"Basic": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"tags": [
|
|
||||||
"API Keys"
|
|
||||||
],
|
|
||||||
"summary": "Revoke the current API Key",
|
|
||||||
"description": "Revoke the current API key so that it cannot be used anymore",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "The key was revoked and is no longer usable",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/ApiKeyData"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"API Key": [ "unrestricted" ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue