SECURITY FIX: Prevent intra-tenant unauthorized project access
Problem:
Users within the same tenant could join ANY project room via SignalR
without permission checks, causing potential data leakage. The TODO
at line 18 in ProjectHub.cs left this critical validation unimplemented.
Solution:
- Created IProjectPermissionService interface for permission checking
- Implemented ProjectPermissionService with owner-based validation
- Added permission validation to ProjectHub.JoinProject() and LeaveProject()
- Returns clear HubException if user lacks permission
- Multi-tenant isolation enforced via PMDbContext query filters
Implementation Details:
1. IProjectPermissionService.IsUserProjectMemberAsync() checks if user
is the project owner (currently based on Project.OwnerId)
2. Service registered as Scoped in DI container via ModuleExtensions
3. ProjectHub throws HubException with clear error message for unauthorized access
4. TODO comments added for future ProjectMember table implementation
Files Changed:
- Added: IProjectPermissionService.cs (Application layer interface)
- Added: ProjectPermissionService.cs (Infrastructure layer implementation)
- Modified: ProjectHub.cs (permission checks in JoinProject/LeaveProject)
- Modified: ModuleExtensions.cs (service registration)
Testing:
- All existing tests pass (437 tests, 0 failures)
- Build succeeds with no errors
- Multi-tenant isolation preserved via DbContext filters
Future Enhancement:
When ProjectMember table is implemented, extend permission check to:
return project.OwnerId == userId ||
await _dbContext.ProjectMembers.AnyAsync(pm =>
pm.ProjectId == projectId && pm.UserId == userId)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
19 lines
790 B
C#
19 lines
790 B
C#
namespace ColaFlow.Modules.ProjectManagement.Application.Services;
|
|
|
|
/// <summary>
|
|
/// Service for checking project-level permissions
|
|
/// </summary>
|
|
public interface IProjectPermissionService
|
|
{
|
|
/// <summary>
|
|
/// Checks if a user has permission to access a project
|
|
/// Currently checks if user is the project owner
|
|
/// TODO: Extend to check ProjectMember table when implemented
|
|
/// </summary>
|
|
/// <param name="userId">User ID to check</param>
|
|
/// <param name="projectId">Project ID to check access for</param>
|
|
/// <param name="cancellationToken">Cancellation token</param>
|
|
/// <returns>True if user has access, false otherwise</returns>
|
|
Task<bool> IsUserProjectMemberAsync(Guid userId, Guid projectId, CancellationToken cancellationToken = default);
|
|
}
|