From c07fcc171cb5a79a11d043d3c0a392948efd5102 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Wed, 2 Feb 2022 12:09:08 +0100 Subject: [PATCH] Fix Plugin Local Client authorization when user is provided (#3401) * Fix Plugin Local Client authorization when user is provided * 1337 hax --- .../GreenField/LocalBTCPayServerClient.cs | 60 ++++++++++++++++++- .../GreenFieldAuthorizationHandler.cs | 22 +++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs index 295f83967..cd066f37f 100644 --- a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs +++ b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Reflection; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; @@ -11,9 +12,12 @@ using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Security.Greenfield; using BTCPayServer.Services.Stores; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NBitcoin; using NBXplorer.Models; @@ -52,6 +56,7 @@ namespace BTCPayServer.Controllers.Greenfield private readonly GreenfieldPullPaymentController _greenfieldPullPaymentController; private readonly UIHomeController _homeController; private readonly GreenfieldStorePaymentMethodsController _storePaymentMethodsController; + private readonly IServiceProvider _serviceProvider; public BTCPayServerClientFactory(StoreRepository storeRepository, IOptionsMonitor identityOptions, @@ -73,7 +78,8 @@ namespace BTCPayServer.Controllers.Greenfield GreenfieldStoreWebhooksController storeWebhooksController, GreenfieldPullPaymentController greenfieldPullPaymentController, UIHomeController homeController, - GreenfieldStorePaymentMethodsController storePaymentMethodsController) + GreenfieldStorePaymentMethodsController storePaymentMethodsController, + IServiceProvider serviceProvider) { _storeRepository = storeRepository; _identityOptions = identityOptions; @@ -96,6 +102,7 @@ namespace BTCPayServer.Controllers.Greenfield _greenfieldPullPaymentController = greenfieldPullPaymentController; _homeController = homeController; _storePaymentMethodsController = storePaymentMethodsController; + _serviceProvider = serviceProvider; } public async Task Create(string userId, params string[] storeIds) @@ -113,7 +120,7 @@ namespace BTCPayServer.Controllers.Greenfield claims.AddRange((await _userManager.GetRolesAsync(user)).Select(s => new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s))); context.User = - new ClaimsPrincipal(new ClaimsIdentity(claims, GreenfieldConstants.AuthenticationType)); + new ClaimsPrincipal(new ClaimsIdentity(claims, $"Local{GreenfieldConstants.AuthenticationType}WithUser")); } else { @@ -132,6 +139,7 @@ namespace BTCPayServer.Controllers.Greenfield } return new LocalBTCPayServerClient( + _serviceProvider, _chainPaymentMethodsController, _storeOnChainWalletsController, _healthController, @@ -176,7 +184,9 @@ namespace BTCPayServer.Controllers.Greenfield private readonly UIHomeController _homeController; private readonly GreenfieldStorePaymentMethodsController _storePaymentMethodsController; - public LocalBTCPayServerClient(GreenfieldStoreOnChainPaymentMethodsController chainPaymentMethodsController, + public LocalBTCPayServerClient( + IServiceProvider serviceProvider, + GreenfieldStoreOnChainPaymentMethodsController chainPaymentMethodsController, GreenfieldStoreOnChainWalletsController storeOnChainWalletsController, GreenfieldHealthController healthController, GreenfieldPaymentRequestsController paymentRequestController, @@ -223,12 +233,56 @@ namespace BTCPayServer.Controllers.Greenfield greenFieldServerInfoController, greenfieldPullPaymentController, storesController, homeController, lightningNodeApiController, storeLightningNodeApiController as ControllerBase, storePaymentMethodsController }; + + var authoverride = new DefaultAuthorizationService( + serviceProvider.GetRequiredService(), + new AuthHandlerProvider( + serviceProvider.GetRequiredService(), + serviceProvider.GetRequiredService>(), + httpContextAccessor + ), + serviceProvider.GetRequiredService>(), + serviceProvider.GetRequiredService(), + serviceProvider.GetRequiredService(), + serviceProvider.GetRequiredService>() + + + ); + + foreach (var controller in controllers) { controller.ControllerContext.HttpContext = httpContextAccessor.HttpContext; + var authInterface = typeof(IAuthorizationService); + foreach (FieldInfo fieldInfo in controller.GetType().GetFields().Where(info => authInterface.IsAssignableFrom(info.FieldType))) + { + fieldInfo.SetValue(controller, authoverride); + } } } + class AuthHandlerProvider : IAuthorizationHandlerProvider + { + private readonly IHttpContextAccessor _httpContextAccessor; + + + private readonly UserManager _userManager; + private readonly StoreRepository _storeRepository; + + public AuthHandlerProvider(StoreRepository storeRepository, UserManager userManager, IHttpContextAccessor httpContextAccessor) + { + _storeRepository = storeRepository; + _userManager = userManager; + _httpContextAccessor = httpContextAccessor; + } + public Task> GetHandlersAsync(AuthorizationHandlerContext context) + { + return Task.FromResult>(new IAuthorizationHandler[] + { + new LocalGreenfieldAuthorizationHandler(_httpContextAccessor, _userManager, _storeRepository) + }); + } + } protected override HttpRequestMessage CreateHttpRequest(string path, Dictionary queryPayload = null, HttpMethod method = null) { diff --git a/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs b/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs index 03ce67719..335893c07 100644 --- a/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs +++ b/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs @@ -1,6 +1,7 @@ using System.Buffers; using System.Collections.Generic; using System.Globalization; +using System.Security.Claims; using System.Text; using System.Threading.Tasks; using BTCPayServer.Client; @@ -17,8 +18,29 @@ namespace BTCPayServer.Security.Greenfield { public class LocalGreenfieldAuthorizationHandler : AuthorizationHandler { + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly UserManager _userManager; + private readonly StoreRepository _storeRepository; + + public LocalGreenfieldAuthorizationHandler(IHttpContextAccessor httpContextAccessor, + UserManager userManager, + StoreRepository storeRepository) + { + _httpContextAccessor = httpContextAccessor; + _userManager = userManager; + _storeRepository = storeRepository; + } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement) { + var withuser = context.User.Identity?.AuthenticationType == $"Local{GreenfieldConstants.AuthenticationType}WithUser"; + if (withuser) + { + var newUser = new ClaimsPrincipal(new ClaimsIdentity(context.User.Claims, + $"{GreenfieldConstants.AuthenticationType}")); + var newContext = new AuthorizationHandlerContext(context.Requirements, newUser, null); + return new GreenfieldAuthorizationHandler(_httpContextAccessor, _userManager, _storeRepository).HandleAsync(newContext); + } + var succeed = context.User.Identity.AuthenticationType == $"Local{GreenfieldConstants.AuthenticationType}"; if (succeed)