1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.IdentityModel.Tokens
6 {
7     using System.Collections.Generic;
8     using System.Collections.ObjectModel;
9     using System.Globalization;
10     using System.IO;
11     using System.IdentityModel;
12     using System.IdentityModel.Claims;
13     using System.IdentityModel.Policy;
14     using System.IdentityModel.Selectors;
15     using System.Runtime;
16     using System.Runtime.InteropServices;
17     using System.Security;
18     using System.Security.Cryptography;
19     using System.Xml;
20 
21     public class SamlAssertion : ICanonicalWriterEndRootElementCallback
22     {
23         string assertionId = SamlConstants.AssertionIdPrefix + Guid.NewGuid().ToString();
24         string issuer;
25         DateTime issueInstant = DateTime.UtcNow.ToUniversalTime();
26         SamlConditions conditions;
27         SamlAdvice advice;
28         readonly ImmutableCollection<SamlStatement> statements = new ImmutableCollection<SamlStatement>();
29         ReadOnlyCollection<SecurityKey> cryptoList;
30 
31         SignedXml signature;
32         SigningCredentials signingCredentials;
33         SecurityKey verificationKey;
34         SecurityToken signingToken;
35 
36         HashStream hashStream;
37         XmlTokenStream tokenStream;
38         SecurityTokenSerializer keyInfoSerializer;
39         DictionaryManager dictionaryManager;
40         XmlTokenStream sourceData;
41 
42         bool isReadOnly = false;
43 
SamlAssertion()44         public SamlAssertion()
45         {
46         }
47 
SamlAssertion( string assertionId, string issuer, DateTime issueInstant, SamlConditions samlConditions, SamlAdvice samlAdvice, IEnumerable<SamlStatement> samlStatements )48         public SamlAssertion(
49             string assertionId,
50             string issuer,
51             DateTime issueInstant,
52             SamlConditions samlConditions,
53             SamlAdvice samlAdvice,
54             IEnumerable<SamlStatement> samlStatements
55             )
56         {
57             if (string.IsNullOrEmpty(assertionId))
58                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionIdRequired));
59 
60             if (!IsAssertionIdValid(assertionId))
61                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionIDIsInvalid, assertionId));
62 
63             if (string.IsNullOrEmpty(issuer))
64                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionIssuerRequired));
65 
66             if (samlStatements == null)
67             {
68                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("samlStatements");
69             }
70 
71             this.assertionId = assertionId;
72             this.issuer = issuer;
73             this.issueInstant = issueInstant.ToUniversalTime();
74             this.conditions = samlConditions;
75             this.advice = samlAdvice;
76 
77             foreach (SamlStatement samlStatement in samlStatements)
78             {
79                 if (samlStatement == null)
80                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLEntityCannotBeNullOrEmpty, XD.SamlDictionary.Statement.Value));
81 
82                 this.statements.Add(samlStatement);
83             }
84 
85             if (this.statements.Count == 0)
86                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionRequireOneStatement));
87         }
88 
89         public int MinorVersion
90         {
91             get { return SamlConstants.MinorVersionValue; }
92         }
93 
94         public int MajorVersion
95         {
96             get { return SamlConstants.MajorVersionValue; }
97         }
98 
99         public string AssertionId
100         {
101             get { return this.assertionId; }
102             set
103             {
104                 if (isReadOnly)
105                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
106 
107                 if (string.IsNullOrEmpty(value))
108                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionIdRequired));
109 
110                 this.assertionId = value;
111             }
112         }
113 
114         /// <summary>
115         /// Indicates whether this assertion was deserialized from XML source
116         /// and can re-emit the XML data unchanged.
117         /// </summary>
118         /// <remarks>
119         /// <para>
120         /// The default implementation preserves the source data when read using
121         /// Saml2AssertionSerializer.ReadAssertion and is willing to re-emit the
122         /// original data as long as the Id has not changed from the time that
123         /// assertion was read.
124         /// </para>
125         /// <para>
126         /// Note that it is vitally important that SAML assertions with different
127         /// data have different IDs. If implementing a scheme whereby an assertion
128         /// "template" is loaded and certain bits of data are filled in, the Id
129         /// must be changed.
130         /// </para>
131         /// </remarks>
132         /// <returns></returns>
133         public virtual bool CanWriteSourceData
134         {
135             get { return null != this.sourceData; }
136         }
137 
138         public string Issuer
139         {
140             get { return this.issuer; }
141             set
142             {
143                 if (isReadOnly)
144                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
145 
146                 if (string.IsNullOrEmpty(value))
147                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SAMLAssertionIssuerRequired));
148 
149                 this.issuer = value;
150             }
151         }
152 
153         public DateTime IssueInstant
154         {
155             get { return this.issueInstant; }
156             set
157             {
158                 if (isReadOnly)
159                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
160 
161                 this.issueInstant = value;
162             }
163         }
164 
165         public SamlConditions Conditions
166         {
167             get { return this.conditions; }
168             set
169             {
170                 if (isReadOnly)
171                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
172 
173                 this.conditions = value;
174             }
175         }
176 
177         public SamlAdvice Advice
178         {
179             get { return this.advice; }
180             set
181             {
182                 if (isReadOnly)
183                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
184 
185                 this.advice = value;
186             }
187         }
188 
189         public IList<SamlStatement> Statements
190         {
191             get
192             {
193                 return this.statements;
194             }
195         }
196 
197         public SigningCredentials SigningCredentials
198         {
199             get { return this.signingCredentials; }
200             set
201             {
202                 if (isReadOnly)
203                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
204 
205                 this.signingCredentials = value;
206             }
207         }
208 
209         internal SignedXml Signature
210         {
211             get { return this.signature; }
212         }
213 
214         internal SecurityKey SignatureVerificationKey
215         {
216             get { return this.verificationKey; }
217         }
218 
219         public SecurityToken SigningToken
220         {
221             get { return this.signingToken; }
222             set
223             {
224                 if (isReadOnly)
225                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
226 
227                 this.signingToken = value;
228             }
229         }
230 
231         public bool IsReadOnly
232         {
233             get { return this.isReadOnly; }
234         }
235 
236         internal ReadOnlyCollection<SecurityKey> SecurityKeys
237         {
238             get
239             {
240                 return this.cryptoList;
241             }
242         }
243 
MakeReadOnly()244         public void MakeReadOnly()
245         {
246             if (!this.isReadOnly)
247             {
248                 if (this.conditions != null)
249                     this.conditions.MakeReadOnly();
250 
251                 if (this.advice != null)
252                     this.advice.MakeReadOnly();
253 
254                 foreach (SamlStatement statement in this.statements)
255                 {
256                     statement.MakeReadOnly();
257                 }
258 
259                 this.statements.MakeReadOnly();
260 
261                 if (this.cryptoList == null)
262                 {
263                     this.cryptoList = BuildCryptoList();
264                 }
265 
266                 this.isReadOnly = true;
267             }
268         }
269 
270         /// <summary>
271         /// Captures the XML source data from an EnvelopedSignatureReader.
272         /// </summary>
273         /// <remarks>
274         /// The EnvelopedSignatureReader that was used to read the data for this
275         /// assertion should be passed to this method after the &lt;/Assertion>
276         /// element has been read. This method will preserve the raw XML data
277         /// that was read, including the signature, so that it may be re-emitted
278         /// without changes and without the need to re-sign the data. See
279         /// CanWriteSourceData and WriteSourceData.
280         /// </remarks>
281         /// <param name="reader"></param>
CaptureSourceData(EnvelopedSignatureReader reader)282         internal virtual void CaptureSourceData(EnvelopedSignatureReader reader)
283         {
284             if (null == reader)
285             {
286                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
287             }
288 
289             this.sourceData = reader.XmlTokens;
290         }
291 
ReadSignature(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver, SamlSerializer samlSerializer)292         protected void ReadSignature(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver, SamlSerializer samlSerializer)
293         {
294             if (reader == null)
295                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
296 
297             if (samlSerializer == null)
298                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("samlSerializer");
299 
300             if (this.signature != null)
301                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SAMLSignatureAlreadyRead)));
302 
303             // If the reader cannot canonicalize then buffer the signature element to a canonicalizing reader.
304             XmlDictionaryReader effectiveReader = reader;
305             if (!effectiveReader.CanCanonicalize)
306             {
307                 MemoryStream stream = new MemoryStream();
308                 XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, samlSerializer.DictionaryManager.ParentDictionary);
309                 writer.WriteNode(effectiveReader, false);
310                 writer.Flush();
311                 stream.Position = 0;
312                 effectiveReader = XmlDictionaryReader.CreateBinaryReader(stream.GetBuffer(), 0, (int)stream.Length, samlSerializer.DictionaryManager.ParentDictionary, reader.Quotas);
313                 effectiveReader.MoveToContent();
314                 writer.Close();
315             }
316             SignedXml signedXml = new SignedXml(new StandardSignedInfo(samlSerializer.DictionaryManager), samlSerializer.DictionaryManager, keyInfoSerializer);
317             signedXml.TransformFactory = ExtendedTransformFactory.Instance;
318             signedXml.ReadFrom(effectiveReader);
319             SecurityKeyIdentifier securityKeyIdentifier = signedXml.Signature.KeyIdentifier;
320             this.verificationKey = SamlSerializer.ResolveSecurityKey(securityKeyIdentifier, outOfBandTokenResolver);
321             if (this.verificationKey == null)
322                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLUnableToResolveSignatureKey, this.issuer)));
323 
324             this.signature = signedXml;
325             this.signingToken = SamlSerializer.ResolveSecurityToken(securityKeyIdentifier, outOfBandTokenResolver);
326             if (this.signingToken == null)
327                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SamlSigningTokenNotFound)));
328 
329             if (!ReferenceEquals(reader, effectiveReader))
330                 effectiveReader.Close();
331         }
332 
CheckObjectValidity()333         void CheckObjectValidity()
334         {
335             if (string.IsNullOrEmpty(this.assertionId))
336                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionIdRequired)));
337 
338             if (!IsAssertionIdValid(this.assertionId))
339                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionIDIsInvalid, this.assertionId)));
340 
341             if (string.IsNullOrEmpty(this.issuer))
342                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionIssuerRequired)));
343 
344             if (this.statements.Count == 0)
345                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionRequireOneStatement)));
346         }
347 
IsAssertionIdValid(string assertionId)348         bool IsAssertionIdValid(string assertionId)
349         {
350             if (string.IsNullOrEmpty(assertionId))
351                 return false;
352 
353             // The first character of the Assertion ID should be a letter or a '_'
354             return (((assertionId[0] >= 'A') && (assertionId[0] <= 'Z')) ||
355                 ((assertionId[0] >= 'a') && (assertionId[0] <= 'z')) ||
356                 (assertionId[0] == '_'));
357         }
358 
BuildCryptoList()359         ReadOnlyCollection<SecurityKey> BuildCryptoList()
360         {
361             List<SecurityKey> cryptoList = new List<SecurityKey>();
362 
363             for (int i = 0; i < this.statements.Count; ++i)
364             {
365                 SamlSubjectStatement statement = this.statements[i] as SamlSubjectStatement;
366                 if (statement != null)
367                 {
368                     bool skipCrypto = false;
369                     SecurityKey crypto = null;
370                     if (statement.SamlSubject != null)
371                         crypto = statement.SamlSubject.Crypto;
372                     InMemorySymmetricSecurityKey inMemorySymmetricSecurityKey = crypto as InMemorySymmetricSecurityKey;
373                     if (inMemorySymmetricSecurityKey != null)
374                     {
375 
376                         // Verify that you have not already added this to crypto list.
377                         for (int j = 0; j < cryptoList.Count; ++j)
378                         {
379                             if ((cryptoList[j] is InMemorySymmetricSecurityKey) && (cryptoList[j].KeySize == inMemorySymmetricSecurityKey.KeySize))
380                             {
381                                 byte[] key1 = ((InMemorySymmetricSecurityKey)cryptoList[j]).GetSymmetricKey();
382                                 byte[] key2 = inMemorySymmetricSecurityKey.GetSymmetricKey();
383                                 int k = 0;
384                                 for (k = 0; k < key1.Length; ++k)
385                                 {
386                                     if (key1[k] != key2[k])
387                                     {
388                                         break;
389                                     }
390                                 }
391                                 skipCrypto = (k == key1.Length);
392                             }
393 
394                             if (skipCrypto)
395                                 break;
396                         }
397                     }
398                     if (!skipCrypto && (crypto != null))
399                     {
400                         cryptoList.Add(crypto);
401                     }
402                 }
403             }
404 
405             return cryptoList.AsReadOnly();
406 
407         }
408 
VerifySignature(SignedXml signature, SecurityKey signatureVerificationKey)409         void VerifySignature(SignedXml signature, SecurityKey signatureVerificationKey)
410         {
411             if (signature == null)
412                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("signature");
413 
414             if (signatureVerificationKey == null)
415                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("signatureVerificatonKey");
416 
417             signature.StartSignatureVerification(signatureVerificationKey);
418             signature.EnsureDigestValidity(this.assertionId, tokenStream);
419             signature.CompleteSignatureVerification();
420         }
421 
ICanonicalWriterEndRootElementCallback.OnEndOfRootElement(XmlDictionaryWriter dictionaryWriter)422         void ICanonicalWriterEndRootElementCallback.OnEndOfRootElement(XmlDictionaryWriter dictionaryWriter)
423         {
424             byte[] hashValue = this.hashStream.FlushHashAndGetValue();
425 
426             PreDigestedSignedInfo signedInfo = new PreDigestedSignedInfo(this.dictionaryManager);
427             signedInfo.AddEnvelopedSignatureTransform = true;
428             signedInfo.CanonicalizationMethod = SecurityAlgorithms.ExclusiveC14n;
429             signedInfo.SignatureMethod = this.signingCredentials.SignatureAlgorithm;
430             signedInfo.DigestMethod = this.signingCredentials.DigestAlgorithm;
431             signedInfo.AddReference(this.assertionId, hashValue);
432 
433             SignedXml signedXml = new SignedXml(signedInfo, this.dictionaryManager, this.keyInfoSerializer);
434             signedXml.ComputeSignature(this.signingCredentials.SigningKey);
435             signedXml.Signature.KeyIdentifier = this.signingCredentials.SigningKeyIdentifier;
436             signedXml.WriteTo(dictionaryWriter);
437         }
438 
ReadXml(XmlDictionaryReader reader, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)439         public virtual void ReadXml(XmlDictionaryReader reader, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
440         {
441             if (reader == null)
442                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ReadXml"));
443 
444             if (samlSerializer == null)
445                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("samlSerializer"));
446 
447             XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateDictionaryReader(reader);
448             WrappedReader wrappedReader = new WrappedReader(dictionaryReader);
449 #pragma warning suppress 56506 // samlSerializer.DictionaryManager is never null.
450             SamlDictionary dictionary = samlSerializer.DictionaryManager.SamlDictionary;
451 
452             if (!wrappedReader.IsStartElement(dictionary.Assertion, dictionary.Namespace))
453                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLElementNotRecognized, wrappedReader.LocalName)));
454 
455             string attributeValue = wrappedReader.GetAttribute(dictionary.MajorVersion, null);
456             if (string.IsNullOrEmpty(attributeValue))
457                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionMissingMajorVersionAttributeOnRead)));
458             int majorVersion = Int32.Parse(attributeValue, CultureInfo.InvariantCulture);
459 
460             attributeValue = wrappedReader.GetAttribute(dictionary.MinorVersion, null);
461             if (string.IsNullOrEmpty(attributeValue))
462                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionMissingMinorVersionAttributeOnRead)));
463 
464             int minorVersion = Int32.Parse(attributeValue, CultureInfo.InvariantCulture);
465 
466             if ((majorVersion != SamlConstants.MajorVersionValue) || (minorVersion != SamlConstants.MinorVersionValue))
467             {
468                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLTokenVersionNotSupported, majorVersion, minorVersion, SamlConstants.MajorVersionValue, SamlConstants.MinorVersionValue)));
469             }
470 
471             attributeValue = wrappedReader.GetAttribute(dictionary.AssertionId, null);
472             if (string.IsNullOrEmpty(attributeValue))
473                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionIdRequired)));
474 
475             if (!IsAssertionIdValid(attributeValue))
476                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionIDIsInvalid, attributeValue)));
477 
478             this.assertionId = attributeValue;
479 
480             attributeValue = wrappedReader.GetAttribute(dictionary.Issuer, null);
481             if (string.IsNullOrEmpty(attributeValue))
482                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionMissingIssuerAttributeOnRead)));
483             this.issuer = attributeValue;
484 
485             attributeValue = wrappedReader.GetAttribute(dictionary.IssueInstant, null);
486             if (!string.IsNullOrEmpty(attributeValue))
487                 this.issueInstant = DateTime.ParseExact(
488                     attributeValue, SamlConstants.AcceptedDateTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None).ToUniversalTime();
489 
490             wrappedReader.MoveToContent();
491             wrappedReader.Read();
492 
493             if (wrappedReader.IsStartElement(dictionary.Conditions, dictionary.Namespace))
494             {
495                 this.conditions = samlSerializer.LoadConditions(wrappedReader, keyInfoSerializer, outOfBandTokenResolver);
496                 if (this.conditions == null)
497                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLUnableToLoadCondtions)));
498             }
499 
500             if (wrappedReader.IsStartElement(dictionary.Advice, dictionary.Namespace))
501             {
502                 this.advice = samlSerializer.LoadAdvice(wrappedReader, keyInfoSerializer, outOfBandTokenResolver);
503                 if (this.advice == null)
504                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLUnableToLoadAdvice)));
505             }
506 
507             while (wrappedReader.IsStartElement())
508             {
509 #pragma warning suppress 56506 // samlSerializer.DictionaryManager is never null.
510                 if (wrappedReader.IsStartElement(samlSerializer.DictionaryManager.XmlSignatureDictionary.Signature, samlSerializer.DictionaryManager.XmlSignatureDictionary.Namespace))
511                 {
512                     break;
513                 }
514                 else
515                 {
516                     SamlStatement statement = samlSerializer.LoadStatement(wrappedReader, keyInfoSerializer, outOfBandTokenResolver);
517                     if (statement == null)
518                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLUnableToLoadStatement)));
519                     this.statements.Add(statement);
520                 }
521             }
522 
523             if (this.statements.Count == 0)
524                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SAMLAssertionRequireOneStatementOnRead)));
525 
526             if (wrappedReader.IsStartElement(samlSerializer.DictionaryManager.XmlSignatureDictionary.Signature, samlSerializer.DictionaryManager.XmlSignatureDictionary.Namespace))
527                 this.ReadSignature(wrappedReader, keyInfoSerializer, outOfBandTokenResolver, samlSerializer);
528 
529             wrappedReader.MoveToContent();
530             wrappedReader.ReadEndElement();
531 
532             this.tokenStream = wrappedReader.XmlTokens;
533 
534             if (this.signature != null)
535             {
536                 VerifySignature(this.signature, this.verificationKey);
537             }
538 
539             BuildCryptoList();
540         }
541 
WriteTo(XmlWriter writer, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer)542         internal void WriteTo(XmlWriter writer, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer)
543         {
544             if (writer == null)
545                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
546 
547             if ((this.signingCredentials == null) && (this.signature == null))
548                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SamlAssertionMissingSigningCredentials)));
549 
550             XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer);
551 
552             if (this.signingCredentials != null)
553             {
554                 using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(this.signingCredentials.DigestAlgorithm))
555                 {
556                     this.hashStream = new HashStream(hash);
557                     this.keyInfoSerializer = keyInfoSerializer;
558                     this.dictionaryManager = samlSerializer.DictionaryManager;
559                     SamlDelegatingWriter delegatingWriter = new SamlDelegatingWriter(dictionaryWriter, this.hashStream, this, samlSerializer.DictionaryManager.ParentDictionary);
560                     this.WriteXml(delegatingWriter, samlSerializer, keyInfoSerializer);
561                 }
562             }
563             else
564             {
565                 this.tokenStream.SetElementExclusion(null, null);
566                 this.tokenStream.WriteTo(dictionaryWriter, samlSerializer.DictionaryManager);
567             }
568         }
569 
WriteXml(XmlDictionaryWriter writer, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer)570         public virtual void WriteXml(XmlDictionaryWriter writer, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer)
571         {
572             CheckObjectValidity();
573 
574             if (writer == null)
575                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
576 
577             if (samlSerializer == null)
578                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("samlSerializer"));
579 
580 #pragma warning suppress 56506 // samlSerializer.DictionaryManager is never null.
581             SamlDictionary dictionary = samlSerializer.DictionaryManager.SamlDictionary;
582 
583             try
584             {
585                 writer.WriteStartElement(dictionary.PreferredPrefix.Value, dictionary.Assertion, dictionary.Namespace);
586 
587                 writer.WriteStartAttribute(dictionary.MajorVersion, null);
588                 writer.WriteValue(SamlConstants.MajorVersionValue);
589                 writer.WriteEndAttribute();
590                 writer.WriteStartAttribute(dictionary.MinorVersion, null);
591                 writer.WriteValue(SamlConstants.MinorVersionValue);
592                 writer.WriteEndAttribute();
593                 writer.WriteStartAttribute(dictionary.AssertionId, null);
594                 writer.WriteString(this.assertionId);
595                 writer.WriteEndAttribute();
596                 writer.WriteStartAttribute(dictionary.Issuer, null);
597                 writer.WriteString(this.issuer);
598                 writer.WriteEndAttribute();
599                 writer.WriteStartAttribute(dictionary.IssueInstant, null);
600                 writer.WriteString(this.issueInstant.ToString(SamlConstants.GeneratedDateTimeFormat, CultureInfo.InvariantCulture));
601                 writer.WriteEndAttribute();
602 
603                 // Write out conditions
604                 if (this.conditions != null)
605                 {
606                     this.conditions.WriteXml(writer, samlSerializer, keyInfoSerializer);
607                 }
608 
609                 // Write out advice if there is one
610                 if (this.advice != null)
611                 {
612                     this.advice.WriteXml(writer, samlSerializer, keyInfoSerializer);
613                 }
614 
615                 for (int i = 0; i < this.statements.Count; i++)
616                 {
617                     this.statements[i].WriteXml(writer, samlSerializer, keyInfoSerializer);
618                 }
619 
620                 writer.WriteEndElement();
621             }
622             catch (Exception e)
623             {
624                 // Always immediately rethrow fatal exceptions.
625                 if (Fx.IsFatal(e)) throw;
626 
627                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SAMLTokenNotSerialized), e));
628             }
629         }
630 
631         /// <summary>
632         /// Writes the source data, if available.
633         /// </summary>
634         /// <exception cref="InvalidOperationException">When no source data is available</exception>
635         /// <param name="writer"></param>
WriteSourceData(XmlWriter writer)636         public virtual void WriteSourceData(XmlWriter writer)
637         {
638             if (!this.CanWriteSourceData)
639             {
640                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
641                     new InvalidOperationException(SR.GetString(SR.ID4140)));
642             }
643 
644             // This call will properly just reuse the existing writer if it already qualifies
645             XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer);
646             this.sourceData.SetElementExclusion(null, null);
647             this.sourceData.GetWriter().WriteTo(dictionaryWriter, null );
648         }
649 
AddSamlClaimTypes(ICollection<Type> knownClaimTypes)650         static internal void AddSamlClaimTypes(ICollection<Type> knownClaimTypes)
651         {
652             if (knownClaimTypes == null)
653             {
654                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("knownClaimTypes");
655             }
656             knownClaimTypes.Add(typeof(SamlAuthorizationDecisionClaimResource));
657             knownClaimTypes.Add(typeof(SamlAuthenticationClaimResource));
658             knownClaimTypes.Add(typeof(SamlAccessDecision));
659             knownClaimTypes.Add(typeof(SamlAuthorityBinding));
660             knownClaimTypes.Add(typeof(SamlNameIdentifierClaimResource));
661         }
662     }
663 }
664