SEBWIN-296: Implemented unit tests for binary serializer.

This commit is contained in:
dbuechel 2019-02-20 08:47:30 +01:00
parent f86615c77d
commit 817d9eaefc
4 changed files with 156 additions and 26 deletions

View file

@ -6,17 +6,148 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Configuration.DataFormats;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration.DataCompression;
using SafeExamBrowser.Contracts.Configuration.DataFormats;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
{
[TestClass]
public class BinarySerializerTests
{
private Mock<IDataCompressor> compressor;
private Mock<ILogger> logger;
private Mock<IPasswordEncryption> passwordEncryption;
private Mock<IPublicKeyEncryption> publicKeyEncryption;
private Mock<IPublicKeyEncryption> symmetricEncryption;
private Mock<IDataSerializer> xmlSerializer;
private SerializeResult xmlResult;
private BinarySerializer sut;
[TestInitialize]
public void Initialize()
{
compressor = new Mock<IDataCompressor>();
logger = new Mock<ILogger>();
passwordEncryption = new Mock<IPasswordEncryption>();
publicKeyEncryption = new Mock<IPublicKeyEncryption>();
symmetricEncryption = new Mock<IPublicKeyEncryption>();
xmlResult = new SerializeResult { Data = new MemoryStream(), Status = SaveStatus.Success };
xmlSerializer = new Mock<IDataSerializer>();
compressor.Setup(c => c.Compress(It.IsAny<Stream>())).Returns(new MemoryStream());
xmlSerializer.Setup(x => x.TrySerialize(It.IsAny<IDictionary<string, object>>(), It.IsAny<EncryptionParameters>())).Returns(xmlResult);
sut = new BinarySerializer(compressor.Object, logger.Object, passwordEncryption.Object, publicKeyEncryption.Object, symmetricEncryption.Object, xmlSerializer.Object);
}
[TestMethod]
public void MustOnlySupportBinaryFormat()
{
var values = Enum.GetValues(typeof(FormatType));
foreach (var value in values)
{
if (value is FormatType format && format != FormatType.Binary)
{
Assert.IsFalse(sut.CanSerialize(format));
}
}
Assert.IsTrue(sut.CanSerialize(FormatType.Binary));
}
[TestMethod]
public void MustCorrectlySerializePlainDataBlock()
{
var data = new Dictionary<string, object>();
var result = sut.TrySerialize(data);
compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2));
xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once);
passwordEncryption.VerifyNoOtherCalls();
publicKeyEncryption.VerifyNoOtherCalls();
symmetricEncryption.VerifyNoOtherCalls();
Assert.AreEqual(SaveStatus.Success, result.Status);
}
[TestMethod]
public void MustCorrectlySerializePasswordBlock()
{
var encrypted = new MemoryStream() as Stream;
var data = new Dictionary<string, object>();
var encryption = new PasswordParameters { Password = "blubb" };
passwordEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<string>(), out encrypted)).Returns(SaveStatus.Success);
var result = sut.TrySerialize(data, encryption);
compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2));
passwordEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.Is<string>(s => s == encryption.Password), out encrypted), Times.Once);
xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once);
publicKeyEncryption.VerifyNoOtherCalls();
symmetricEncryption.VerifyNoOtherCalls();
Assert.AreEqual(SaveStatus.Success, result.Status);
}
[TestMethod]
public void MustCorrectlySerializePublicKeyBlock()
{
var encrypted = new MemoryStream() as Stream;
var data = new Dictionary<string, object>();
var encryption = new PublicKeyParameters
{
InnerEncryption = new PasswordParameters { Password = "test" },
SymmetricEncryption = false
};
passwordEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<string>(), out encrypted)).Returns(SaveStatus.Success);
publicKeyEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted)).Returns(SaveStatus.Success);
var result = sut.TrySerialize(data, encryption);
compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2));
passwordEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.Is<string>(s => s == encryption.InnerEncryption.Password), out encrypted), Times.Once);
publicKeyEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted), Times.Once);
xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once);
symmetricEncryption.VerifyNoOtherCalls();
Assert.AreEqual(SaveStatus.Success, result.Status);
}
[TestMethod]
public void MustCorrectlySerializePublicKeySymmetricBlock()
{
var encrypted = new MemoryStream() as Stream;
var data = new Dictionary<string, object>();
var encryption = new PublicKeyParameters
{
SymmetricEncryption = true
};
symmetricEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted)).Returns(SaveStatus.Success);
var result = sut.TrySerialize(data, encryption);
compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2));
symmetricEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted), Times.Once);
xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once);
passwordEncryption.VerifyNoOtherCalls();
publicKeyEncryption.VerifyNoOtherCalls();
Assert.AreEqual(SaveStatus.Success, result.Status);
}
}
}

View file

@ -181,19 +181,19 @@ namespace SafeExamBrowser.Configuration.DataFormats
private string ReadPrefix(Stream data)
{
var prefixData = new byte[PREFIX_LENGTH];
var prefix = new byte[PREFIX_LENGTH];
if (compressor.IsCompressed(data))
{
prefixData = compressor.Peek(data, PREFIX_LENGTH);
prefix = compressor.Peek(data, PREFIX_LENGTH);
}
else
{
data.Seek(0, SeekOrigin.Begin);
data.Read(prefixData, 0, PREFIX_LENGTH);
data.Read(prefix, 0, PREFIX_LENGTH);
}
return Encoding.UTF8.GetString(prefixData);
return Encoding.UTF8.GetString(prefix);
}
private bool IsValid(string prefix)

View file

@ -9,7 +9,6 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SafeExamBrowser.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration.DataCompression;
@ -21,12 +20,26 @@ namespace SafeExamBrowser.Configuration.DataFormats
public class BinarySerializer : IDataSerializer
{
private IDataCompressor compressor;
private IModuleLogger logger;
private ILogger logger;
private IPasswordEncryption passwordEncryption;
private IPublicKeyEncryption publicKeyEncryption;
private IPublicKeyEncryption symmetricEncryption;
private IDataSerializer xmlSerializer;
public BinarySerializer(IDataCompressor compressor, IModuleLogger logger)
public BinarySerializer(
IDataCompressor compressor,
ILogger logger,
IPasswordEncryption passwordEncryption,
IPublicKeyEncryption publicKeyEncryption,
IPublicKeyEncryption symmetricEncryption,
IDataSerializer xmlSerializer)
{
this.compressor = compressor;
this.logger = logger;
this.passwordEncryption = passwordEncryption;
this.publicKeyEncryption = publicKeyEncryption;
this.symmetricEncryption = symmetricEncryption;
this.xmlSerializer = xmlSerializer;
}
public bool CanSerialize(FormatType format)
@ -65,12 +78,11 @@ namespace SafeExamBrowser.Configuration.DataFormats
if (result.Status == SaveStatus.Success)
{
var encryption = new PasswordEncryption(logger.CloneFor(nameof(PasswordEncryption)));
var prefix = password.IsHash ? BinaryBlock.PasswordConfigureClient : BinaryBlock.Password;
logger.Debug("Attempting to serialize password block...");
var status = encryption.Encrypt(result.Data, password.Password, out var encrypted);
var status = passwordEncryption.Encrypt(result.Data, password.Password, out var encrypted);
if (status == SaveStatus.Success)
{
@ -87,7 +99,6 @@ namespace SafeExamBrowser.Configuration.DataFormats
{
logger.Debug("Attempting to serialize plain data block...");
var xmlSerializer = new XmlSerializer(logger.CloneFor(nameof(XmlSerializer)));
var result = xmlSerializer.TrySerialize(data);
if (result.Status == SaveStatus.Success)
@ -109,7 +120,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
if (result.Status == SaveStatus.Success)
{
var encryption = DetermineEncryptionForPublicKeyHashBlock(parameters);
var encryption = parameters.SymmetricEncryption ? symmetricEncryption : publicKeyEncryption;
var prefix = parameters.SymmetricEncryption ? BinaryBlock.PublicKeySymmetric : BinaryBlock.PublicKey;
logger.Debug("Attempting to serialize public key hash block...");
@ -135,18 +146,6 @@ namespace SafeExamBrowser.Configuration.DataFormats
return SerializePlainDataBlock(data, true);
}
private PublicKeyEncryption DetermineEncryptionForPublicKeyHashBlock(PublicKeyParameters parameters)
{
var passwordEncryption = new PasswordEncryption(logger.CloneFor(nameof(PasswordEncryption)));
if (parameters.SymmetricEncryption)
{
return new PublicKeySymmetricEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeySymmetricEncryption)), passwordEncryption);
}
return new PublicKeyEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyEncryption)));
}
private Stream WritePrefix(string prefix, Stream data)
{
var prefixBytes = Encoding.UTF8.GetBytes(prefix);

View file

@ -119,16 +119,16 @@ namespace SafeExamBrowser.Runtime
var compressor = new GZipCompressor(ModuleLogger(nameof(GZipCompressor)));
var passwordEncryption = new PasswordEncryption(ModuleLogger(nameof(PasswordEncryption)));
var publicKeyEncryption = new PublicKeyEncryption(new CertificateStore(), ModuleLogger(nameof(PublicKeyEncryption)));
var symmetricInnerEncryption = new PasswordEncryption(ModuleLogger(nameof(PasswordEncryption)));
var symmetricEncryption = new PublicKeySymmetricEncryption(new CertificateStore(), ModuleLogger(nameof(PublicKeySymmetricEncryption)), symmetricInnerEncryption);
var symmetricEncryption = new PublicKeySymmetricEncryption(new CertificateStore(), ModuleLogger(nameof(PublicKeySymmetricEncryption)), passwordEncryption);
var repositoryLogger = ModuleLogger(nameof(ConfigurationRepository));
var xmlParser = new XmlParser(ModuleLogger(nameof(XmlParser)));
var xmlSerializer = new XmlSerializer(ModuleLogger(nameof(XmlSerializer)));
configuration = new ConfigurationRepository(new HashAlgorithm(), repositoryLogger, executable.Location, programCopyright, programTitle, programVersion);
appConfig = configuration.InitializeAppConfig();
configuration.Register(new BinaryParser(compressor, new HashAlgorithm(), ModuleLogger(nameof(BinaryParser)), passwordEncryption, publicKeyEncryption, symmetricEncryption, xmlParser));
configuration.Register(new BinarySerializer(compressor, ModuleLogger(nameof(BinarySerializer))));
configuration.Register(new BinarySerializer(compressor, ModuleLogger(nameof(BinarySerializer)), passwordEncryption, publicKeyEncryption, symmetricEncryption, xmlSerializer));
configuration.Register(new XmlParser(ModuleLogger(nameof(XmlParser))));
configuration.Register(new XmlSerializer(ModuleLogger(nameof(XmlSerializer))));
configuration.Register(new FileResourceLoader(ModuleLogger(nameof(FileResourceLoader))));