| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- // 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(@"<element />");
- // Act
- var retVal = original.DecryptElement(activator: null);
- // Assert
- Assert.Same(original, retVal);
- XmlAssert.Equal("<element />", original); // unmutated
- }
- [Fact]
- public void DecryptElement_RootNodeRequiresDecryption_Success()
- {
- // Arrange
- var original = XElement.Parse(@"
- <x:encryptedSecret decryptorType='theDecryptor' xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <node />
- </x:encryptedSecret>");
- var mockActivator = new Mock<IActivator>();
- mockActivator.ReturnDecryptedElementGivenDecryptorTypeNameAndInput("theDecryptor", "<node />", "<newNode />");
- var serviceCollection = new ServiceCollection();
- serviceCollection.AddSingleton<IActivator>(mockActivator.Object);
- var services = serviceCollection.BuildServiceProvider();
- var activator = services.GetActivator();
- // Act
- var retVal = original.DecryptElement(activator);
- // Assert
- XmlAssert.Equal("<newNode />", retVal);
- }
- [Fact]
- public void DecryptElement_MultipleNodesRequireDecryption_AvoidsRecursion_Success()
- {
- // Arrange
- var original = XElement.Parse(@"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <x:encryptedSecret decryptorType='myDecryptor'>
- <node1 />
- </x:encryptedSecret>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <x:encryptedSecret decryptorType='myDecryptor'>
- <node3 />
- </x:encryptedSecret>
- </node2>
- </rootNode>");
- var expected = @"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <node1_decrypted>
- <x:encryptedSecret>nested</x:encryptedSecret>
- </node1_decrypted>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <node3_decrypted>
- <x:encryptedSecret>nested</x:encryptedSecret>
- </node3_decrypted>
- </node2>
- </rootNode>";
- var mockDecryptor = new Mock<IXmlDecryptor>();
- mockDecryptor
- .Setup(o => o.Decrypt(It.IsAny<XElement>()))
- .Returns<XElement>(el => new XElement(el.Name.LocalName + "_decrypted", new XElement(XmlConstants.EncryptedSecretElementName, "nested")));
- var mockActivator = new Mock<IActivator>();
- mockActivator.Setup(o => o.CreateInstance(typeof(IXmlDecryptor), "myDecryptor")).Returns(mockDecryptor.Object);
- var serviceCollection = new ServiceCollection();
- serviceCollection.AddSingleton<IActivator>(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(@"<element />");
- var xmlEncryptor = new Mock<IXmlEncryptor>(MockBehavior.Strict).Object;
- // Act
- var retVal = xmlEncryptor.EncryptIfNecessary(original);
- // Assert
- Assert.Null(retVal);
- XmlAssert.Equal("<element />", original); // unmutated
- }
- [Fact]
- public void EncryptIfNecessary_RootNodeRequiresEncryption_Success()
- {
- // Arrange
- var original = XElement.Parse(@"<rootNode x:requiresEncryption='true' xmlns:x='http://schemas.asp.net/2015/03/dataProtection' />");
- var mockXmlEncryptor = new Mock<IXmlEncryptor>();
- mockXmlEncryptor.Setup(o => o.Encrypt(It.IsAny<XElement>())).Returns(new EncryptedXmlInfo(new XElement("theElement"), typeof(MyXmlDecryptor)));
- // Act
- var retVal = mockXmlEncryptor.Object.EncryptIfNecessary(original);
- // Assert
- XmlAssert.Equal(@"<rootNode x:requiresEncryption='true' xmlns:x='http://schemas.asp.net/2015/03/dataProtection' />", original); // unmutated
- Assert.Equal(XmlConstants.EncryptedSecretElementName, retVal.Name);
- Assert.Equal(typeof(MyXmlDecryptor).AssemblyQualifiedName, (string)retVal.Attribute(XmlConstants.DecryptorTypeAttributeName));
- XmlAssert.Equal("<theElement />", retVal.Descendants().Single());
- }
- [Fact]
- public void EncryptIfNecessary_MultipleNodesRequireEncryption_Success()
- {
- // Arrange
- var original = XElement.Parse(@"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <node1 x:requiresEncryption='true'>
- <![CDATA[This data should be encrypted.]]>
- </node1>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <node3 x:requiresEncryption='true'>
- <node4 x:requiresEncryption='true' />
- </node3>
- </node2>
- </rootNode>");
- var expected = string.Format(@"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <x:encryptedSecret decryptorType='{0}'>
- <node1_encrypted />
- </x:encryptedSecret>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <x:encryptedSecret decryptorType='{0}'>
- <node3_encrypted />
- </x:encryptedSecret>
- </node2>
- </rootNode>",
- typeof(MyXmlDecryptor).AssemblyQualifiedName);
- var mockXmlEncryptor = new Mock<IXmlEncryptor>();
- mockXmlEncryptor
- .Setup(o => o.Encrypt(It.IsAny<XElement>()))
- .Returns<XElement>(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(@"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <node1 x:requiresEncryption='true'>
- <![CDATA[This data should be encrypted.]]>
- </node1>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <node3 x:requiresEncryption='true'>
- <node4 x:requiresEncryption='true' />
- </node3>
- </node2>
- </rootNode>");
- var expected = string.Format(@"
- <rootNode xmlns:x='http://schemas.asp.net/2015/03/dataProtection'>
- <x:encryptedSecret decryptorType='{0}'>
- <node1 x:requiresEncryption='true'>
- <![CDATA[This data should be encrypted.]]>
- </node1>
- </x:encryptedSecret>
- <node2 x:requiresEncryption='false'>
- <![CDATA[This data should stick around.]]>
- <x:encryptedSecret decryptorType='{0}'>
- <node3 x:requiresEncryption='true'>
- <node4 x:requiresEncryption='true' />
- </node3>
- </x:encryptedSecret>
- </node2>
- </rootNode>",
- typeof(MyXmlDecryptor).AssemblyQualifiedName);
- var mockXmlEncryptor = new Mock<IXmlEncryptor>();
- mockXmlEncryptor
- .Setup(o => o.Encrypt(It.IsAny<XElement>()))
- .Returns<XElement>(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();
- }
- }
- }
- }
|