Skip to content

Commit adf7c0a

Browse files
authored
Uses Fallback When Without Repository (#48103)
1 parent c55ee62 commit adf7c0a

File tree

4 files changed

+64
-44
lines changed

4 files changed

+64
-44
lines changed

src/DataProtection/DataProtection/src/KeyManagement/XmlKeyManager.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,10 @@ internal XmlKeyManager(
9696
var keyEncryptor = keyManagementOptions.Value.XmlEncryptor;
9797
if (keyRepository == null)
9898
{
99-
if (keyEncryptor != null)
99+
var keyRepositoryEncryptorPair = GetFallbackKeyRepositoryEncryptorPair();
100+
keyRepository = keyRepositoryEncryptorPair.Key;
101+
if (keyEncryptor == null)
100102
{
101-
throw new InvalidOperationException(
102-
Resources.FormatXmlKeyManager_IXmlRepositoryNotFound(nameof(IXmlRepository), nameof(IXmlEncryptor)));
103-
}
104-
else
105-
{
106-
var keyRepositoryEncryptorPair = GetFallbackKeyRepositoryEncryptorPair();
107-
keyRepository = keyRepositoryEncryptorPair.Key;
108103
keyEncryptor = keyRepositoryEncryptorPair.Value;
109104
}
110105
}

src/DataProtection/DataProtection/src/Resources.resx

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3-
<!--
4-
Microsoft ResX Schema
5-
3+
<!--
4+
Microsoft ResX Schema
5+
66
Version 2.0
7-
8-
The primary goals of this format is to allow a simple XML format
9-
that is mostly human readable. The generation and parsing of the
10-
various data types are done through the TypeConverter classes
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
1111
associated with the data types.
12-
12+
1313
Example:
14-
14+
1515
... ado.net/XML headers & schema ...
1616
<resheader name="resmimetype">text/microsoft-resx</resheader>
1717
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
2626
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
2727
<comment>This is a comment</comment>
2828
</data>
29-
30-
There are any number of "resheader" rows that contain simple
29+
30+
There are any number of "resheader" rows that contain simple
3131
name/value pairs.
32-
33-
Each data row contains a name, and value. The row also contains a
34-
type or mimetype. Type corresponds to a .NET class that support
35-
text/value conversion through the TypeConverter architecture.
36-
Classes that don't support this are serialized and stored with the
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
3737
mimetype set.
38-
39-
The mimetype is used for serialized objects, and tells the
40-
ResXResourceReader how to depersist the object. This is currently not
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
4141
extensible. For a given mimetype the value must be set accordingly:
42-
43-
Note - application/x-microsoft.net.object.binary.base64 is the format
44-
that the ResXResourceWriter will generate, however the reader can
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
4545
read any of the formats listed below.
46-
46+
4747
mimetype: application/x-microsoft.net.object.binary.base64
48-
value : The object must be serialized with
48+
value : The object must be serialized with
4949
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
5050
: and then encoded with base64 encoding.
51-
51+
5252
mimetype: application/x-microsoft.net.object.soap.base64
53-
value : The object must be serialized with
53+
value : The object must be serialized with
5454
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
5555
: and then encoded with base64 encoding.
5656
5757
mimetype: application/x-microsoft.net.object.bytearray.base64
58-
value : The object must be serialized into a byte array
58+
value : The object must be serialized into a byte array
5959
: using a System.ComponentModel.TypeConverter
6060
: and then encoded with base64 encoding.
6161
-->
@@ -189,9 +189,6 @@
189189
<data name="LifetimeMustNotBeNegative" xml:space="preserve">
190190
<value>{0} must not be negative. For more information go to http://aka.ms/dataprotectionwarning</value>
191191
</data>
192-
<data name="XmlKeyManager_IXmlRepositoryNotFound" xml:space="preserve">
193-
<value>The '{0}' instance could not be found. When an '{1}' instance is set, a corresponding '{0}' instance must also be set. For more information go to http://aka.ms/dataprotectionwarning</value>
194-
</data>
195192
<data name="FileSystem_EphemeralKeysLocationInContainer" xml:space="preserve">
196193
<value>Storing keys in a directory '{path}' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to http://aka.ms/dataprotectionwarning</value>
197194
</data>

src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests/KeyManagement/XmlKeyManagerTests.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,24 @@ public void Ctor_WithoutEncryptorOrRepository_UsesFallback()
5151
}
5252

5353
[Fact]
54-
public void Ctor_WithEncryptorButNoRepository_IgnoresFallback_FailsWithServiceNotFound()
54+
public void Ctor_WithEncryptorButNoRepository_UsesFallback()
5555
{
5656
// Arrange
57+
var expectedXmlEncryptor = new Mock<IXmlEncryptor>().Object;
5758
var options = Options.Create(new KeyManagementOptions()
5859
{
5960
AuthenticatedEncryptorConfiguration = new Mock<AlgorithmConfiguration>().Object,
6061
XmlRepository = null,
61-
XmlEncryptor = new Mock<IXmlEncryptor>().Object
62+
XmlEncryptor = expectedXmlEncryptor
6263
});
6364

64-
// Act & assert - we don't care about exception type, only exception message
65-
Exception ex = Assert.ThrowsAny<Exception>(
66-
() => new XmlKeyManager(options, SimpleActivator.DefaultWithoutServices, NullLoggerFactory.Instance));
67-
Assert.Contains("IXmlRepository", ex.Message);
65+
// Act
66+
var keyManager = new XmlKeyManager(options, SimpleActivator.DefaultWithoutServices, NullLoggerFactory.Instance);
67+
68+
// Assert
69+
Assert.NotNull(keyManager.KeyRepository);
70+
71+
Assert.Same(expectedXmlEncryptor, keyManager.KeyEncryptor);
6872
}
6973

7074
[Fact]

src/DataProtection/Extensions/test/DataProtectionProviderTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,30 @@ public void System_UsesInMemoryCertificate()
239239
});
240240
}
241241

242+
[Fact]
243+
public void System_UsesCertificate()
244+
{
245+
var filePath = Path.Combine(GetTestFilesPath(), "TestCert2.pfx");
246+
var certificate = new X509Certificate2(filePath, "password");
247+
248+
AssetStoreDoesNotContain(certificate);
249+
250+
WithUniqueTempDirectory(directory =>
251+
{
252+
// Step 1: directory should be completely empty
253+
directory.Create();
254+
Assert.Empty(directory.GetFiles());
255+
256+
// Step 2: instantiate the system and round-trip a payload
257+
var protector = DataProtectionProvider.Create("Test", certificate).CreateProtector("purpose");
258+
Assert.Equal("payload",
259+
protector.Unprotect(protector.Protect("payload")));
260+
261+
// Step 3: validate that there's no key in the directory
262+
Assert.Empty(directory.GetFiles());
263+
});
264+
}
265+
242266
private static void AssetStoreDoesNotContain(X509Certificate2 certificate)
243267
{
244268
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))

0 commit comments

Comments
 (0)