305 lines
11 KiB
C#
305 lines
11 KiB
C#
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using System.Security.Claims;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Xunit;
|
|
using IamService.Domain.AggregatesModel.UserAggregate;
|
|
|
|
namespace IamService.FunctionalTests.Controllers;
|
|
|
|
/// <summary>
|
|
/// EN: Functional tests for Authorization Policies.
|
|
/// VI: Functional tests cho Authorization Policies.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// EN: These tests require additional authentication configuration in CustomWebApplicationFactory
|
|
/// to properly inject role claims into the test JWT. The tests verify that:
|
|
/// - RequireSuperAdmin: Only SuperAdmin can access PAM endpoints
|
|
/// - RequireAdmin: Admin/SuperAdmin can access management endpoints
|
|
/// - RequireAuditor: Auditor/Admin/SuperAdmin can access audit endpoints
|
|
/// - OwnerOrAdmin: User can access own profile or Admin can access any
|
|
///
|
|
/// TODO: Configure test authentication to properly inject role claims.
|
|
/// Current unit tests in IamService.UnitTests cover authorization handler logic.
|
|
/// VI: Các tests này yêu cầu cấu hình thêm authentication trong CustomWebApplicationFactory
|
|
/// để inject role claims vào test JWT. Unit tests trong IamService.UnitTests đã cover
|
|
/// logic authorization handler.
|
|
/// </remarks>
|
|
[Collection("Sequential")]
|
|
public class AuthorizationPolicyTests : IClassFixture<CustomWebApplicationFactory>
|
|
{
|
|
private readonly HttpClient _client;
|
|
private readonly CustomWebApplicationFactory _factory;
|
|
|
|
public AuthorizationPolicyTests(CustomWebApplicationFactory factory)
|
|
{
|
|
_factory = factory;
|
|
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
|
|
{
|
|
AllowAutoRedirect = false
|
|
});
|
|
}
|
|
|
|
#region Token Generation Helpers
|
|
|
|
/// <summary>
|
|
/// EN: Generate a test JWT token with specified roles.
|
|
/// VI: Tạo test JWT token với các roles được chỉ định.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// EN: Creates an unsigned JWT that the CustomWebApplicationFactory accepts.
|
|
/// The test factory is configured to skip signature validation.
|
|
/// VI: Tạo unsigned JWT mà CustomWebApplicationFactory chấp nhận.
|
|
/// Test factory được cấu hình để bỏ qua signature validation.
|
|
/// </remarks>
|
|
private string GenerateTestToken(Guid userId, string email, params string[] roles)
|
|
{
|
|
var claims = new List<Claim>
|
|
{
|
|
new("sub", userId.ToString()),
|
|
new("email", email),
|
|
new("name", "Test User"),
|
|
new("iss", "http://localhost"),
|
|
new("aud", "api"),
|
|
new("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
|
|
new("exp", DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds().ToString())
|
|
};
|
|
|
|
// Add role claims
|
|
foreach (var role in roles)
|
|
{
|
|
claims.Add(new Claim("role", role));
|
|
}
|
|
|
|
// Create unsigned token descriptor
|
|
var tokenDescriptor = new SecurityTokenDescriptor
|
|
{
|
|
Subject = new ClaimsIdentity(claims),
|
|
Expires = DateTime.UtcNow.AddHours(1),
|
|
Issuer = "http://localhost",
|
|
Audience = "api"
|
|
};
|
|
|
|
// Generate JWT without signature (for test purposes)
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var token = handler.CreateJwtSecurityToken(tokenDescriptor);
|
|
|
|
return handler.WriteToken(token);
|
|
}
|
|
|
|
private HttpRequestMessage CreateRequest(HttpMethod method, string url, string token)
|
|
{
|
|
var request = new HttpRequestMessage(method, url);
|
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
return request;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RequireAdmin Policy Tests
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetUsers_WithoutAdminRole_ShouldReturn403()
|
|
{
|
|
// Arrange - User with no admin role
|
|
var token = GenerateTestToken(Guid.NewGuid(), "user@example.com", "User");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/users", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetUsers_WithAdminRole_ShouldReturn200()
|
|
{
|
|
// Arrange - User with Admin role
|
|
var token = GenerateTestToken(Guid.NewGuid(), "admin@example.com", "Admin");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/users", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetUsers_WithSuperAdminRole_ShouldReturn200()
|
|
{
|
|
// Arrange - SuperAdmin can access Admin endpoints
|
|
var token = GenerateTestToken(Guid.NewGuid(), "superadmin@example.com", "SuperAdmin");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/users", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RequireSuperAdmin Policy Tests (PAM)
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetActivePrivilegedAccess_WithAdminRole_ShouldReturn403()
|
|
{
|
|
// Arrange - Admin cannot access SuperAdmin endpoints
|
|
var userId = Guid.NewGuid();
|
|
var token = GenerateTestToken(userId, "admin@example.com", "Admin");
|
|
var request = CreateRequest(HttpMethod.Get, $"/api/v1/privileged-access/active?userId={userId}", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetActivePrivilegedAccess_WithSuperAdminRole_ShouldReturn200()
|
|
{
|
|
// Arrange - Only SuperAdmin can access PAM
|
|
var userId = Guid.NewGuid();
|
|
var token = GenerateTestToken(userId, "superadmin@example.com", "SuperAdmin");
|
|
var request = CreateRequest(HttpMethod.Get, $"/api/v1/privileged-access/active?userId={userId}", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RequireAuditor Policy Tests
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetAuditLogs_WithUserRole_ShouldReturn403()
|
|
{
|
|
// Arrange - Regular user cannot access audit logs
|
|
var token = GenerateTestToken(Guid.NewGuid(), "user@example.com", "User");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/audit/logs", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetAuditLogs_WithAuditorRole_ShouldReturn200()
|
|
{
|
|
// Arrange - Auditor can access audit logs
|
|
var token = GenerateTestToken(Guid.NewGuid(), "auditor@example.com", "Auditor");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/audit/logs", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GetComplianceReports_WithAdminRole_ShouldReturn200()
|
|
{
|
|
// Arrange - Admin can access compliance (auditor policy allows admin)
|
|
var token = GenerateTestToken(Guid.NewGuid(), "admin@example.com", "Admin");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/compliance/reports", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Controller-Level Policy Tests
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task RolesController_WithUserRole_ShouldReturn403()
|
|
{
|
|
// Arrange - User cannot access roles management
|
|
var token = GenerateTestToken(Guid.NewGuid(), "user@example.com", "User");
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/roles", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task OrganizationsController_WithUserRole_ShouldReturn403()
|
|
{
|
|
// Arrange - User cannot access organizations management
|
|
var token = GenerateTestToken(Guid.NewGuid(), "user@example.com", "User");
|
|
var orgId = Guid.NewGuid();
|
|
var request = CreateRequest(HttpMethod.Get, $"/api/v1/organizations/{orgId}", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
[Fact(Skip = "Requires test authentication configuration for role claims")]
|
|
public async Task GroupsController_WithUserRole_ShouldReturn403()
|
|
{
|
|
// Arrange - User cannot access groups management
|
|
var token = GenerateTestToken(Guid.NewGuid(), "user@example.com", "User");
|
|
var groupId = Guid.NewGuid();
|
|
var request = CreateRequest(HttpMethod.Get, $"/api/v1/groups/{groupId}", token);
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Edge Cases
|
|
|
|
[Fact]
|
|
public async Task AnyEndpoint_WithoutToken_ShouldReturn401()
|
|
{
|
|
// Arrange - No token provided
|
|
var response = await _client.GetAsync("/api/v1/users");
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AnyEndpoint_WithInvalidToken_ShouldReturn401()
|
|
{
|
|
// Arrange - Invalid token
|
|
var request = CreateRequest(HttpMethod.Get, "/api/v1/users", "invalid-token");
|
|
|
|
// Act
|
|
var response = await _client.SendAsync(request);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
#endregion
|
|
}
|