// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection.Internal;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.DataProtection.XmlEncryption
{
public class XmlEncryptionExtensionsTests
{
[Fact]
public void DecryptElement_NothingToDecrypt_ReturnsOriginalElement()
{
// Arrange
var original = XElement.Parse(@"");
// Act
var retVal = original.DecryptElement(activator: null);
// Assert
Assert.Same(original, retVal);
XmlAssert.Equal("", original); // unmutated
}
[Fact]
public void DecryptElement_RootNodeRequiresDecryption_Success()
{
// Arrange
var original = XElement.Parse(@"
");
var mockActivator = new Mock();
mockActivator.ReturnDecryptedElementGivenDecryptorTypeNameAndInput("theDecryptor", "", "");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(mockActivator.Object);
var services = serviceCollection.BuildServiceProvider();
var activator = services.GetActivator();
// Act
var retVal = original.DecryptElement(activator);
// Assert
XmlAssert.Equal("", retVal);
}
[Fact]
public void DecryptElement_MultipleNodesRequireDecryption_AvoidsRecursion_Success()
{
// Arrange
var original = XElement.Parse(@"
");
var expected = @"
nested
nested
";
var mockDecryptor = new Mock();
mockDecryptor
.Setup(o => o.Decrypt(It.IsAny()))
.Returns(el => new XElement(el.Name.LocalName + "_decrypted", new XElement(XmlConstants.EncryptedSecretElementName, "nested")));
var mockActivator = new Mock();
mockActivator.Setup(o => o.CreateInstance(typeof(IXmlDecryptor), "myDecryptor")).Returns(mockDecryptor.Object);
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(mockActivator.Object);
var services = serviceCollection.BuildServiceProvider();
var activator = services.GetActivator();
// Act
var retVal = original.DecryptElement(activator);
// Assert
XmlAssert.Equal(expected, retVal);
}
[Fact]
public void EncryptIfNecessary_NothingToEncrypt_ReturnsNull()
{
// Arrange
var original = XElement.Parse(@"");
var xmlEncryptor = new Mock(MockBehavior.Strict).Object;
// Act
var retVal = xmlEncryptor.EncryptIfNecessary(original);
// Assert
Assert.Null(retVal);
XmlAssert.Equal("", original); // unmutated
}
[Fact]
public void EncryptIfNecessary_RootNodeRequiresEncryption_Success()
{
// Arrange
var original = XElement.Parse(@"");
var mockXmlEncryptor = new Mock();
mockXmlEncryptor.Setup(o => o.Encrypt(It.IsAny())).Returns(new EncryptedXmlInfo(new XElement("theElement"), typeof(MyXmlDecryptor)));
// Act
var retVal = mockXmlEncryptor.Object.EncryptIfNecessary(original);
// Assert
XmlAssert.Equal(@"", original); // unmutated
Assert.Equal(XmlConstants.EncryptedSecretElementName, retVal.Name);
Assert.Equal(typeof(MyXmlDecryptor).AssemblyQualifiedName, (string)retVal.Attribute(XmlConstants.DecryptorTypeAttributeName));
XmlAssert.Equal("", retVal.Descendants().Single());
}
[Fact]
public void EncryptIfNecessary_MultipleNodesRequireEncryption_Success()
{
// Arrange
var original = XElement.Parse(@"
");
var expected = String.Format(@"
",
typeof(MyXmlDecryptor).AssemblyQualifiedName);
var mockXmlEncryptor = new Mock();
mockXmlEncryptor
.Setup(o => o.Encrypt(It.IsAny()))
.Returns(element => new EncryptedXmlInfo(new XElement(element.Name.LocalName + "_encrypted"), typeof(MyXmlDecryptor)));
// Act
var retVal = mockXmlEncryptor.Object.EncryptIfNecessary(original);
// Assert
XmlAssert.Equal(expected, retVal);
}
[Fact]
public void EncryptIfNecessary_NullEncryptorWithRecursion_NoStackDive_Success()
{
// Arrange
var original = XElement.Parse(@"
");
var expected = String.Format(@"
",
typeof(MyXmlDecryptor).AssemblyQualifiedName);
var mockXmlEncryptor = new Mock();
mockXmlEncryptor
.Setup(o => o.Encrypt(It.IsAny()))
.Returns(element => new EncryptedXmlInfo(new XElement(element), typeof(MyXmlDecryptor)));
// Act
var retVal = mockXmlEncryptor.Object.EncryptIfNecessary(original);
// Assert
XmlAssert.Equal(expected, retVal);
}
private sealed class MyXmlDecryptor : IXmlDecryptor
{
public XElement Decrypt(XElement encryptedElement)
{
throw new NotImplementedException();
}
}
}
}