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

@@ -0,0 +1,37 @@
using System.Text.Json;
using ScadaLink.Commons.Entities.Audit;
using ScadaLink.Commons.Interfaces.Services;
namespace ScadaLink.ConfigurationDatabase.Services;
public class AuditService : IAuditService
{
private readonly ScadaLinkDbContext _context;
public AuditService(ScadaLinkDbContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public async Task LogAsync(
string user,
string action,
string entityType,
string entityId,
string entityName,
object? afterState,
CancellationToken cancellationToken = default)
{
var entry = new AuditLogEntry(user, action, entityType, entityId, entityName)
{
Timestamp = DateTimeOffset.UtcNow,
AfterStateJson = afterState != null
? JsonSerializer.Serialize(afterState)
: null
};
// Add to change tracker only — caller is responsible for calling SaveChangesAsync
// to ensure atomicity with the entity change.
await _context.AuditLogEntries.AddAsync(entry, cancellationToken);
}
}