public override SecurityToken ReadToken(string tokenString) { var assertion = new Saml2Assertion(new Saml2NameIdentifier("__TemporaryIssuer__")); var wrappedSerializer = new WrappedSerializer(this, assertion); var sr = new StringReader(_samlXml); using (var reader1 = XmlReader.Create(sr)) { var reader2 = new EnvelopedSignatureReader(reader1, wrappedSerializer, Configuration.IssuerTokenResolver, false, false, false); if (!reader2.ReadToFollowing("Signature", "http://www.w3.org/2000/09/xmldsig#") || !reader2.TryReadSignature()) { throw new FederatedAuthenticationException("Cannot find token signature", FederatedAuthenticationErrorCode.WrongFormat); } if (!reader2.ReadToFollowing("Assertion", "urn:oasis:names:tc:SAML:2.0:assertion")) { throw new FederatedAuthenticationException("Cannot find token assertion", FederatedAuthenticationErrorCode.WrongFormat); } assertion = ReadAssertion(reader2); try { while (reader2.Read()) { // } } catch (CryptographicException cryptographicExceptione) { throw new FederatedAuthenticationException(cryptographicExceptione.Message, FederatedAuthenticationErrorCode.NotTrustedIssuer, cryptographicExceptione); } assertion.SigningCredentials = reader2.SigningCredentials; var keys = ResolveSecurityKeys(assertion, Configuration.ServiceTokenResolver); SecurityToken token; TryResolveIssuerToken(assertion, Configuration.IssuerTokenResolver, out token); return(new Saml2SecurityToken(assertion, keys, token)); } }
/// <summary> /// Reads the <saml:Assertion> element. /// </summary> /// <param name="reader">A <see cref="XmlReader"/> positioned at a <see cref="Saml2Assertion"/> element.</param> /// <returns>A <see cref="Saml2Assertion"/> instance.</returns> protected virtual Saml2Assertion ReadAssertion(XmlReader reader) { if (null == reader) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } if (this.Configuration == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4274)); } if (this.Configuration.IssuerTokenResolver == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4275)); } if (this.Configuration.ServiceTokenResolver == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4276)); } XmlDictionaryReader plaintextReader = XmlDictionaryReader.CreateDictionaryReader(reader); Saml2Assertion assertion = new Saml2Assertion(new Saml2NameIdentifier("__TemporaryIssuer__")); // If it's an EncryptedAssertion, we need to retrieve the plaintext // and repoint our reader if (reader.IsStartElement(Saml2Constants.Elements.EncryptedAssertion, Saml2Constants.Namespace)) { EncryptingCredentials encryptingCredentials = null; plaintextReader = CreatePlaintextReaderFromEncryptedData( plaintextReader, Configuration.ServiceTokenResolver, this.KeyInfoSerializer, assertion.ExternalEncryptedKeys, out encryptingCredentials); assertion.EncryptingCredentials = encryptingCredentials; } // Throw if wrong element if (!plaintextReader.IsStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace)) { plaintextReader.ReadStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace); } // disallow empty if (plaintextReader.IsEmptyElement) { #pragma warning suppress 56504 // bogus - thinks plaintextReader.LocalName, plaintextReader.NamespaceURI need validation throw DiagnosticUtility.ThrowHelperXml(plaintextReader, SR.GetString(SR.ID3061, plaintextReader.LocalName, plaintextReader.NamespaceURI)); } // Construct a wrapped serializer so that the EnvelopedSignatureReader's // attempt to read the <ds:KeyInfo> will hit our ReadKeyInfo virtual. WrappedSerializer wrappedSerializer = new WrappedSerializer(this, assertion); // SAML supports enveloped signature, so we need to wrap our reader. // We do not dispose this reader, since as a delegating reader it would // dispose the inner reader, which we don't properly own. EnvelopedSignatureReader realReader = new EnvelopedSignatureReader(plaintextReader, wrappedSerializer, this.Configuration.IssuerTokenResolver, false, false, false); try { // Process @attributes string value; // @xsi:type XmlUtil.ValidateXsiType(realReader, Saml2Constants.Types.AssertionType, Saml2Constants.Namespace); // @Version - required - must be "2.0" string version = realReader.GetAttribute(Saml2Constants.Attributes.Version); if (string.IsNullOrEmpty(version)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.Version, Saml2Constants.Elements.Assertion)); } if (!StringComparer.Ordinal.Equals(assertion.Version, version)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID4100, version)); } // @ID - required value = realReader.GetAttribute(Saml2Constants.Attributes.ID); if (string.IsNullOrEmpty(value)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.ID, Saml2Constants.Elements.Assertion)); } assertion.Id = new Saml2Id(value); // @IssueInstant - required value = realReader.GetAttribute(Saml2Constants.Attributes.IssueInstant); if (string.IsNullOrEmpty(value)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.IssueInstant, Saml2Constants.Elements.Assertion)); } assertion.IssueInstant = XmlConvert.ToDateTime(value, DateTimeFormats.Accepted); // Process <elements> realReader.Read(); // <Issuer> 1 assertion.Issuer = this.ReadIssuer(realReader); // <ds:Signature> 0-1 realReader.TryReadSignature(); // <Subject> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace)) { assertion.Subject = this.ReadSubject(realReader); } // <Conditions> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Conditions, Saml2Constants.Namespace)) { assertion.Conditions = this.ReadConditions(realReader); } // <Advice> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace)) { assertion.Advice = this.ReadAdvice(realReader); } // <Statement|AuthnStatement|AuthzDecisionStatement|AttributeStatement>, 0-OO while (realReader.IsStartElement()) { Saml2Statement statement; if (realReader.IsStartElement(Saml2Constants.Elements.Statement, Saml2Constants.Namespace)) { statement = this.ReadStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AttributeStatement, Saml2Constants.Namespace)) { statement = this.ReadAttributeStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AuthnStatement, Saml2Constants.Namespace)) { statement = this.ReadAuthenticationStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AuthzDecisionStatement, Saml2Constants.Namespace)) { statement = this.ReadAuthorizationDecisionStatement(realReader); } else { break; } assertion.Statements.Add(statement); } realReader.ReadEndElement(); if (null == assertion.Subject) { // An assertion with no statements MUST contain a <Subject> element. [Saml2Core, line 585] if (0 == assertion.Statements.Count) { throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4106)); } // 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 DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4119)); } } } // Reading the end element will complete the signature; // capture the signing creds assertion.SigningCredentials = realReader.SigningCredentials; // Save the captured on-the-wire data, which can then be used // to re-emit this assertion, preserving the same signature. assertion.CaptureSourceData(realReader); return assertion; } catch (Exception e) { if (System.Runtime.Fx.IsFatal(e)) throw; Exception wrapped = TryWrapReadException(realReader, e); if (null == wrapped) { throw; } else { throw wrapped; } } }