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 </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