mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 14:04:12 +01:00
GreenField: Create API Key
This commit is contained in:
parent
927c09ff7b
commit
39a8c3fe47
6 changed files with 143 additions and 4 deletions
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -12,7 +13,15 @@ namespace BTCPayServer.Client
|
|||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current"), token);
|
||||
return await HandleResponse<ApiKeyData>(response);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<ApiKeyData> CreateAPIKey(CreateApiKeyRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys", bodyPayload: request, method: HttpMethod.Post), token);
|
||||
return await HandleResponse<ApiKeyData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
|
||||
|
|
|
@ -55,6 +55,33 @@ namespace BTCPayServer.Tests
|
|||
await AssertHttpError(401, async () => await clientBasic.RevokeCurrentAPIKeyInfo());
|
||||
}
|
||||
}
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanCreateAPIKeyViaAPI()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
await tester.StartAsync();
|
||||
var acc = tester.NewAccount();
|
||||
await acc.GrantAccessAsync();
|
||||
var unrestricted = await acc.CreateClient();
|
||||
var apiKey = await unrestricted.CreateAPIKey(new CreateApiKeyRequest()
|
||||
{
|
||||
Label = "Hello world",
|
||||
Permissions = new Permission[] { Permission.Create(Policies.CanViewProfile) }
|
||||
});
|
||||
Assert.Equal("Hello world", apiKey.Label);
|
||||
var p = Assert.Single(apiKey.Permissions);
|
||||
Assert.Equal(Policies.CanViewProfile, p.Policy);
|
||||
|
||||
var restricted = acc.CreateClientFromAPIKey(apiKey.ApiKey);
|
||||
await AssertHttpError(403, async () => await restricted.CreateAPIKey(new CreateApiKeyRequest()
|
||||
{
|
||||
Label = "Hello world2",
|
||||
Permissions = new Permission[] { Permission.Create(Policies.CanViewProfile) }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
|
|
|
@ -87,6 +87,12 @@ namespace BTCPayServer.Tests
|
|||
Assert.IsType<ViewResult>(await store.RequestPairing(pairingCode.ToString()));
|
||||
await store.Pair(pairingCode.ToString(), StoreId);
|
||||
}
|
||||
|
||||
public BTCPayServerClient CreateClientFromAPIKey(string apiKey)
|
||||
{
|
||||
return new BTCPayServerClient(parent.PayTester.ServerUri, apiKey);
|
||||
}
|
||||
|
||||
public void CreateStore()
|
||||
{
|
||||
CreateStoreAsync().GetAwaiter().GetResult();
|
||||
|
|
|
@ -223,5 +223,5 @@
|
|||
<_ContentIncludedByDefault Remove="Views\Authorization\Authorize.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
|
||||
<ProjectExtensions><VisualStudio><UserProperties wwwroot_4swagger_4v1_4swagger_1template_1json__JsonSchema="https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/schemas/v3.0/schema.json" /></VisualStudio></ProjectExtensions>
|
||||
</Project>
|
||||
|
|
|
@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using BTCPayServer.Security.GreenField;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Controllers.GreenField
|
||||
{
|
||||
|
@ -35,9 +37,27 @@ namespace BTCPayServer.Controllers.GreenField
|
|||
return Ok(FromModel(data));
|
||||
}
|
||||
|
||||
[HttpPost("~/api/v1/api-keys")]
|
||||
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
public async Task<ActionResult<ApiKeyData>> CreateKey(CreateApiKeyRequest request)
|
||||
{
|
||||
if (request is null)
|
||||
return BadRequest();
|
||||
var key = new APIKeyData()
|
||||
{
|
||||
Id = Encoders.Hex.EncodeData(RandomUtils.GetBytes(20)),
|
||||
Type = APIKeyType.Permanent,
|
||||
UserId = _userManager.GetUserId(User),
|
||||
Label = request.Label
|
||||
};
|
||||
key.Permissions = string.Join(";", request.Permissions.Select(p => p.ToString()).Distinct().ToArray());
|
||||
await _apiKeyRepository.CreateKey(key);
|
||||
return Ok(FromModel(key));
|
||||
}
|
||||
|
||||
[HttpDelete("~/api/v1/api-keys/current")]
|
||||
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.GreenfieldAPIKeys)]
|
||||
public async Task<ActionResult<ApiKeyData>> RevokeKey()
|
||||
public async Task<IActionResult> RevokeKey()
|
||||
{
|
||||
if (!ControllerContext.HttpContext.GetAPIKey(out var apiKey))
|
||||
{
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"security": [ ]
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/users/me": {
|
||||
|
@ -237,6 +237,83 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/api-keys": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"API Keys"
|
||||
],
|
||||
"summary": "Create a new API Key",
|
||||
"description": "Create a new API Key",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Information about the new api key",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiKeyData"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requestBody": {
|
||||
"x-name": "request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "The label of the new API Key",
|
||||
"nullable": true
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "The permissions granted to this API Key (See API Key Authentication)",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"API Key": [ "unrestricted" ],
|
||||
"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" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
|
|
Loading…
Add table
Reference in a new issue