/// <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 <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); }
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); } }
/// <summary> /// Reads a <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); }