DataProtectionExtensionsTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Copyright (c) .NET Foundation. All rights reserved.
  2. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using Microsoft.AspNetCore.DataProtection.Infrastructure;
  8. using Microsoft.AspNetCore.DataProtection.Abstractions;
  9. using Microsoft.AspNetCore.Testing;
  10. using Microsoft.Extensions.PlatformAbstractions;
  11. using Moq;
  12. using Xunit;
  13. namespace Microsoft.AspNetCore.DataProtection
  14. {
  15. public class DataProtectionExtensionsTests
  16. {
  17. [Theory]
  18. [InlineData(new object[] { new string[0] })]
  19. [InlineData(new object[] { new string[] { null } })]
  20. [InlineData(new object[] { new string[] { "the next value is bad", null } })]
  21. public void CreateProtector_ChainedAsIEnumerable_FailureCases(string[] purposes)
  22. {
  23. // Arrange
  24. var mockProtector = new Mock<IDataProtector>();
  25. mockProtector.Setup(o => o.CreateProtector(It.IsAny<string>())).Returns(mockProtector.Object);
  26. var provider = mockProtector.Object;
  27. // Act & assert
  28. ExceptionAssert.ThrowsArgument(
  29. testCode: () => provider.CreateProtector((IEnumerable<string>)purposes),
  30. paramName: "purposes",
  31. exceptionMessage: Resources.DataProtectionExtensions_NullPurposesCollection);
  32. }
  33. [Theory]
  34. [InlineData(new object[] { new string[] { null } })]
  35. [InlineData(new object[] { new string[] { "the next value is bad", null } })]
  36. public void CreateProtector_ChainedAsParams_FailureCases(string[] subPurposes)
  37. {
  38. // Arrange
  39. var mockProtector = new Mock<IDataProtector>();
  40. mockProtector.Setup(o => o.CreateProtector(It.IsAny<string>())).Returns(mockProtector.Object);
  41. var provider = mockProtector.Object;
  42. // Act & assert
  43. ExceptionAssert.ThrowsArgument(
  44. testCode: () => provider.CreateProtector("primary-purpose", subPurposes),
  45. paramName: "purposes",
  46. exceptionMessage: Resources.DataProtectionExtensions_NullPurposesCollection);
  47. }
  48. [Fact]
  49. public void CreateProtector_ChainedAsIEnumerable_SuccessCase()
  50. {
  51. // Arrange
  52. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  53. var thirdMock = new Mock<IDataProtector>();
  54. thirdMock.Setup(o => o.CreateProtector("third")).Returns(finalExpectedProtector);
  55. var secondMock = new Mock<IDataProtector>();
  56. secondMock.Setup(o => o.CreateProtector("second")).Returns(thirdMock.Object);
  57. var firstMock = new Mock<IDataProtector>();
  58. firstMock.Setup(o => o.CreateProtector("first")).Returns(secondMock.Object);
  59. // Act
  60. var retVal = firstMock.Object.CreateProtector((IEnumerable<string>)new string[] { "first", "second", "third" });
  61. // Assert
  62. Assert.Same(finalExpectedProtector, retVal);
  63. }
  64. [Fact]
  65. public void CreateProtector_ChainedAsParams_NonEmptyParams_SuccessCase()
  66. {
  67. // Arrange
  68. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  69. var thirdMock = new Mock<IDataProtector>();
  70. thirdMock.Setup(o => o.CreateProtector("third")).Returns(finalExpectedProtector);
  71. var secondMock = new Mock<IDataProtector>();
  72. secondMock.Setup(o => o.CreateProtector("second")).Returns(thirdMock.Object);
  73. var firstMock = new Mock<IDataProtector>();
  74. firstMock.Setup(o => o.CreateProtector("first")).Returns(secondMock.Object);
  75. // Act
  76. var retVal = firstMock.Object.CreateProtector("first", "second", "third");
  77. // Assert
  78. Assert.Same(finalExpectedProtector, retVal);
  79. }
  80. [Theory]
  81. [InlineData(new object[] { null })]
  82. [InlineData(new object[] { new string[0] })]
  83. public void CreateProtector_ChainedAsParams_EmptyParams_SuccessCases(string[] subPurposes)
  84. {
  85. // Arrange
  86. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  87. var firstMock = new Mock<IDataProtector>();
  88. firstMock.Setup(o => o.CreateProtector("first")).Returns(finalExpectedProtector);
  89. // Act
  90. var retVal = firstMock.Object.CreateProtector("first", subPurposes);
  91. // Assert
  92. Assert.Same(finalExpectedProtector, retVal);
  93. }
  94. [Theory]
  95. [InlineData(" discriminator", "app-path ", "discriminator")] // normalized trim
  96. [InlineData("", "app-path", null)] // app discriminator not null -> overrides app base path
  97. [InlineData(null, "app-path ", "app-path")] // normalized trim
  98. [InlineData(null, " ", null)] // normalized whitespace -> null
  99. [InlineData(null, null, null)] // nothing provided at all
  100. public void GetApplicationUniqueIdentifier(string appDiscriminator, string appBasePath, string expected)
  101. {
  102. // Arrange
  103. var mockAppDiscriminator = new Mock<IApplicationDiscriminator>();
  104. mockAppDiscriminator.Setup(o => o.Discriminator).Returns(appDiscriminator);
  105. var mockAppEnvironment = new Mock<IApplicationEnvironment>();
  106. mockAppEnvironment.Setup(o => o.ApplicationBasePath).Returns(appBasePath);
  107. var mockServiceProvider = new Mock<IServiceProvider>();
  108. mockServiceProvider.Setup(o => o.GetService(typeof(IApplicationDiscriminator))).Returns(mockAppDiscriminator.Object);
  109. mockServiceProvider.Setup(o => o.GetService(typeof(IApplicationEnvironment))).Returns(mockAppEnvironment.Object);
  110. // Act
  111. string actual = mockServiceProvider.Object.GetApplicationUniqueIdentifier();
  112. // Assert
  113. Assert.Equal(expected, actual);
  114. }
  115. [Fact]
  116. public void GetApplicationUniqueIdentifier_NoServiceProvider_ReturnsNull()
  117. {
  118. Assert.Null(((IServiceProvider)null).GetApplicationUniqueIdentifier());
  119. }
  120. [Fact]
  121. public void GetDataProtectionProvider_NoServiceFound_Throws()
  122. {
  123. // Arrange
  124. var services = new Mock<IServiceProvider>().Object;
  125. // Act & assert
  126. var ex = Assert.Throws<InvalidOperationException>(() => services.GetDataProtectionProvider());
  127. Assert.Equal(Resources.FormatDataProtectionExtensions_NoService(typeof(IDataProtectionProvider).FullName), ex.Message);
  128. }
  129. [Fact]
  130. public void GetDataProtectionProvider_ServiceFound_ReturnsService()
  131. {
  132. // Arrange
  133. var expected = new Mock<IDataProtectionProvider>().Object;
  134. var mockServices = new Mock<IServiceProvider>();
  135. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(expected);
  136. var services = mockServices.Object;
  137. // Act
  138. var actual = services.GetDataProtectionProvider();
  139. // Assert
  140. Assert.Same(expected, actual);
  141. }
  142. [Theory]
  143. [InlineData(new object[] { new string[0] })]
  144. [InlineData(new object[] { new string[] { null } })]
  145. [InlineData(new object[] { new string[] { "the next value is bad", null } })]
  146. public void GetDataProtector_ChainedAsIEnumerable_FailureCases(string[] purposes)
  147. {
  148. // Arrange
  149. var mockProtector = new Mock<IDataProtector>();
  150. mockProtector.Setup(o => o.CreateProtector(It.IsAny<string>())).Returns(mockProtector.Object);
  151. var mockServices = new Mock<IServiceProvider>();
  152. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(mockProtector.Object);
  153. var services = mockServices.Object;
  154. // Act & assert
  155. ExceptionAssert.ThrowsArgument(
  156. testCode: () => services.GetDataProtector((IEnumerable<string>)purposes),
  157. paramName: "purposes",
  158. exceptionMessage: Resources.DataProtectionExtensions_NullPurposesCollection);
  159. }
  160. [Theory]
  161. [InlineData(new object[] { new string[] { null } })]
  162. [InlineData(new object[] { new string[] { "the next value is bad", null } })]
  163. public void GetDataProtector_ChainedAsParams_FailureCases(string[] subPurposes)
  164. {
  165. // Arrange
  166. var mockProtector = new Mock<IDataProtector>();
  167. mockProtector.Setup(o => o.CreateProtector(It.IsAny<string>())).Returns(mockProtector.Object);
  168. var mockServices = new Mock<IServiceProvider>();
  169. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(mockProtector.Object);
  170. var services = mockServices.Object;
  171. // Act & assert
  172. ExceptionAssert.ThrowsArgument(
  173. testCode: () => services.GetDataProtector("primary-purpose", subPurposes),
  174. paramName: "purposes",
  175. exceptionMessage: Resources.DataProtectionExtensions_NullPurposesCollection);
  176. }
  177. [Fact]
  178. public void GetDataProtector_ChainedAsIEnumerable_SuccessCase()
  179. {
  180. // Arrange
  181. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  182. var thirdMock = new Mock<IDataProtector>();
  183. thirdMock.Setup(o => o.CreateProtector("third")).Returns(finalExpectedProtector);
  184. var secondMock = new Mock<IDataProtector>();
  185. secondMock.Setup(o => o.CreateProtector("second")).Returns(thirdMock.Object);
  186. var firstMock = new Mock<IDataProtector>();
  187. firstMock.Setup(o => o.CreateProtector("first")).Returns(secondMock.Object);
  188. var mockServices = new Mock<IServiceProvider>();
  189. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(firstMock.Object);
  190. var services = mockServices.Object;
  191. // Act
  192. var retVal = services.GetDataProtector((IEnumerable<string>)new string[] { "first", "second", "third" });
  193. // Assert
  194. Assert.Same(finalExpectedProtector, retVal);
  195. }
  196. [Fact]
  197. public void GetDataProtector_ChainedAsParams_NonEmptyParams_SuccessCase()
  198. {
  199. // Arrange
  200. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  201. var thirdMock = new Mock<IDataProtector>();
  202. thirdMock.Setup(o => o.CreateProtector("third")).Returns(finalExpectedProtector);
  203. var secondMock = new Mock<IDataProtector>();
  204. secondMock.Setup(o => o.CreateProtector("second")).Returns(thirdMock.Object);
  205. var firstMock = new Mock<IDataProtector>();
  206. firstMock.Setup(o => o.CreateProtector("first")).Returns(secondMock.Object);
  207. var mockServices = new Mock<IServiceProvider>();
  208. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(firstMock.Object);
  209. var services = mockServices.Object;
  210. // Act
  211. var retVal = services.GetDataProtector("first", "second", "third");
  212. // Assert
  213. Assert.Same(finalExpectedProtector, retVal);
  214. }
  215. [Theory]
  216. [InlineData(new object[] { null })]
  217. [InlineData(new object[] { new string[0] })]
  218. public void GetDataProtector_ChainedAsParams_EmptyParams_SuccessCases(string[] subPurposes)
  219. {
  220. // Arrange
  221. var finalExpectedProtector = new Mock<IDataProtector>().Object;
  222. var firstMock = new Mock<IDataProtector>();
  223. firstMock.Setup(o => o.CreateProtector("first")).Returns(finalExpectedProtector);
  224. var mockServices = new Mock<IServiceProvider>();
  225. mockServices.Setup(o => o.GetService(typeof(IDataProtectionProvider))).Returns(firstMock.Object);
  226. var services = mockServices.Object;
  227. // Act
  228. var retVal = services.GetDataProtector("first", subPurposes);
  229. // Assert
  230. Assert.Same(finalExpectedProtector, retVal);
  231. }
  232. [Fact]
  233. public void Protect_InvalidUtf8_Failure()
  234. {
  235. // Arrange
  236. Mock<IDataProtector> mockProtector = new Mock<IDataProtector>();
  237. // Act & assert
  238. var ex = Assert.Throws<CryptographicException>(() =>
  239. {
  240. mockProtector.Object.Protect("Hello\ud800");
  241. });
  242. Assert.IsAssignableFrom(typeof(EncoderFallbackException), ex.InnerException);
  243. }
  244. [Fact]
  245. public void Protect_Success()
  246. {
  247. // Arrange
  248. Mock<IDataProtector> mockProtector = new Mock<IDataProtector>();
  249. mockProtector.Setup(p => p.Protect(new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f })).Returns(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 });
  250. // Act
  251. string retVal = mockProtector.Object.Protect("Hello");
  252. // Assert
  253. Assert.Equal("AQIDBAU", retVal);
  254. }
  255. [Fact]
  256. public void Unprotect_InvalidBase64BeforeDecryption_Failure()
  257. {
  258. // Arrange
  259. Mock<IDataProtector> mockProtector = new Mock<IDataProtector>();
  260. // Act & assert
  261. var ex = Assert.Throws<CryptographicException>(() =>
  262. {
  263. mockProtector.Object.Unprotect("A");
  264. });
  265. }
  266. [Fact]
  267. public void Unprotect_InvalidUtf8AfterDecryption_Failure()
  268. {
  269. // Arrange
  270. Mock<IDataProtector> mockProtector = new Mock<IDataProtector>();
  271. mockProtector.Setup(p => p.Unprotect(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })).Returns(new byte[] { 0xff });
  272. // Act & assert
  273. var ex = Assert.Throws<CryptographicException>(() =>
  274. {
  275. mockProtector.Object.Unprotect("AQIDBAU");
  276. });
  277. Assert.IsAssignableFrom(typeof(DecoderFallbackException), ex.InnerException);
  278. }
  279. [Fact]
  280. public void Unprotect_Success()
  281. {
  282. // Arrange
  283. Mock<IDataProtector> mockProtector = new Mock<IDataProtector>();
  284. mockProtector.Setup(p => p.Unprotect(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })).Returns(new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f });
  285. // Act
  286. string retVal = DataProtectionExtensions.Unprotect(mockProtector.Object, "AQIDBAU");
  287. // Assert
  288. Assert.Equal("Hello", retVal);
  289. }
  290. }
  291. }