diff --git a/BTCPayServer.Tests/ApiKeysTests.cs b/BTCPayServer.Tests/ApiKeysTests.cs index 1630863dd..419fb2a60 100644 --- a/BTCPayServer.Tests/ApiKeysTests.cs +++ b/BTCPayServer.Tests/ApiKeysTests.cs @@ -214,8 +214,9 @@ namespace BTCPayServer.Tests Assert.DoesNotContain(resultStores, data => data.Id.Equals(secondUser.StoreId, StringComparison.InvariantCultureIgnoreCase)); } - else + else if(!permissions.Contains(Permissions.ServerManagement)) { + await Assert.ThrowsAnyAsync(async () => { await TestApiAgainstAccessToken(accessToken, @@ -223,12 +224,26 @@ namespace BTCPayServer.Tests tester.PayTester.HttpClient); }); } + else + { + await TestApiAgainstAccessToken(accessToken, + $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-edit", + tester.PayTester.HttpClient); + } - await Assert.ThrowsAnyAsync(async () => + if (!permissions.Contains(Permissions.ServerManagement)) + { + await Assert.ThrowsAnyAsync(async () => + { + await TestApiAgainstAccessToken(accessToken, $"{TestApiPath}/me/stores/{secondUser.StoreId}/can-edit", + tester.PayTester.HttpClient); + }); + } + else { await TestApiAgainstAccessToken(accessToken, $"{TestApiPath}/me/stores/{secondUser.StoreId}/can-edit", tester.PayTester.HttpClient); - }); + } if (permissions.Contains(Permissions.ServerManagement)) { @@ -236,6 +251,15 @@ namespace BTCPayServer.Tests $"{TestApiPath}/me/is-admin", tester.PayTester.HttpClient)); } + else + { + await Assert.ThrowsAnyAsync(async () => + { + await TestApiAgainstAccessToken(accessToken, + $"{TestApiPath}/me/is-admin", + tester.PayTester.HttpClient); + }); + } } public async Task TestApiAgainstAccessToken(string apikey, string url, HttpClient client) diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 9841a004e..937d1d5ae 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -62,8 +62,10 @@ namespace BTCPayServer.Tests user.GrantAccess(); await user.MakeAdmin(); string apiKeyProfile = await GenerateAPIKey(tester, user, Permissions.ProfileManagement); + string apiKeyServer = await GenerateAPIKey(tester, user, Permissions.ServerManagement); string apiKeyInsufficient = await GenerateAPIKey(tester, user, Permissions.StoreManagement); var clientProfile = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyProfile); + var clientServer = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyServer); var clientInsufficient= new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyInsufficient); var apiKeyProfileUserData = await clientProfile.GetCurrentUser(); @@ -72,6 +74,7 @@ namespace BTCPayServer.Tests Assert.Equal(apiKeyProfileUserData.Email, user.RegisterDetails.Email); await Assert.ThrowsAsync(async () => await clientInsufficient.GetCurrentUser()); + await clientServer.GetCurrentUser(); } } diff --git a/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs b/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs index fe2f5bfc2..71c27e698 100644 --- a/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs +++ b/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using BTCPayServer.Client; using BTCPayServer.Data; @@ -69,20 +70,32 @@ namespace BTCPayServer.Security.APIKeys case Policies.CanModifyServerSettings.Key: if (!context.HasPermissions(Permissions.ServerManagement)) break; - // For this authorization, we stil check in database because it is super sensitive. - var user = await _userManager.GetUserAsync(context.User); - if (user == null) - break; - if (!await _userManager.IsInRoleAsync(user, Roles.ServerAdmin)) - break; - success = true; + // For this authorization, we still check in database because it is super sensitive. + success = await IsUserAdmin(context.User); break; } + //if you do not have the specific permissions, BUT you have server management, we enable god mode + if (!success && context.HasPermissions(Permissions.ServerManagement) && + requirement.Policy != Policies.CanModifyServerSettings.Key) + { + success = await IsUserAdmin(context.User); + } + if (success) { context.Succeed(requirement); } } + + private async Task IsUserAdmin(ClaimsPrincipal contextUser) + { + var user = await _userManager.GetUserAsync(contextUser); + if (user == null) + return false; + if (!await _userManager.IsInRoleAsync(user, Roles.ServerAdmin)) + return false; + return true; + } } }