From fd75008499274fd1d106a189a5f089439492cd83 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Tue, 7 Dec 2021 16:40:24 +0100 Subject: [PATCH] Allow pull payments for store guests (#3128) --- ...torePullPaymentsController.PullPayments.cs | 7 ++- .../Security/CookieAuthorizationHandler.cs | 16 +++--- BTCPayServer/Security/PermissionTagHelper.cs | 51 +++++++++++++++++++ .../Views/StorePullPayments/Payouts.cshtml | 9 ++-- .../StorePullPayments/PullPayments.cshtml | 12 +++-- BTCPayServer/Views/Stores/_Nav.cshtml | 21 ++++---- .../Views/UserStores/ListStores.cshtml | 5 +- 7 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 BTCPayServer/Security/PermissionTagHelper.cs diff --git a/BTCPayServer/Controllers/StorePullPaymentsController.PullPayments.cs b/BTCPayServer/Controllers/StorePullPaymentsController.PullPayments.cs index 9e0bb7bb5..b39b071ae 100644 --- a/BTCPayServer/Controllers/StorePullPaymentsController.PullPayments.cs +++ b/BTCPayServer/Controllers/StorePullPaymentsController.PullPayments.cs @@ -26,7 +26,7 @@ using StoreData = BTCPayServer.Data.StoreData; namespace BTCPayServer.Controllers { [Route("stores/{storeId}/pull-payments")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] + [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] [AutoValidateAntiforgeryToken] public class StorePullPaymentsController: Controller { @@ -60,6 +60,7 @@ namespace BTCPayServer.Controllers } [HttpGet("new")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] public async Task NewPullPayment(string storeId) { if (CurrentStore is null) @@ -86,6 +87,7 @@ namespace BTCPayServer.Controllers } [HttpPost("new")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] public async Task NewPullPayment(string storeId, NewPullPaymentModel model) { if (CurrentStore is null) @@ -217,6 +219,7 @@ namespace BTCPayServer.Controllers } [HttpGet("{pullPaymentId}/archive")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] public IActionResult ArchivePullPayment(string storeId, string pullPaymentId) { @@ -224,6 +227,7 @@ namespace BTCPayServer.Controllers } [HttpPost("{pullPaymentId}/archive")] + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] public async Task ArchivePullPaymentPost(string storeId, string pullPaymentId) { @@ -236,6 +240,7 @@ namespace BTCPayServer.Controllers return RedirectToAction(nameof(PullPayments), new { storeId = storeId }); } + [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] [HttpPost("payouts")] public async Task PayoutsPost( string storeId, PayoutsModel vm, CancellationToken cancellationToken) diff --git a/BTCPayServer/Security/CookieAuthorizationHandler.cs b/BTCPayServer/Security/CookieAuthorizationHandler.cs index 998c556f7..a15d38ca9 100644 --- a/BTCPayServer/Security/CookieAuthorizationHandler.cs +++ b/BTCPayServer/Security/CookieAuthorizationHandler.cs @@ -37,7 +37,7 @@ namespace BTCPayServer.Security return; } - string storeId = _HttpContext.GetImplicitStoreId(); + string storeId = context.Resource is string s? s :_HttpContext.GetImplicitStoreId(); if (storeId == null) return; @@ -47,20 +47,20 @@ namespace BTCPayServer.Security var store = await _storeRepository.FindStore(storeId, userid); - if (store == null) - return; + bool success = false; switch (requirement.Policy) { case Policies.CanModifyStoreSettings: - if (store.Role == StoreRoles.Owner || isAdmin) + if (store != null && (store.Role == StoreRoles.Owner || isAdmin)) + success = true; + break; + case Policies.CanViewStoreSettings: + if (store != null || isAdmin) success = true; break; case Policies.CanCreateInvoice: - if (store.Role == StoreRoles.Owner || - store.Role == StoreRoles.Guest || - isAdmin || - store.GetStoreBlob().AnyoneCanInvoice) + if (store != null || isAdmin) success = true; break; } diff --git a/BTCPayServer/Security/PermissionTagHelper.cs b/BTCPayServer/Security/PermissionTagHelper.cs new file mode 100644 index 000000000..73b81c876 --- /dev/null +++ b/BTCPayServer/Security/PermissionTagHelper.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Logging; + +namespace BTCPayServer.Security +{ + [HtmlTargetElement(Attributes = nameof(Permission))] + public class PermissionTagHelper : TagHelper + { + private readonly IAuthorizationService _authorizationService; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ILogger _logger; + + public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor, ILogger logger) + { + _authorizationService = authorizationService; + _httpContextAccessor = httpContextAccessor; + _logger = logger; + } + + public string Permission { get; set; } + public string PermissionResource { get; set; } + + public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + if (string.IsNullOrEmpty(Permission)) + { + return; + } + + var key = $"{Permission}_{PermissionResource}"; + if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key,out var cachedResult)) + { + var result = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, + PermissionResource, + Permission); + + cachedResult = result; + _httpContextAccessor.HttpContext.Items.Add(key, result); + + } + if (!((AuthorizationResult)cachedResult).Succeeded) + { + output.SuppressOutput(); + } + + } + } +} diff --git a/BTCPayServer/Views/StorePullPayments/Payouts.cshtml b/BTCPayServer/Views/StorePullPayments/Payouts.cshtml index 4779e131e..e34eb9de4 100644 --- a/BTCPayServer/Views/StorePullPayments/Payouts.cshtml +++ b/BTCPayServer/Views/StorePullPayments/Payouts.cshtml @@ -2,6 +2,7 @@ @using BTCPayServer.Payments @using BTCPayServer.Views.Stores @using BTCPayServer.Abstractions.Extensions +@using BTCPayServer.Client @model BTCPayServer.Models.WalletViewModels.PayoutsModel @inject IEnumerable PayoutHandlers; @@ -88,9 +89,9 @@ - @if (Model.Payouts.Any() && stateActions.Any()) + @if (Model.Payouts.Any() && stateActions.Any() ) { -
+