- Implemented InjectionTests.cs to cover various injection vulnerabilities including SQL, NoSQL, Command, LDAP, and XPath injections. - Created SsrfTests.cs to test for Server-Side Request Forgery (SSRF) vulnerabilities, including internal URL access, cloud metadata access, and URL allowlist bypass attempts. - Introduced MaliciousPayloads.cs to store a collection of malicious payloads for testing various security vulnerabilities. - Added SecurityAssertions.cs for common security-specific assertion helpers. - Established SecurityTestBase.cs as a base class for security tests, providing common infrastructure and mocking utilities. - Configured the test project StellaOps.Security.Tests.csproj with necessary dependencies for testing.
129 lines
4.0 KiB
C#
129 lines
4.0 KiB
C#
// =============================================================================
|
|
// SecurityTestBase.cs
|
|
// Base class for all security tests providing common infrastructure
|
|
// =============================================================================
|
|
|
|
using FluentAssertions;
|
|
using Microsoft.Extensions.Logging;
|
|
using Moq;
|
|
|
|
namespace StellaOps.Security.Tests.Infrastructure;
|
|
|
|
/// <summary>
|
|
/// Base class for OWASP-category security tests.
|
|
/// Provides common test infrastructure, mocking utilities, and security assertions.
|
|
/// </summary>
|
|
[Trait("Category", "Security")]
|
|
public abstract class SecurityTestBase : IDisposable
|
|
{
|
|
protected readonly Mock<ILogger> LoggerMock;
|
|
protected readonly CancellationToken TestCancellation;
|
|
private readonly CancellationTokenSource _cts;
|
|
|
|
protected SecurityTestBase()
|
|
{
|
|
LoggerMock = new Mock<ILogger>();
|
|
_cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
|
TestCancellation = _cts.Token;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assert that an action throws a security-related exception.
|
|
/// </summary>
|
|
protected static void AssertSecurityException<TException>(Action action, string? expectedMessage = null)
|
|
where TException : Exception
|
|
{
|
|
var exception = Assert.Throws<TException>(action);
|
|
if (expectedMessage != null)
|
|
{
|
|
exception.Message.Should().Contain(expectedMessage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assert that an async action throws a security-related exception.
|
|
/// </summary>
|
|
protected static async Task AssertSecurityExceptionAsync<TException>(Func<Task> action, string? expectedMessage = null)
|
|
where TException : Exception
|
|
{
|
|
var exception = await Assert.ThrowsAsync<TException>(action);
|
|
if (expectedMessage != null)
|
|
{
|
|
exception.Message.Should().Contain(expectedMessage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assert that the logger was called with a security warning.
|
|
/// </summary>
|
|
protected void AssertSecurityWarningLogged(string expectedMessage)
|
|
{
|
|
LoggerMock.Verify(
|
|
x => x.Log(
|
|
LogLevel.Warning,
|
|
It.IsAny<EventId>(),
|
|
It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains(expectedMessage)),
|
|
It.IsAny<Exception?>(),
|
|
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
|
|
Times.AtLeastOnce);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assert that no sensitive data is present in the response.
|
|
/// </summary>
|
|
protected static void AssertNoSensitiveDataLeakage(string content)
|
|
{
|
|
var sensitivePatterns = new[]
|
|
{
|
|
"password",
|
|
"secret",
|
|
"api_key",
|
|
"apikey",
|
|
"private_key",
|
|
"token",
|
|
"bearer",
|
|
"authorization"
|
|
};
|
|
|
|
foreach (var pattern in sensitivePatterns)
|
|
{
|
|
// Case-insensitive check for sensitive patterns in unexpected places
|
|
content.ToLowerInvariant().Should().NotContain(pattern,
|
|
$"Response should not contain sensitive data pattern: {pattern}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate a random tenant ID for isolation.
|
|
/// </summary>
|
|
protected static Guid GenerateTestTenantId() => Guid.NewGuid();
|
|
|
|
/// <summary>
|
|
/// Generate a random user ID for isolation.
|
|
/// </summary>
|
|
protected static Guid GenerateTestUserId() => Guid.NewGuid();
|
|
|
|
public virtual void Dispose()
|
|
{
|
|
_cts.Cancel();
|
|
_cts.Dispose();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Trait for categorizing tests by OWASP category.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
|
public class OwaspCategoryAttribute : Attribute
|
|
{
|
|
public string Category { get; }
|
|
public string Description { get; }
|
|
|
|
public OwaspCategoryAttribute(string category, string description)
|
|
{
|
|
Category = category;
|
|
Description = description;
|
|
}
|
|
}
|