MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Tests/Security/SecurityValidatorTests.cs

238 lines
5.9 KiB
C#
Executable File

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MarketAlly.AIPlugin.Security;
using System;
using System.IO;
using System.Collections.Generic;
namespace MarketAlly.AIPlugin.Tests.Security
{
[TestClass]
public class SecurityValidatorTests
{
private SecurityConfiguration _testConfig;
private string _testDirectory;
[TestInitialize]
public void Setup()
{
_testDirectory = Path.Combine(Path.GetTempPath(), "AIPlugin_Tests", Guid.NewGuid().ToString());
Directory.CreateDirectory(_testDirectory);
_testConfig = new SecurityConfiguration
{
AllowedDirectories = new List<string> { _testDirectory },
AllowedFileExtensions = new List<string> { ".txt", ".json", ".log" },
MaxFileSizeBytes = 1024 * 1024, // 1MB
AllowedUrlSchemes = new List<string> { "https" }
};
}
[TestCleanup]
public void Cleanup()
{
if (Directory.Exists(_testDirectory))
{
Directory.Delete(_testDirectory, true);
}
}
[TestMethod]
public void ValidateAndNormalizePath_ValidPath_ReturnsNormalizedPath()
{
// Arrange
var validPath = Path.Combine(_testDirectory, "test.txt");
// Act
var result = SecurityValidator.ValidateAndNormalizePath(validPath, _testConfig);
// Assert
Assert.AreEqual(Path.GetFullPath(validPath), result);
}
[TestMethod]
public void ValidateAndNormalizePath_ValidSubdirectoryPath_ReturnsNormalizedPath()
{
// Arrange
var validPath = Path.Combine(_testDirectory, "subdir", "test.txt");
// Act
var result = SecurityValidator.ValidateAndNormalizePath(validPath, _testConfig);
// Assert
Assert.AreEqual(Path.GetFullPath(validPath), result);
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateAndNormalizePath_PathTraversal_ThrowsException()
{
// Arrange
var maliciousPath = Path.Combine(_testDirectory, "..", "..", "etc", "passwd");
// Act
SecurityValidator.ValidateAndNormalizePath(maliciousPath, _testConfig);
// Assert - Exception expected
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateAndNormalizePath_OutsideAllowedDirectory_ThrowsException()
{
// Arrange
var outsidePath = Path.Combine(Path.GetTempPath(), "outside.txt");
// Act
SecurityValidator.ValidateAndNormalizePath(outsidePath, _testConfig);
// Assert - Exception expected
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateAndNormalizePath_DisallowedExtension_ThrowsException()
{
// Arrange
var disallowedPath = Path.Combine(_testDirectory, "test.exe");
// Act
SecurityValidator.ValidateAndNormalizePath(disallowedPath, _testConfig);
// Assert - Exception expected
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ValidateAndNormalizePath_UnsafeCharacters_ThrowsException()
{
// Arrange
var unsafePath = Path.Combine(_testDirectory, "test<>.txt");
// Act
SecurityValidator.ValidateAndNormalizePath(unsafePath, _testConfig);
// Assert - Exception expected
}
[TestMethod]
public void ValidateContentSize_ValidSize_DoesNotThrow()
{
// Arrange
var content = "This is a test content";
// Act & Assert
SecurityValidator.ValidateContentSize(content, _testConfig);
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateContentSize_TooLarge_ThrowsException()
{
long size = _testConfig.MaxFileSizeBytes + 1;
if (size > int.MaxValue)
throw new InvalidOperationException("Requested string size exceeds maximum allowed length.");
var largeContent = new string('A', (int)size);
// Act
SecurityValidator.ValidateContentSize(largeContent, _testConfig);
// Assert - Exception expected
}
[TestMethod]
public void ValidateUrl_ValidHttpsUrl_ReturnsUri()
{
// Arrange
var validUrl = "https://example.com/api/test";
// Act
var result = SecurityValidator.ValidateUrl(validUrl, _testConfig);
// Assert
Assert.AreEqual("https", result.Scheme);
Assert.AreEqual("example.com", result.Host);
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateUrl_HttpScheme_ThrowsException()
{
// Arrange
var httpUrl = "http://example.com/api/test";
// Act
SecurityValidator.ValidateUrl(httpUrl, _testConfig);
// Assert - Exception expected
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateUrl_LocalhostUrl_ThrowsException()
{
// Arrange
var localhostUrl = "https://localhost:8080/api/test";
// Act
SecurityValidator.ValidateUrl(localhostUrl, _testConfig);
// Assert - Exception expected
}
[TestMethod]
[ExpectedException(typeof(UnauthorizedAccessException))]
public void ValidateUrl_PrivateIpUrl_ThrowsException()
{
// Arrange
var privateIpUrl = "https://192.168.1.1/api/test";
// Act
SecurityValidator.ValidateUrl(privateIpUrl, _testConfig);
// Assert - Exception expected
}
[TestMethod]
public void SanitizeInput_ValidInput_ReturnsInput()
{
// Arrange
var validInput = "This is a normal string";
// Act
var result = SecurityValidator.SanitizeInput(validInput);
// Assert
Assert.AreEqual(validInput, result);
}
[TestMethod]
public void SanitizeInput_ControlCharacters_RemovesControlCharacters()
{
// Arrange
var inputWithControlChars = "Test\x00\x01string\x1F";
// Act
var result = SecurityValidator.SanitizeInput(inputWithControlChars);
// Assert
Assert.AreEqual("Teststring", result);
}
[TestMethod]
public void CreateSecureBackupPath_ValidPath_ReturnsSecurePath()
{
// Arrange
var originalPath = Path.Combine(_testDirectory, "test.txt");
// Act
var backupPath = SecurityValidator.CreateSecureBackupPath(originalPath);
// Assert
Assert.IsTrue(backupPath.StartsWith(_testDirectory));
Assert.IsTrue(backupPath.Contains("test_"));
Assert.IsTrue(backupPath.EndsWith(".bak.txt"));
}
}
}