// ============================================================================= // A01_BrokenAccessControl/AuthorizationBypassTests.cs // OWASP A01:2021 - Broken Access Control // Tests for authorization bypass vulnerabilities // ============================================================================= using FluentAssertions; using StellaOps.Security.Tests.Infrastructure; namespace StellaOps.Security.Tests.A01_BrokenAccessControl; /// /// Tests for broken access control vulnerabilities including: /// - Horizontal privilege escalation (accessing other users' data) /// - Vertical privilege escalation (accessing admin functions) /// - IDOR (Insecure Direct Object Reference) /// - Path-based access control bypass /// [Trait("Category", "Security")] [Trait("OWASP", "A01")] [OwaspCategory("A01:2021", "Broken Access Control")] public class AuthorizationBypassTests : SecurityTestBase { [Fact] public void Should_Reject_Cross_Tenant_Access_Attempt() { // Arrange var tenantA = GenerateTestTenantId(); var tenantB = GenerateTestTenantId(); var userFromTenantA = GenerateTestUserId(); // Act & Assert // Simulates checking that a user from Tenant A cannot access Tenant B resources // In real implementation, this would test the actual authorization service tenantA.Should().NotBe(tenantB, "Test setup: tenants should be different"); // The authorization check should prevent cross-tenant access var authorizationResult = SimulateCrossTenantAccessCheck(tenantA, tenantB, userFromTenantA); authorizationResult.Should().BeFalse("Cross-tenant access should be denied"); } [Fact] public void Should_Reject_IDOR_Attack_On_Resource_Id() { // Arrange var authenticatedUserId = GenerateTestUserId(); var otherUserId = GenerateTestUserId(); // Act - Attempt to access another user's resource by ID manipulation var canAccessOtherUserResource = SimulateIdorCheck(authenticatedUserId, otherUserId); // Assert canAccessOtherUserResource.Should().BeFalse( "User should not access resources of another user via IDOR"); } [Fact] public void Should_Reject_Admin_Function_Access_By_Regular_User() { // Arrange var regularUserId = GenerateTestUserId(); var isAdmin = false; // Act - Attempt to access admin-only function var canAccessAdminFunction = SimulateAdminFunctionCheck(regularUserId, isAdmin); // Assert canAccessAdminFunction.Should().BeFalse( "Regular user should not access admin functions"); } [Theory] [InlineData("/api/admin/users", false)] [InlineData("/api/admin/settings", false)] [InlineData("/api/admin/audit-logs", false)] [InlineData("/api/v1/scans", true)] // Regular endpoint - should be accessible public void Should_Enforce_Path_Based_Authorization(string path, bool shouldBeAccessible) { // Arrange var regularUserId = GenerateTestUserId(); // Act var canAccess = SimulatePathBasedAuth(path, regularUserId, isAdmin: false); // Assert canAccess.Should().Be(shouldBeAccessible, $"Path {path} should {(shouldBeAccessible ? "" : "not ")}be accessible to regular users"); } [Fact] public void Should_Prevent_Parameter_Tampering_For_Ownership() { // Arrange var authenticatedUserId = GenerateTestUserId(); var tamperedOwnerId = GenerateTestUserId(); // Attacker tries to claim ownership // Act - Simulate API call where attacker modifies owner_id parameter var result = SimulateOwnershipTamperingCheck(authenticatedUserId, tamperedOwnerId); // Assert result.Should().BeFalse("Parameter tampering for ownership should be rejected"); } [Fact] public void Should_Enforce_Method_Level_Authorization() { // Arrange var userId = GenerateTestUserId(); var resourceId = Guid.NewGuid(); // User has READ but not WRITE permission var readAllowed = true; var writeAllowed = false; // Act & Assert SimulateMethodAuth(userId, resourceId, "GET", readAllowed).Should().BeTrue(); SimulateMethodAuth(userId, resourceId, "DELETE", writeAllowed).Should().BeFalse( "User with read-only permission should not delete resources"); } [Fact] public void Should_Validate_JWT_Claims_For_Authorization() { // Arrange - JWT with tampered claims var tamperedToken = MaliciousPayloads.JwtAttacks.NoneAlgorithm; // Act & Assert var action = () => ValidateJwtForAuth(tamperedToken); action.Should().Throw("Tampered JWT should be rejected"); } #region Simulation Helpers private static bool SimulateCrossTenantAccessCheck(Guid requestorTenant, Guid targetTenant, Guid userId) { // In real implementation, this would call the authorization service // For test purposes, we verify the logic exists return requestorTenant == targetTenant; } private static bool SimulateIdorCheck(Guid authenticatedUserId, Guid resourceOwnerId) { // Proper IDOR protection requires ownership verification return authenticatedUserId == resourceOwnerId; } private static bool SimulateAdminFunctionCheck(Guid userId, bool isAdmin) { // Admin functions require admin role return isAdmin; } private static bool SimulatePathBasedAuth(string path, Guid userId, bool isAdmin) { // Admin paths require admin role if (path.StartsWith("/api/admin", StringComparison.OrdinalIgnoreCase)) { return isAdmin; } return true; } private static bool SimulateOwnershipTamperingCheck(Guid authenticatedUserId, Guid claimedOwnerId) { // The claimed owner must match the authenticated user return authenticatedUserId == claimedOwnerId; } private static bool SimulateMethodAuth(Guid userId, Guid resourceId, string method, bool hasPermission) { // Method-level authorization check return hasPermission; } private static void ValidateJwtForAuth(string token) { // Simulate JWT validation that should reject invalid tokens if (token.EndsWith('.') || token.Split('.').Length != 3) { throw new InvalidOperationException("Invalid JWT format"); } var parts = token.Split('.'); if (string.IsNullOrEmpty(parts[2])) { throw new InvalidOperationException("JWT signature is missing"); } } #endregion }