diff --git a/test/Api.Test/AdminConsole/Authorization/HttpContextExtensionsTests.cs b/test/Api.Test/AdminConsole/Authorization/HttpContextExtensionsTests.cs new file mode 100644 index 0000000000..1901742777 --- /dev/null +++ b/test/Api.Test/AdminConsole/Authorization/HttpContextExtensionsTests.cs @@ -0,0 +1,28 @@ +using Bit.Api.AdminConsole.Authorization; +using Microsoft.AspNetCore.Http; +using NSubstitute; +using Xunit; + +namespace Bit.Api.Test.AdminConsole.Authorization; + +public class HttpContextExtensionsTests +{ + [Fact] + public async Task WithFeaturesCacheAsync_OnlyExecutesCallbackOnce() + { + var httpContext = new DefaultHttpContext(); + var callback = Substitute.For>>(); + callback().Returns(Task.FromResult("hello world")); + + // Call once + var result1 = await httpContext.WithFeaturesCacheAsync(callback); + Assert.Equal("hello world", result1); + await callback.ReceivedWithAnyArgs(1).Invoke(); + + // Call again - callback not executed again + var result2 = await httpContext.WithFeaturesCacheAsync(callback); + Assert.Equal("hello world", result2); + await callback.ReceivedWithAnyArgs(1).Invoke(); + } + +} diff --git a/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs b/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs index b3ebc2640e..117630cd74 100644 --- a/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs +++ b/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs @@ -13,25 +13,13 @@ namespace Bit.Api.Test.AdminConsole.Authorization; [SutProviderCustomize] public class OrganizationRequirementHandlerTests { - [Theory, BitAutoData] - public async Task IfNoOrganizationId_Throws(SutProvider sutProvider) + [Theory] + [BitAutoData((string)null)] + [BitAutoData("malformed guid")] + public async Task IfInvalidOrganizationId_Throws(string orgId, Guid userId, SutProvider sutProvider) { // Arrange - ArrangeRouteAndUser(sutProvider, null!); // no orgId in route - var testRequirement = Substitute.For(); - var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null); - - // Act - var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.HandleAsync(authContext)); - Assert.Equal(HttpContextExtensions.NoOrgIdError, exception.Message); - Assert.False(authContext.HasSucceeded); - } - - [Theory, BitAutoData] - public async Task IfInvalidOrganizationId_Throws(SutProvider sutProvider) - { - // Arrange - ArrangeRouteAndUser(sutProvider, "malformed guid"); + ArrangeRouteAndUser(sutProvider, orgId, userId); var testRequirement = Substitute.For(); var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null); @@ -42,10 +30,39 @@ public class OrganizationRequirementHandlerTests } [Theory, BitAutoData] - public async Task DoesNotAuthorize_IfAuthorizeAsync_ReturnsFalse(SutProvider sutProvider, Guid organizationId) + public async Task IfHttpContextIsNull_Throws(SutProvider sutProvider) + { + // Arrange + sutProvider.GetDependency().HttpContext = null; + var testRequirement = Substitute.For(); + var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null); + + // Act + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.HandleAsync(authContext)); + Assert.Contains(OrganizationRequirementHandler.NoHttpContextError, exception.Message); + Assert.False(authContext.HasSucceeded); + } + + [Theory, BitAutoData] + public async Task IfUserIdIsNull_Throws(Guid orgId, SutProvider sutProvider) + { + // Arrange + ArrangeRouteAndUser(sutProvider, orgId.ToString(), null); + var testRequirement = Substitute.For(); + var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null); + + // Act + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.HandleAsync(authContext)); + Assert.Contains(OrganizationRequirementHandler.NoUserIdError, exception.Message); + Assert.False(authContext.HasSucceeded); + } + + [Theory, BitAutoData] + public async Task DoesNotAuthorize_IfAuthorizeAsync_ReturnsFalse( + SutProvider sutProvider, Guid organizationId, Guid userId) { // Arrange route values - ArrangeRouteAndUser(sutProvider, organizationId.ToString()); + ArrangeRouteAndUser(sutProvider, organizationId.ToString(), userId); // Arrange requirement var testRequirement = Substitute.For(); @@ -63,10 +80,11 @@ public class OrganizationRequirementHandlerTests } [Theory, BitAutoData] - public async Task Authorizes_IfAuthorizeAsync_ReturnsTrue(SutProvider sutProvider, Guid organizationId) + public async Task Authorizes_IfAuthorizeAsync_ReturnsTrue( + SutProvider sutProvider, Guid organizationId, Guid userId) { // Arrange route values - ArrangeRouteAndUser(sutProvider, organizationId.ToString()); + ArrangeRouteAndUser(sutProvider, organizationId.ToString(), userId); // Arrange requirement var testRequirement = Substitute.For(); @@ -83,11 +101,12 @@ public class OrganizationRequirementHandlerTests Assert.True(authContext.HasSucceeded); } - private static void ArrangeRouteAndUser(SutProvider sutProvider, string orgIdRouteValue) + private static void ArrangeRouteAndUser(SutProvider sutProvider, string orgIdRouteValue, + Guid? userId) { var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues["orgId"] = orgIdRouteValue; sutProvider.GetDependency().HttpContext = httpContext; - sutProvider.GetDependency().GetProperUserId(Arg.Any()).Returns(Guid.NewGuid()); + sutProvider.GetDependency().GetProperUserId(Arg.Any()).Returns(userId); } }