/// <summary>
        /// Validates the presence and correctness of a <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/> among the any-xml-elements of a SubjectConfirmationData
        /// </summary>
        /// <param name="subjectConfirmationData">The subject confirmation data.</param>
        public void ValidateKeyInfo(SubjectConfirmationData subjectConfirmationData)
        {
            if (subjectConfirmationData == null)
            {
                throw new Saml20FormatException("SubjectConfirmationData cannot be null when KeyInfo subelements are required");
            }

            if (subjectConfirmationData.AnyElements == null)
            {
                throw new Saml20FormatException(string.Format("SubjectConfirmationData element MUST have at least one {0} subelement", KeyInfo.ElementName));
            }

            var keyInfoFound = false;
            foreach (var element in subjectConfirmationData.AnyElements)
            {
                if (element.NamespaceURI != Saml20Constants.Xmldsig || element.LocalName != KeyInfo.ElementName)
                {
                    continue;
                }

                keyInfoFound = true;

                // A KeyInfo element MUST identify a cryptographic key
                if (!element.HasChildNodes)
                {
                    throw new Saml20FormatException(string.Format("{0} subelement of SubjectConfirmationData MUST NOT be empty", KeyInfo.ElementName));
                }
            }

            // There MUST BE at least one <ds:KeyInfo> element present (from the arbitrary elements list on SubjectConfirmationData
            if (!keyInfoFound)
            {
                throw new Saml20FormatException(string.Format("SubjectConfirmationData element MUST contain at least one {0} in namespace {1}", KeyInfo.ElementName, Saml20Constants.Xmldsig));
            }
        }
        /// <summary>
        /// Validate SubjectConfirmationData.
        /// </summary>
        /// <param name="subjectConfirmationData">The subject confirmation data.</param>
        /// <remarks>
        /// [SAML2.0 standard] section 2.4.1.2
        /// </remarks>
        public void ValidateSubjectConfirmationData(SubjectConfirmationData subjectConfirmationData)
        {
            // If present it must be anyUri
            if (subjectConfirmationData.Recipient != null)
            {
                if (!Uri.IsWellFormedUriString(subjectConfirmationData.Recipient, UriKind.Absolute))
                {
                    throw new Saml20FormatException("Recipient of SubjectConfirmationData must be a wellformed absolute URI.");
                }
            }

            // NotBefore MUST BE striclty less than NotOnOrAfter if they are both set
            if (subjectConfirmationData.NotBefore != null && subjectConfirmationData.NotOnOrAfter != null && !(subjectConfirmationData.NotBefore < subjectConfirmationData.NotOnOrAfter))
            {
                throw new Saml20FormatException(string.Format("NotBefore {0} MUST BE less than NotOnOrAfter {1} on SubjectConfirmationData", Saml20Utils.ToUtcString(subjectConfirmationData.NotBefore.Value), Saml20Utils.ToUtcString(subjectConfirmationData.NotOnOrAfter.Value)));
            }

            // Make sure the extension-attributes are namespace-qualified and do not use reserved namespaces
            if (subjectConfirmationData.AnyAttr != null)
            {
                _anyAttrValidator.ValidateXmlAnyAttributes(subjectConfirmationData.AnyAttr);
            }

            // Standards-defined extension type which has stricter rules than it's base type
            if (subjectConfirmationData is KeyInfoConfirmationData)
            {
                _keyInfoValidator.ValidateKeyInfo(subjectConfirmationData);
            }
        }
            public void ValidatesSubjectConfirmationDataTimeIntervalSettings()
            {
                // TODO: Split this up
                // Arrange
                var validator = new Saml20SubjectConfirmationDataValidator();

                var subjectConfirmationData = new SubjectConfirmationData();
                subjectConfirmationData.NotBefore = new DateTime(2008, 01, 30, 17, 13, 0, 500, DateTimeKind.Utc);
                subjectConfirmationData.NotOnOrAfter = subjectConfirmationData.NotBefore.Value.AddHours(1);

                validator.ValidateSubjectConfirmationData(subjectConfirmationData);

                subjectConfirmationData.NotBefore = null;
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);

                // DateTime validation wrt DateTime.UtcNow is NOT done by the validators
                // so a future-NotBefore must be valid
                subjectConfirmationData.NotBefore = subjectConfirmationData.NotOnOrAfter;
                subjectConfirmationData.NotOnOrAfter = null;
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);

                subjectConfirmationData.NotBefore = null;

                // Act
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);
            }
            public void ValidatesSubjectConfirmationDataRecipient()
            {
                // Arrange
                var subjectConfirmationData = new SubjectConfirmationData { Recipient = "urn:wellformed.uri:ok" };
                var validator = new Saml20SubjectConfirmationDataValidator();

                // Act
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);
            }
            public void ThrowsExceptionWhenSubjectConfirmationDataTimeIntervalIsInvalid()
            {
                // Arrange
                var subjectConfirmationData = new SubjectConfirmationData();
                subjectConfirmationData.NotBefore = new DateTime(2008, 01, 30, 17, 13, 0, 500, DateTimeKind.Utc);
                subjectConfirmationData.NotOnOrAfter = subjectConfirmationData.NotBefore.Value.AddHours(-1);

                var validator = new Saml20SubjectConfirmationDataValidator();

                // Act
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);
            }
            public void ThrowsExceptionWhenSubjectConfirmationDataRecipientIsInvalid()
            {
                // Arrange
                var subjectConfirmationData = new SubjectConfirmationData { Recipient = "malformed uri" };
                var validator = new Saml20SubjectConfirmationDataValidator();

                // Act
                validator.ValidateSubjectConfirmationData(subjectConfirmationData);
            }