// 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(); } } } }