/// <summary>
        /// Creates a new <see cref="KeyInfo"/> object.
        /// </summary>
        /// <param name="reader">The current <see cref="XmlReader"/>.</param>
        protected virtual KeyInfo CreateKeyInfo(XmlReader reader)
        {
            XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace);

            return(new KeyInfo
            {
                Prefix = reader.Prefix
            });
        }
        /// <summary>
        /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-KeyInfo
        /// </summary>
        /// <param name="reader"><see cref="XmlReader"/> pointing positioned on a &lt;KeyInfo> element.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="reader"/> is null.</exception>
        /// <exception cref="XmlReadException">if there is a problem reading the XML.</exception>
        /// <remarks>Only handles IssuerSerial, Ski, SubjectName, Certificate. Unsupported types are skipped. Only a X509 data element is supported.</remarks>
        public override KeyInfo ReadKeyInfo(XmlReader reader)
        {
            XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace);

            var keyInfo = CreateKeyInfo(reader);

            try
            {
                bool isEmptyElement = reader.IsEmptyElement;

                // <KeyInfo>
                reader.ReadStartElement();
                while (reader.IsStartElement())
                {
                    if (!TryReadKeyInfoType(reader, ref keyInfo))
                    {
                        // Skip the element since it is not one of elements handled by TryReadKeyInfoType
                        LogHelper.LogWarning(GetLogMessage("IDX30300"), reader.ReadOuterXml());
                    }
                }

                // </KeyInfo>
                if (!isEmptyElement)
                {
                    reader.ReadEndElement();
                }
            }
            catch (Exception ex)
            {
                if (ex is XmlReadException)
                {
                    throw;
                }

                throw XmlUtil.LogReadException(GetLogMessage("IDX30017"), ex, XmlSignatureConstants.Elements.KeyInfo, ex);
            }

            return(keyInfo);
        }
Exemple #3
0
        protected override Saml2SubjectConfirmationData ReadSubjectConfirmationData(XmlDictionaryReader reader)
        {
            XmlUtil.CheckReaderOnEntry(reader, Saml2Constants.Elements.SubjectConfirmationData, Saml2Constants.Namespace);
            try
            {
                var  confirmationData = new Saml2SubjectConfirmationData();
                bool isEmpty          = reader.IsEmptyElement;

                // @xsi:type
                bool requireKeyInfo = false;
                var  type           = XmlUtil.GetXsiTypeAsQualifiedName(reader);

                if (null != type)
                {
                    if (XmlUtil.EqualsQName(type, Saml2Constants.Types.KeyInfoConfirmationDataType, Saml2Constants.Namespace) ||
                        type.Name == Saml2Constants.Types.KeyInfoConfirmationDataType)
                    {
                        requireKeyInfo = true;
                    }
                    else if (!XmlUtil.EqualsQName(type, Saml2Constants.Types.SubjectConfirmationDataType, Saml2Constants.Namespace) &&
                             type.Name != Saml2Constants.Types.SubjectConfirmationDataType)
                    {
                        throw XmlUtil.LogReadException(GetLogMessage("IDX13126"), type.Name, type.Namespace);
                    }
                }

                // KeyInfoConfirmationData cannot be empty
                if (requireKeyInfo && isEmpty)
                {
                    throw XmlUtil.LogReadException(GetLogMessage("IDX13127"));
                }

                // @Address - optional
                string value = reader.GetAttribute(Saml2Constants.Attributes.Address);
                if (!string.IsNullOrEmpty(value))
                {
                    confirmationData.Address = value;
                }

                // @InResponseTo - optional
                value = reader.GetAttribute(Saml2Constants.Attributes.InResponseTo);
                if (!string.IsNullOrEmpty(value))
                {
                    confirmationData.InResponseTo = new Saml2Id(value);
                }

                // @NotBefore - optional
                value = reader.GetAttribute(Saml2Constants.Attributes.NotBefore);
                if (!string.IsNullOrEmpty(value))
                {
                    confirmationData.NotBefore = XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
                }

                // @NotOnOrAfter - optional
                value = reader.GetAttribute(Saml2Constants.Attributes.NotOnOrAfter);
                if (!string.IsNullOrEmpty(value))
                {
                    confirmationData.NotOnOrAfter = XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
                }

                // @Recipient - optional
                value = reader.GetAttribute(Saml2Constants.Attributes.Recipient);
                if (!string.IsNullOrEmpty(value))
                {
                    if (!Uri.TryCreate(value, UriKind.Absolute, out _))
                    {
                        throw XmlUtil.LogReadException(GetLogMessage("IDX13107"), Saml2Constants.Elements.SubjectConfirmationData, Saml2Constants.Attributes.Recipient, reader.LocalName);
                    }

                    confirmationData.Recipient = new Uri(value);
                }

                // Contents
                reader.Read();
                if (!isEmpty)
                {
                    while (reader.IsStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace))
                    {
                        confirmationData.KeyInfos.Add(DSigSerializer.ReadKeyInfo(reader));
                    }

                    // If this isn't KeyInfo restricted, there might be open content here ...
                    if (!requireKeyInfo && XmlNodeType.EndElement != reader.NodeType)
                    {
                        // So throw and tell the user how to handle the open content
                        throw XmlUtil.LogReadException(GetLogMessage("IDX13128"), Saml2Constants.Elements.SubjectConfirmationData);
                    }

                    reader.ReadEndElement();
                }

                return(confirmationData);
            }
            catch (Exception ex)
            {
                if (ex is Saml2SecurityTokenReadException)
                {
                    throw;
                }

                throw XmlUtil.LogReadException(GetLogMessage("IDX13102"), ex, Saml2Constants.Elements.SubjectConfirmationData, ex);
            }
        }
Exemple #4
0
        /// <summary>
        /// Reads a &lt;saml:Assertion> element.
        /// </summary>
        /// <param name="reader">A <see cref="XmlReader"/> positioned at a <see cref="Saml2Assertion"/> element.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="reader"/> is null.</exception>
        /// <exception cref="NotSupportedException">if assertion is encrypted.</exception>
        /// <exception cref="Saml2SecurityTokenReadException">If <paramref name="reader"/> is not positioned at a Saml2Assertion.</exception>
        /// <exception cref="Saml2SecurityTokenReadException">If Version is not '2.0'.</exception>
        /// <exception cref="Saml2SecurityTokenReadException">If 'Id' is missing.</exception>>
        /// <exception cref="Saml2SecurityTokenReadException">If 'IssueInstant' is missing.</exception>>
        /// <exception cref="Saml2SecurityTokenReadException">If no statements are found.</exception>>
        /// <returns>A <see cref="Saml2Assertion"/> instance.</returns>
        public override Saml2Assertion ReadAssertion(XmlReader reader)
        {
            XmlUtil.CheckReaderOnEntry(reader, Saml2Constants.Elements.Assertion, Saml2Constants.Namespace);

            if (reader.IsStartElement(Saml2Constants.Elements.EncryptedAssertion, Saml2Constants.Namespace))
            {
                var encrypted = new XmlDocument();
                encrypted.PreserveWhitespace = true;
                encrypted.Load(reader);
                XmlElement decrypted = null;
                foreach (var cert in DecryptionCertificates)
                {
                    try
                    {
                        decrypted = encrypted.DocumentElement.Decrypt(cert.PrivateKey);
                        break;
                    }
                    catch (CryptographicException)
                    {
                    }
                }

                if (decrypted == null)
                {
                    throw new InvalidOperationException(
                              "Encrypted assertion could not be decrypted using any available decryption certificate");
                }

                reader = new XmlNodeReader(decrypted);
            }

            var envelopeReader = new EnvelopedSignatureReader(reader);
            var assertion      = new Saml2Assertion(new Saml2NameIdentifier("__TemporaryIssuer__"));

            try
            {
                // @xsi:type
                XmlUtil.ValidateXsiType(envelopeReader, Saml2Constants.Types.AssertionType, Saml2Constants.Namespace);

                // @Version - required - must be "2.0"
                string version = envelopeReader.GetAttribute(Saml2Constants.Attributes.Version);
                if (string.IsNullOrEmpty(version))
                {
                    throw LogReadException(LogMessages.IDX13106, Saml2Constants.Elements.Assertion, Saml2Constants.Attributes.Version);
                }

                if (!StringComparer.Ordinal.Equals(Saml2Constants.Version, version))
                {
                    throw LogReadException(LogMessages.IDX13137, version);
                }

                // @ID - required
                string value = envelopeReader.GetAttribute(Saml2Constants.Attributes.ID);
                if (string.IsNullOrEmpty(value))
                {
                    throw LogReadException(LogMessages.IDX13106, Saml2Constants.Elements.Assertion, Saml2Constants.Attributes.ID);
                }

                assertion.Id = new Saml2Id(value);

                // @IssueInstant - required
                value = envelopeReader.GetAttribute(Saml2Constants.Attributes.IssueInstant);
                if (string.IsNullOrEmpty(value))
                {
                    throw LogReadException(LogMessages.IDX13106, Saml2Constants.Elements.Assertion, Saml2Constants.Attributes.IssueInstant);
                }

                assertion.IssueInstant = DateTime.ParseExact(value, Saml2Constants.AcceptedDateTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None).ToUniversalTime();

                // will move to next element
                // <ds:Signature> 0-1 read by EnvelopedSignatureReader
                envelopeReader.Read();

                // <Issuer> 1
                assertion.Issuer = ReadIssuer(envelopeReader);

                // <Subject> 0-1
                if (envelopeReader.IsStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace))
                {
                    assertion.Subject = ReadSubject(envelopeReader);
                }

                // <Conditions> 0-1
                if (envelopeReader.IsStartElement(Saml2Constants.Elements.Conditions, Saml2Constants.Namespace))
                {
                    assertion.Conditions = ReadConditions(envelopeReader);
                }

                // <Advice> 0-1
                if (envelopeReader.IsStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace))
                {
                    assertion.Advice = ReadAdvice(envelopeReader);
                }

                // <Statement|AuthnStatement|AuthzDecisionStatement|AttributeStatement>, 0-OO
                while (envelopeReader.IsStartElement())
                {
                    Saml2Statement statement;

                    if (envelopeReader.IsStartElement(Saml2Constants.Elements.Statement, Saml2Constants.Namespace))
                    {
                        statement = ReadStatement(envelopeReader);
                    }
                    else if (envelopeReader.IsStartElement(Saml2Constants.Elements.AttributeStatement, Saml2Constants.Namespace))
                    {
                        statement = ReadAttributeStatement(envelopeReader);
                    }
                    else if (envelopeReader.IsStartElement(Saml2Constants.Elements.AuthnStatement, Saml2Constants.Namespace))
                    {
                        if (IgnoreAuthenticationContext)
                        {
                            envelopeReader.Skip();
                            continue;
                        }
                        statement = ReadAuthenticationStatement(envelopeReader);
                    }
                    else if (envelopeReader.IsStartElement(Saml2Constants.Elements.AuthzDecisionStatement, Saml2Constants.Namespace))
                    {
                        statement = ReadAuthorizationDecisionStatement(envelopeReader);
                    }
                    else
                    {
                        break;
                    }

                    assertion.Statements.Add(statement);
                }

                envelopeReader.ReadEndElement();
                if (assertion.Subject == null)
                {
                    // An assertion with no statements MUST contain a <Subject> element. [Saml2Core, line 585]
                    if (0 == assertion.Statements.Count)
                    {
                        throw LogReadException(LogMessages.IDX13108, Saml2Constants.Elements.Assertion);
                    }

                    // Furthermore, the built-in statement types all require the presence of a subject.
                    // [Saml2Core, lines 1050, 1168, 1280]
                    foreach (Saml2Statement statement in assertion.Statements)
                    {
                        if (statement is Saml2AuthenticationStatement ||
                            statement is Saml2AttributeStatement ||
                            statement is Saml2AuthorizationDecisionStatement)
                        {
                            throw LogReadException(LogMessages.IDX13109, Saml2Constants.Elements.Assertion);
                        }
                    }
                }

                // attach signedXml for validation of signature
                assertion.Signature = envelopeReader.Signature;
                return(assertion);
            }
            catch (Exception ex)
            {
                if (ex is Saml2SecurityTokenReadException)
                {
                    throw;
                }

                throw LogReadException(LogMessages.IDX13102, ex, Saml2Constants.Elements.Assertion, ex);
            }
        }
        public override KeyInfo ReadKeyInfo(XmlReader reader)
        {
            XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace);

            var keyInfo = new WsSecurityKeyInfo
            {
                Prefix = reader.Prefix
            };

            try
            {
                bool isEmptyElement = reader.IsEmptyElement;

                // <KeyInfo>
                reader.ReadStartElement();
                while (reader.IsStartElement())
                {
                    // <SecurityTokenReference>
                    if (reader.IsStartElement("SecurityTokenReference", WsSecurityConstants.WsSecurity10.Namespace))
                    {
                        //<o:SecurityTokenReference>
                        //  <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-2a7d35cf-97d9-4177-8b84-8a74f5dcd8a2-29"></o:Reference>
                        //</o:SecurityTokenReference>
                        reader.ReadStartElement();
                        if (reader.IsStartElement("Reference", WsSecurityConstants.WsSecurity10.Namespace))
                        {
                            var uri = reader.GetAttribute(XmlSignatureConstants.Attributes.URI);
                            keyInfo.SecurityTokenReference = new WsSecurityTokenReference(new KeyIdentifier(uri))
                            {
                                Reference = new WsSecurityReference
                                {
                                    ValueType = reader.GetAttribute("ValueType"),
                                    Uri       = uri
                                }
                                //Reference = new WsSecurityReference()
                                //{
                                //    ValueType = reader.GetAttribute("ValueType"),
                                //    Uri = uri
                                //}
                            };
                            _ = reader.ReadOuterXml();
                        }
                        reader.ReadEndElement();
                    }
                    else
                    {
                        //LogHelper.LogWarning(LogMessages.IDX30300, reader.ReadOuterXml());
                        _ = reader.ReadOuterXml(); // TODO: log this somehow
                    }
                }

                // </KeyInfo>
                if (!isEmptyElement)
                {
                    reader.ReadEndElement();
                }
            }
            catch (Exception ex)
            {
                if (ex is XmlReadException)
                {
                    throw;
                }

                throw new XmlReadException($"{ "IDX30017" }: Could not read {XmlSignatureConstants.Elements.KeyInfo} element.", ex);// XmlUtil.LogReadException(LogMessages.IDX30017, ex, XmlSignatureConstants.Elements.KeyInfo, ex);
            }

            return(keyInfo);
        }