public void GetAllKeys_SwallowsKeyDeserializationErrors()
        {
            // Arrange
            const string xml = @"
                <root>
                  <!-- The below key will throw an exception when deserializing. -->
                  <key id='78cd498e-9375-4e55-ac0d-d79527ecd09d' version='1'>
                    <creationDate>2015-01-01T00:00:00Z</creationDate>
                    <activationDate>2015-02-01T00:00:00Z</activationDate>
                    <expirationDate>NOT A VALID DATE</expirationDate>
                    <descriptor deserializerType='badDeserializer'>
                      <node />
                    </descriptor>
                  </key>
                  <!-- The below key will deserialize properly. -->
                  <key id='49c0cda9-0232-4d8c-a541-de20cc5a73d6' version='1'>
                    <creationDate>2015-01-01T00:00:00Z</creationDate>
                    <activationDate>2015-02-01T00:00:00Z</activationDate>
                    <expirationDate>2015-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='goodDeserializer'>
                      <node xmlns='private' />
                    </descriptor>
                  </key>
                </root>";

            var expectedEncryptor = new Mock<IAuthenticatedEncryptor>().Object;
            var mockActivator = new Mock<IActivator>();
            mockActivator.ReturnAuthenticatedEncryptorGivenDeserializerTypeNameAndInput("goodDeserializer", "<node xmlns='private' />", expectedEncryptor);

            // Act
            var keys = RunGetAllKeysCore(xml, mockActivator.Object).ToArray();

            // Assert
            Assert.Equal(1, keys.Length);
            Assert.Equal(new Guid("49c0cda9-0232-4d8c-a541-de20cc5a73d6"), keys[0].KeyId);
            Assert.Same(expectedEncryptor, keys[0].CreateEncryptorInstance());
        }
        public void GetAllKeys_UnderstandsRevocations()
        {
            // Arrange
            const string xml = @"
                <root>
                  <key id='67f9cdea-83ba-41ed-b160-2b1d0ea30251' version='1'>
                    <creationDate>2015-01-01T00:00:00Z</creationDate>
                    <activationDate>2015-02-01T00:00:00Z</activationDate>
                    <expirationDate>2015-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='theDeserializer'>
                      <node />
                    </descriptor>
                  </key>
                  <key id='0cf83742-d175-42a8-94b5-1ec049b354c3' version='1'>
                    <creationDate>2016-01-01T00:00:00Z</creationDate>
                    <activationDate>2016-02-01T00:00:00Z</activationDate>
                    <expirationDate>2016-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='theDeserializer'>
                      <node />
                    </descriptor>
                  </key>
                  <key id='21580ac4-c83a-493c-bde6-29a1cc97ca0f' version='1'>
                    <creationDate>2017-01-01T00:00:00Z</creationDate>
                    <activationDate>2017-02-01T00:00:00Z</activationDate>
                    <expirationDate>2017-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='theDeserializer'>
                      <node />
                    </descriptor>
                  </key>
                  <key id='6bd14f12-0bb8-4822-91d7-04b360de0497' version='1'>
                    <creationDate>2018-01-01T00:00:00Z</creationDate>
                    <activationDate>2018-02-01T00:00:00Z</activationDate>
                    <expirationDate>2018-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='theDeserializer'>
                      <node />
                    </descriptor>
                  </key>
                  <revocation version='1'>
                    <!-- The below will revoke no keys. -->
                    <revocationDate>2014-01-01T00:00:00Z</revocationDate>
                    <key id='*' />
                  </revocation>
                  <revocation version='1'>
                    <!-- The below will revoke the first two keys. -->
                    <revocationDate>2017-01-01T00:00:00Z</revocationDate>
                    <key id='*' />
                  </revocation>
                  <revocation version='1'>
                    <!-- The below will revoke only the last key. -->
                    <revocationDate>2020-01-01T00:00:00Z</revocationDate>
                    <key id='6bd14f12-0bb8-4822-91d7-04b360de0497' />
                  </revocation>
                </root>";

            var mockActivator = new Mock<IActivator>();
            mockActivator.ReturnAuthenticatedEncryptorGivenDeserializerTypeNameAndInput("theDeserializer", "<node />", new Mock<IAuthenticatedEncryptor>().Object);

            // Act
            var keys = RunGetAllKeysCore(xml, mockActivator.Object).ToArray();

            // Assert
            Assert.Equal(4, keys.Length);
            Assert.Equal(new Guid("67f9cdea-83ba-41ed-b160-2b1d0ea30251"), keys[0].KeyId);
            Assert.True(keys[0].IsRevoked);
            Assert.Equal(new Guid("0cf83742-d175-42a8-94b5-1ec049b354c3"), keys[1].KeyId);
            Assert.True(keys[1].IsRevoked);
            Assert.Equal(new Guid("21580ac4-c83a-493c-bde6-29a1cc97ca0f"), keys[2].KeyId);
            Assert.False(keys[2].IsRevoked);
            Assert.Equal(new Guid("6bd14f12-0bb8-4822-91d7-04b360de0497"), keys[3].KeyId);
            Assert.True(keys[3].IsRevoked);
        }
        public void GetAllKeys_PerformsDecryption()
        {
            // Arrange
            const string xml = @"
                <root xmlns:enc='http://schemas.asp.net/2015/03/dataProtection'>
                  <key id='09712588-ba68-438a-a5ee-fe842b3453b2' version='1'>
                    <creationDate>2015-01-01T00:00:00Z</creationDate>
                    <activationDate>2015-02-01T00:00:00Z</activationDate>
                    <expirationDate>2015-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='theDeserializer'>
                      <enc:encryptedSecret decryptorType='theDecryptor'>
                        <node xmlns='private' />
                      </enc:encryptedSecret>
                    </descriptor>
                  </key>
                </root>";

            var expectedEncryptor = new Mock<IAuthenticatedEncryptor>().Object;
            var mockActivator = new Mock<IActivator>();
            mockActivator.ReturnDecryptedElementGivenDecryptorTypeNameAndInput("theDecryptor", "<node xmlns='private' />", "<decryptedNode />");
            mockActivator.ReturnAuthenticatedEncryptorGivenDeserializerTypeNameAndInput("theDeserializer", "<decryptedNode />", expectedEncryptor);

            // Act
            var keys = RunGetAllKeysCore(xml, mockActivator.Object).ToArray();

            // Assert
            Assert.Equal(1, keys.Length);
            Assert.Equal(new Guid("09712588-ba68-438a-a5ee-fe842b3453b2"), keys[0].KeyId);
            Assert.Same(expectedEncryptor, keys[0].CreateEncryptorInstance());
        }
        public void GetAllKeys_IgnoresUnknownElements()
        {
            // Arrange
            const string xml = @"
                <root>
                  <key id='62a72ad9-42d7-4e97-b3fa-05bad5d53d33' version='1'>
                    <creationDate>2015-01-01T00:00:00Z</creationDate>
                    <activationDate>2015-02-01T00:00:00Z</activationDate>
                    <expirationDate>2015-03-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='deserializer-A'>
                      <elementA />
                    </descriptor>
                  </key>
                  <unknown>
                    <![CDATA[Unknown elements are ignored.]]>
                  </unknown>
                  <key id='041be4c0-52d7-48b4-8d32-f8c0ff315459' version='1'>
                    <creationDate>2015-04-01T00:00:00Z</creationDate>
                    <activationDate>2015-05-01T00:00:00Z</activationDate>
                    <expirationDate>2015-06-01T00:00:00Z</expirationDate>
                    <descriptor deserializerType='deserializer-B'>
                      <elementB />
                    </descriptor>    
                  </key>
                </root>";

            var encryptorA = new Mock<IAuthenticatedEncryptor>().Object;
            var encryptorB = new Mock<IAuthenticatedEncryptor>().Object;
            var mockActivator = new Mock<IActivator>();
            mockActivator.ReturnAuthenticatedEncryptorGivenDeserializerTypeNameAndInput("deserializer-A", "<elementA />", encryptorA);
            mockActivator.ReturnAuthenticatedEncryptorGivenDeserializerTypeNameAndInput("deserializer-B", "<elementB />", encryptorB);

            // Act
            var keys = RunGetAllKeysCore(xml, mockActivator.Object).ToArray();

            // Assert
            Assert.Equal(2, keys.Length);
            Assert.Equal(new Guid("62a72ad9-42d7-4e97-b3fa-05bad5d53d33"), keys[0].KeyId);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-01-01T00:00:00Z"), keys[0].CreationDate);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-02-01T00:00:00Z"), keys[0].ActivationDate);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-03-01T00:00:00Z"), keys[0].ExpirationDate);
            Assert.False(keys[0].IsRevoked);
            Assert.Same(encryptorA, keys[0].CreateEncryptorInstance());
            Assert.Equal(new Guid("041be4c0-52d7-48b4-8d32-f8c0ff315459"), keys[1].KeyId);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-04-01T00:00:00Z"), keys[1].CreationDate);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-05-01T00:00:00Z"), keys[1].ActivationDate);
            Assert.Equal(XmlConvert.ToDateTimeOffset("2015-06-01T00:00:00Z"), keys[1].ExpirationDate);
            Assert.False(keys[1].IsRevoked);
            Assert.Same(encryptorB, keys[1].CreateEncryptorInstance());
        }