diff --git a/src/Api/AdminConsole/Authorization/OrganizationRequirementHandler.cs b/src/Api/AdminConsole/Authorization/OrganizationRequirementHandler.cs
index 987c0f236a..040cd63491 100644
--- a/src/Api/AdminConsole/Authorization/OrganizationRequirementHandler.cs
+++ b/src/Api/AdminConsole/Authorization/OrganizationRequirementHandler.cs
@@ -11,8 +11,6 @@ namespace Bit.Api.AdminConsole.Authorization;
/// Retrieves the Organization ID from the route and then passes it to the requirement's AuthorizeAsync callback to
/// determine whether the action is authorized.
///
-///
-///
public class OrganizationRequirementHandler(
ICurrentContext currentContext,
IProviderOrganizationContext providerOrganizationContext,
diff --git a/src/Api/AdminConsole/Authorization/OrganizationRequirementHelpers.cs b/src/Api/AdminConsole/Authorization/OrganizationRequirementHelpers.cs
index 5449810953..4c7b9c4941 100644
--- a/src/Api/AdminConsole/Authorization/OrganizationRequirementHelpers.cs
+++ b/src/Api/AdminConsole/Authorization/OrganizationRequirementHelpers.cs
@@ -12,7 +12,7 @@ public static class OrganizationRequirementHelpers
}
httpContextAccessor.HttpContext.GetRouteData().Values.TryGetValue("orgId", out var orgIdParam);
- if (!Guid.TryParse(orgIdParam?.ToString(), out var orgId))
+ if (orgIdParam == null || !Guid.TryParse(orgIdParam.ToString(), out var orgId))
{
return null;
}
diff --git a/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs b/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs
new file mode 100644
index 0000000000..fc156c7eac
--- /dev/null
+++ b/test/Api.Test/AdminConsole/Authorization/OrganizationRequirementHandlerTests.cs
@@ -0,0 +1,92 @@
+using System.Security.Claims;
+using Bit.Api.AdminConsole.Authorization;
+using Bit.Api.AdminConsole.Context;
+using Bit.Test.Common.AutoFixture;
+using Bit.Test.Common.AutoFixture.Attributes;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using NSubstitute;
+using Xunit;
+
+namespace Bit.Api.Test.AdminConsole.Authorization;
+
+[SutProviderCustomize]
+public class OrganizationRequirementHandlerTests
+{
+ [Theory, BitAutoData]
+ public async Task IfNoOrganizationId_Throws(SutProvider sutProvider)
+ {
+ // Arrange
+ ArrangeRouteValues(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.Contains("No organizationId found", exception.Message);
+ Assert.False(authContext.HasSucceeded);
+ }
+
+ [Theory, BitAutoData]
+ public async Task IfInvalidOrganizationId_Throws(SutProvider sutProvider)
+ {
+ // Arrange
+ ArrangeRouteValues(sutProvider, "malformed guid");
+ var testRequirement = Substitute.For();
+ var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null);
+
+ // Act
+ var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.HandleAsync(authContext));
+ Assert.Contains("No organizationId found", exception.Message);
+ Assert.False(authContext.HasSucceeded);
+ }
+
+ [Theory, BitAutoData]
+ public async Task DoesNotAuthorize_IfAuthorizeAsync_ReturnsFalse(SutProvider sutProvider, Guid organizationId)
+ {
+ // Arrange route values
+ ArrangeRouteValues(sutProvider, organizationId.ToString());
+
+ // Arrange requirement
+ var testRequirement = Substitute.For();
+ testRequirement
+ .AuthorizeAsync(organizationId, null, Arg.Any())
+ .ReturnsForAnyArgs(false);
+ var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null);
+
+ // Act
+ await sutProvider.Sut.HandleAsync(authContext);
+
+ // Assert
+ await testRequirement.Received(1).AuthorizeAsync(organizationId, null, Arg.Any());
+ Assert.False(authContext.HasSucceeded);
+ }
+
+ [Theory, BitAutoData]
+ public async Task Authorizes_IfAuthorizeAsync_ReturnsTrue(SutProvider sutProvider, Guid organizationId)
+ {
+ // Arrange route values
+ ArrangeRouteValues(sutProvider, organizationId.ToString());
+
+ // Arrange requirement
+ var testRequirement = Substitute.For();
+ testRequirement
+ .AuthorizeAsync(organizationId, null, Arg.Any())
+ .ReturnsForAnyArgs(true);
+ var authContext = new AuthorizationHandlerContext([testRequirement], new ClaimsPrincipal(), null);
+
+ // Act
+ await sutProvider.Sut.HandleAsync(authContext);
+
+ // Assert
+ await testRequirement.Received(1).AuthorizeAsync(organizationId, null, Arg.Any());
+ Assert.True(authContext.HasSucceeded);
+ }
+
+ private static void ArrangeRouteValues(SutProvider sutProvider, string orgIdRouteValue)
+ {
+ var httpContext = new DefaultHttpContext();
+ httpContext.Request.RouteValues["orgId"] = orgIdRouteValue;
+ sutProvider.GetDependency().HttpContext = httpContext;
+ }
+}