fix(configuration-database): resolve ConfigurationDatabase-012 — store inbound-API keys as HMAC-SHA256 hashes
Inbound-API bearer credentials are no longer persisted in plaintext. ApiKey now holds a KeyHash (peppered HMAC-SHA256); the key is shown once at creation and only its hash is stored. Lookup and validation hash the presented candidate. Cross-module: Commons (ApiKey, ApiKeyHasher), ConfigurationDatabase (mapping + HashApiKeyValue migration), InboundAPI (ApiKeyValidator), ManagementService (key creation), CentralUI (ApiKeys.razor). Existing keys must be re-issued.
This commit is contained in:
@@ -134,4 +134,30 @@ public class SplitQueryBehaviourTests : IDisposable
|
||||
Assert.Equal(2, loaded!.Attributes.Count);
|
||||
Assert.Single(loaded.Scripts);
|
||||
}
|
||||
|
||||
// ConfigurationDatabase-012: the ApiKey table must persist the bearer credential
|
||||
// as a hash column (KeyHash) and must NOT carry a plaintext KeyValue column.
|
||||
|
||||
[Fact]
|
||||
public void ApiKey_KeyHashColumn_IsMappedAndUniquelyIndexed()
|
||||
{
|
||||
var entityType = _context.Model.FindEntityType(typeof(ScadaLink.Commons.Entities.InboundApi.ApiKey))!;
|
||||
|
||||
var keyHash = entityType.FindProperty("KeyHash");
|
||||
Assert.NotNull(keyHash);
|
||||
Assert.False(keyHash!.IsNullable);
|
||||
|
||||
var hashIndex = entityType.GetIndexes()
|
||||
.FirstOrDefault(i => i.Properties.Any(p => p.Name == "KeyHash"));
|
||||
Assert.NotNull(hashIndex);
|
||||
Assert.True(hashIndex!.IsUnique);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApiKey_HasNoPlaintextKeyValueColumn()
|
||||
{
|
||||
var entityType = _context.Model.FindEntityType(typeof(ScadaLink.Commons.Entities.InboundApi.ApiKey))!;
|
||||
|
||||
Assert.Null(entityType.FindProperty("KeyValue"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user