Phase 1 WP-2–10: Repositories, audit service, security & auth (LDAP, JWT, roles, policies, data protection)

- WP-2: SecurityRepository + CentralUiRepository with audit log queries
- WP-3: AuditService with transactional guarantee (same SaveChangesAsync)
- WP-4: Optimistic concurrency tests (deployment records vs template last-write-wins)
- WP-5: Seed data (SCADA-Admins → Admin role mapping)
- WP-6: LdapAuthService (direct bind, TLS enforcement, group query)
- WP-7: JwtTokenService (HMAC-SHA256, 15-min refresh, 30-min idle timeout)
- WP-8: RoleMapper (LDAP groups → roles with site-scoped deployment)
- WP-9: Authorization policies (Admin/Design/Deployment + site scope handler)
- WP-10: Shared Data Protection keys via EF Core
141 tests pass, zero warnings.
This commit is contained in:
Joseph Doherty
2026-03-16 19:32:43 -04:00
parent 1996b21961
commit cafb7d2006
31 changed files with 3356 additions and 8 deletions

View File

@@ -6,6 +6,9 @@ public class LdapGroupMapping
public string LdapGroupName { get; set; }
public string Role { get; set; }
// Parameterless constructor for EF Core seed data
private LdapGroupMapping() { LdapGroupName = null!; Role = null!; }
public LdapGroupMapping(string ldapGroupName, string role)
{
LdapGroupName = ldapGroupName ?? throw new ArgumentNullException(nameof(ldapGroupName));

View File

@@ -1,3 +1,4 @@
using ScadaLink.Commons.Entities.Audit;
using ScadaLink.Commons.Entities.Deployment;
using ScadaLink.Commons.Entities.Instances;
using ScadaLink.Commons.Entities.Sites;
@@ -15,5 +16,18 @@ public interface ICentralUiRepository
Task<IReadOnlyList<DeploymentRecord>> GetRecentDeploymentsAsync(int count, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Area>> GetAreaTreeBySiteIdAsync(int siteId, CancellationToken cancellationToken = default);
// Audit log queries
Task<(IReadOnlyList<AuditLogEntry> Entries, int TotalCount)> GetAuditLogEntriesAsync(
string? user = null,
string? entityType = null,
string? action = null,
DateTimeOffset? from = null,
DateTimeOffset? to = null,
string? entityId = null,
string? entityName = null,
int page = 1,
int pageSize = 50,
CancellationToken cancellationToken = default);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}