1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.IdentityModel.Metadata
6 {
7     using System.Collections.Generic;
8     using System.Globalization;
9     using System.IdentityModel.Configuration;
10     using System.IdentityModel.Diagnostics;
11     using System.IdentityModel.Protocols.WSFederation;
12     using System.IdentityModel.Protocols.WSTrust;
13     using System.IdentityModel.Selectors;
14     using System.IdentityModel.Tokens;
15     using System.IO;
16     using System.Security.Cryptography.X509Certificates;
17     using System.ServiceModel.Security;
18     using System.Text;
19     using System.Xml;
20     using System.Xml.Schema;
21 
22     /// <summary>
23     /// Provides support for Metadata Serialization
24     /// </summary>
25     public class MetadataSerializer
26     {
27 #pragma warning disable 1591
28         public const string LanguagePrefix = "xml";
29         public const string LanguageLocalName = "lang";
30         public const string LanguageAttribute = LanguagePrefix + ":" + LanguageLocalName;
31         public const string LanguageNamespaceUri = "http://www.w3.org/XML/1998/namespace";
32 #pragma warning restore 1591
33 
34         const string _uriReference = "_metadata";
35         List<string> _trustedIssuers = new List<string>();
36         SecurityTokenSerializer _tokenSerializer;
37 
38         /// <summary>
39         /// Initializes an instance of <see cref="MetadataSerializer"/>
40         /// </summary>
MetadataSerializer()41         public MetadataSerializer()
42             : this(new KeyInfoSerializer(true))
43         {
44         }
45 
46 
47         /// <summary>
48         /// Initializes an instance of <see cref="MetadataSerializer"/>
49         /// </summary>
50         /// <param name="tokenSerializer">Security Token Serializer</param>
51         /// <exception cref="ArgumentNullException">The parameter tokenSerializer is null.</exception>
MetadataSerializer(SecurityTokenSerializer tokenSerializer)52         public MetadataSerializer(SecurityTokenSerializer tokenSerializer)
53         {
54             if (tokenSerializer == null)
55             {
56                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenSerializer");
57             }
58 
59             _tokenSerializer = tokenSerializer;
60             TrustedStoreLocation = IdentityConfiguration.DefaultTrustedStoreLocation;
61             CertificateValidationMode = IdentityConfiguration.DefaultCertificateValidationMode;
62             RevocationMode = IdentityConfiguration.DefaultRevocationMode;
63         }
64 
65         /// <summary>
66         /// Creates an application service descriptor.
67         /// </summary>
68         /// <returns>An application service descriptor.</returns>
CreateApplicationServiceInstance()69         protected virtual ApplicationServiceDescriptor CreateApplicationServiceInstance()
70         {
71             return new ApplicationServiceDescriptor();
72         }
73 
74         /// <summary>
75         /// Creates a contact person.
76         /// </summary>
77         /// <returns>A contact person.</returns>
CreateContactPersonInstance()78         protected virtual ContactPerson CreateContactPersonInstance()
79         {
80             return new ContactPerson();
81         }
82 
83         /// <summary>
84         /// Creates an endpoint.
85         /// </summary>
86         /// <returns>An endpoint.</returns>
CreateProtocolEndpointInstance()87         protected virtual ProtocolEndpoint CreateProtocolEndpointInstance()
88         {
89             return new ProtocolEndpoint();
90         }
91 
92         /// <summary>
93         /// Creates entities descriptor.
94         /// </summary>
95         /// <returns>The entities descriptor. </returns>
CreateEntitiesDescriptorInstance()96         protected virtual EntitiesDescriptor CreateEntitiesDescriptorInstance()
97         {
98             return new EntitiesDescriptor();
99         }
100 
101         /// <summary>
102         /// Creates an entity descriptor.
103         /// </summary>
104         /// <returns>The entity descriptor.</returns>
CreateEntityDescriptorInstance()105         protected virtual EntityDescriptor CreateEntityDescriptorInstance()
106         {
107             return new EntityDescriptor();
108         }
109 
110         /// <summary>
111         /// Creates an idpsso descriptor.
112         /// </summary>
113         /// <returns>An idpsso descriptor.</returns>
CreateIdentityProviderSingleSignOnDescriptorInstance()114         protected virtual IdentityProviderSingleSignOnDescriptor CreateIdentityProviderSingleSignOnDescriptorInstance()
115         {
116             return new IdentityProviderSingleSignOnDescriptor();
117         }
118 
119         /// <summary>
120         /// Creates an indexed enpoint.
121         /// </summary>
122         /// <returns>An indexed endpoint.</returns>
CreateIndexedProtocolEndpointInstance()123         protected virtual IndexedProtocolEndpoint CreateIndexedProtocolEndpointInstance()
124         {
125             return new IndexedProtocolEndpoint();
126         }
127 
128         /// <summary>
129         /// Creates a key descriptor.
130         /// </summary>
131         /// <returns>The key descriptor.</returns>
CreateKeyDescriptorInstance()132         protected virtual KeyDescriptor CreateKeyDescriptorInstance()
133         {
134             return new KeyDescriptor();
135         }
136 
137         /// <summary>
138         /// Creates a localized name.
139         /// </summary>
140         /// <returns>The localized name.</returns>
CreateLocalizedNameInstance()141         protected virtual LocalizedName CreateLocalizedNameInstance()
142         {
143             return new LocalizedName();
144         }
145 
146         /// <summary>
147         /// Creates a localized uri.
148         /// </summary>
149         /// <returns>A localized uri.</returns>
CreateLocalizedUriInstance()150         protected virtual LocalizedUri CreateLocalizedUriInstance()
151         {
152             return new LocalizedUri();
153         }
154 
155         /// <summary>
156         /// Creates an organization.
157         /// </summary>
158         /// <returns>An organization.</returns>
CreateOrganizationInstance()159         protected virtual Organization CreateOrganizationInstance()
160         {
161             return new Organization();
162         }
163 
164         /// <summary>
165         /// Creates a security token service descriptor.
166         /// </summary>
167         /// <returns>A security token service descriptor.</returns>
CreateSecurityTokenServiceDescriptorInstance()168         protected virtual SecurityTokenServiceDescriptor CreateSecurityTokenServiceDescriptorInstance()
169         {
170             return new SecurityTokenServiceDescriptor();
171         }
172 
173         /// <summary>
174         /// Creates an Spsso descriptor.
175         /// </summary>
176         /// <returns>An Spsso descriptor.</returns>
CreateServiceProviderSingleSignOnDescriptorInstance()177         protected virtual ServiceProviderSingleSignOnDescriptor CreateServiceProviderSingleSignOnDescriptorInstance()
178         {
179             return new ServiceProviderSingleSignOnDescriptor();
180         }
181 
182         /// <summary>
183         /// Returns the respective contact type from a string contact type.
184         /// </summary>
185         /// <param name="conactType">The string type.</param>
186         /// <param name="found">If found a match.</param>
187         /// <returns>The contact type.</returns>
GetContactPersonType(string conactType, out bool found)188         private static ContactType GetContactPersonType(string conactType, out bool found)
189         {
190             if (conactType == null)
191             {
192                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("conactType");
193             }
194             found = true;
195             if (StringComparer.Ordinal.Equals(conactType, "unspecified"))
196             {
197                 return ContactType.Unspecified;
198             }
199             else if (StringComparer.Ordinal.Equals(conactType, "administrative"))
200             {
201                 return ContactType.Administrative;
202             }
203             else if (StringComparer.Ordinal.Equals(conactType, "billing"))
204             {
205                 return ContactType.Billing;
206             }
207             else if (StringComparer.Ordinal.Equals(conactType, "other"))
208             {
209                 return ContactType.Other;
210             }
211             else if (StringComparer.Ordinal.Equals(conactType, "support"))
212             {
213                 return ContactType.Support;
214             }
215             else if (StringComparer.Ordinal.Equals(conactType, "technical"))
216             {
217                 return ContactType.Technical;
218             }
219             found = false;
220             return ContactType.Unspecified;
221 
222         }
223 
GetKeyDescriptorType(string keyType)224         private static KeyType GetKeyDescriptorType(string keyType)
225         {
226             if (keyType == null)
227             {
228                 return KeyType.Unspecified;
229             }
230             else if (StringComparer.Ordinal.Equals(keyType, "encryption"))
231             {
232                 return KeyType.Encryption;
233             }
234             else if (StringComparer.Ordinal.Equals(keyType, "signing"))
235             {
236                 return KeyType.Signing;
237             }
238 
239             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.Use, keyType)));
240         }
241 
242         /// <summary>
243         /// Reads application service descriptor.
244         /// </summary>
245         /// <param name="reader">Xml reader.</param>
246         /// <returns>An application service descriptor.</returns>
247         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadApplicationServiceDescriptor(XmlReader reader)248         protected virtual ApplicationServiceDescriptor ReadApplicationServiceDescriptor(XmlReader reader)
249         {
250             if (reader == null)
251             {
252                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
253             }
254 
255             ApplicationServiceDescriptor appService = CreateApplicationServiceInstance();
256             ReadWebServiceDescriptorAttributes(reader, appService);
257             ReadCustomAttributes<ApplicationServiceDescriptor>(reader, appService);
258 
259             bool isEmpty = reader.IsEmptyElement;
260             reader.ReadStartElement();
261             if (!isEmpty)
262             {
263                 while (reader.IsStartElement())
264                 {
265                     if (reader.IsStartElement(FederationMetadataConstants.Elements.ApplicationServiceEndpoint, FederationMetadataConstants.Namespace))
266                     {
267                         isEmpty = reader.IsEmptyElement;
268                         reader.ReadStartElement();
269                         if (!isEmpty && reader.IsStartElement())
270                         {
271                             EndpointReference address = EndpointReference.ReadFrom(reader);
272                             appService.Endpoints.Add(address);
273                             reader.ReadEndElement();
274                         }
275                     }
276                     else if (reader.IsStartElement(FederationMetadataConstants.Elements.PassiveRequestorEndpoint, FederationMetadataConstants.Namespace))
277                     {
278                         isEmpty = reader.IsEmptyElement;
279                         reader.ReadStartElement();
280                         if (!isEmpty && reader.IsStartElement())
281                         {
282                             EndpointReference address = EndpointReference.ReadFrom(reader);
283                             appService.PassiveRequestorEndpoints.Add(address);
284                             reader.ReadEndElement();
285                         }
286                     }
287                     else if (ReadWebServiceDescriptorElement(reader, appService))
288                     {
289                         // Do nothing
290                     }
291                     else if (ReadCustomElement<ApplicationServiceDescriptor>(reader, appService))
292                     {
293                         // Do nothing.
294                     }
295                     else
296                     {
297                         reader.Skip();
298                     }
299                 }
300 
301                 // SecurityTokenService
302                 reader.ReadEndElement();
303             }
304 
305             return appService;
306         }
307 
308         /// <summary>
309         /// Reads a contact person.
310         /// </summary>
311         /// <param name="reader">Xml reader.</param>
312         /// <returns>A contact person.</returns>
313         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadContactPerson(XmlReader reader)314         protected virtual ContactPerson ReadContactPerson(XmlReader reader)
315         {
316             if (reader == null)
317             {
318                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
319             }
320             ContactPerson person = CreateContactPersonInstance();
321 
322             string contactType = reader.GetAttribute(Saml2MetadataConstants.Attributes.ContactType, null);
323             bool foundKey = false;
324 
325             person.Type = GetContactPersonType(contactType, out foundKey);
326             if (!foundKey)
327             {
328                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3201, typeof(ContactType), contactType)));
329             }
330 
331             ReadCustomAttributes<ContactPerson>(reader, person);
332 
333             bool isEmpty = reader.IsEmptyElement;
334             reader.ReadStartElement(); // <ContactPerson>
335             if (!isEmpty)
336             {
337                 while (reader.IsStartElement())
338                 {
339                     if (reader.IsStartElement(Saml2MetadataConstants.Elements.Company, Saml2MetadataConstants.Namespace))
340                     {
341                         person.Company = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.Company, Saml2MetadataConstants.Namespace);
342                     }
343                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.GivenName, Saml2MetadataConstants.Namespace))
344                     {
345                         person.GivenName = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.GivenName, Saml2MetadataConstants.Namespace);
346                     }
347                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.Surname, Saml2MetadataConstants.Namespace))
348                     {
349                         person.Surname = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.Surname, Saml2MetadataConstants.Namespace);
350                     }
351                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.EmailAddress, Saml2MetadataConstants.Namespace))
352                     {
353                         string emailId = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.EmailAddress, Saml2MetadataConstants.Namespace);
354                         if (!String.IsNullOrEmpty(emailId))
355                         {
356                             person.EmailAddresses.Add(emailId);
357                         }
358                     }
359                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.TelephoneNumber, Saml2MetadataConstants.Namespace))
360                     {
361                         string phone = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.TelephoneNumber, Saml2MetadataConstants.Namespace);
362                         if (!String.IsNullOrEmpty(phone))
363                         {
364                             person.TelephoneNumbers.Add(phone);
365                         }
366                     }
367                     else if (ReadCustomElement<ContactPerson>(reader, person))
368                     {
369                         // Do nothing
370                     }
371                     else
372                     {
373                         reader.Skip();
374                     }
375 
376                 }
377                 reader.ReadEndElement(); // </ContactPerson>
378             }
379 
380             // No mandatory elements to be validated.
381             return person;
382         }
383 
384         /// <summary>
385         /// Extensibility point for reading custom attributes.
386         /// </summary>
387         /// <typeparam name="T">The type of element.</typeparam>
388         /// <param name="reader">Xml reader.</param>
389         /// <param name="target">An object of type T.</param>
ReadCustomAttributes(XmlReader reader, T target)390         protected virtual void ReadCustomAttributes<T>(XmlReader reader, T target)
391         {
392             // Extensibility point only. Do Nothing.
393         }
394 
395         /// <summary>
396         /// Extensibility point for reading custom elements. By default this returns false.
397         /// </summary>
398         /// <typeparam name="T">The type of element.</typeparam>
399         /// <param name="reader">Xml reader.</param>
400         /// <param name="target">An object of type T.</param>
401         /// <returns>True if an element of type T is read, else false.</returns>
ReadCustomElement(XmlReader reader, T target)402         protected virtual bool ReadCustomElement<T>(XmlReader reader, T target)
403         {
404             // Extensibility point only. Do Nothing.
405             return false;
406         }
407 
408         /// <summary>
409         /// Extensibility point for reading custom RoleDescriptors.
410         /// </summary>
411         /// <param name="xsiType">The xsi type</param>
412         /// <param name="reader">Xml reader</param>
413         /// <param name="entityDescriptor">The entity descriptor for adding the Role Descriptors</param>
ReadCustomRoleDescriptor(string xsiType, XmlReader reader, EntityDescriptor entityDescriptor)414         protected virtual void ReadCustomRoleDescriptor(string xsiType, XmlReader reader, EntityDescriptor entityDescriptor)
415         {
416             //
417             // Extensibility point: Based on the xsiType, overriden implementations have the ability to read the RoleDescriptor
418             // attributes from a (##other) namespace and add the Role Descriptors to the entityDescriptor
419             //
420             if (reader == null)
421             {
422                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
423             }
424 
425             TraceUtility.TraceString(System.Diagnostics.TraceEventType.Warning, SR.GetString(SR.ID3274, xsiType));
426             reader.Skip();
427         }
428 
429         /// <summary>
430         /// Returns the <see cref="DisplayClaim"/> from the <paramref name="reader"/>.
431         /// </summary>
432         /// <param name="reader">XML reader.</param>
433         /// <returns>The display claim.</returns>
434         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
435         /// <exception cref="MetadataSerializationException">Thrown if the XML is not well-formed.</exception>
ReadDisplayClaim(XmlReader reader)436         protected virtual DisplayClaim ReadDisplayClaim(XmlReader reader)
437         {
438             if (reader == null)
439             {
440                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
441             }
442 
443             //
444             // This is out of scope for extensibility.
445             //
446             string claimType = reader.GetAttribute(WSFederationMetadataConstants.Attributes.Uri, null);
447             if (!UriUtil.CanCreateValidUri(claimType, UriKind.Absolute))
448             {
449                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, WSAuthorizationConstants.Elements.ClaimType, claimType)));
450             }
451             DisplayClaim claim = new DisplayClaim(claimType);
452 
453             bool isOptional = true;
454             string optionalString = reader.GetAttribute(WSFederationMetadataConstants.Attributes.Optional);
455             if (!String.IsNullOrEmpty(optionalString))
456             {
457                 try
458                 {
459                     isOptional = XmlConvert.ToBoolean(optionalString.ToLowerInvariant());
460                 }
461                 catch (FormatException)
462                 {
463                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, WSFederationMetadataConstants.Attributes.Optional, optionalString)));
464                 }
465             }
466             claim.Optional = isOptional;
467 
468             bool isEmpty = reader.IsEmptyElement;
469             reader.ReadStartElement();
470             if (!isEmpty)
471             {
472                 while (reader.IsStartElement())
473                 {
474                     if (reader.IsStartElement(WSAuthorizationConstants.Elements.DisplayName, WSAuthorizationConstants.Namespace))
475                     {
476                         claim.DisplayTag = reader.ReadElementContentAsString(WSAuthorizationConstants.Elements.DisplayName, WSAuthorizationConstants.Namespace);
477                     }
478                     else if (reader.IsStartElement(WSAuthorizationConstants.Elements.Description, WSAuthorizationConstants.Namespace))
479                     {
480                         claim.Description = reader.ReadElementContentAsString(WSAuthorizationConstants.Elements.Description, WSAuthorizationConstants.Namespace);
481                     }
482                     else
483                     {
484                         // Move on
485                         reader.Skip();
486                     }
487                 }
488                 reader.ReadEndElement();
489             }
490             return claim;
491         }
492 
493         /// <summary>
494         /// Reads entities descriptor.
495         /// </summary>
496         /// <param name="reader">Xml reader.</param>
497         /// <param name="tokenResolver">The security token resolver.</param>
498         /// <returns>The entities descriptor.</returns>
499         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
500         /// <exception cref="MetadataSerializationException">Thrown if the XML is not well-formed.</exception>
ReadEntitiesDescriptor(XmlReader reader, SecurityTokenResolver tokenResolver)501         protected virtual EntitiesDescriptor ReadEntitiesDescriptor(XmlReader reader, SecurityTokenResolver tokenResolver)
502         {
503             if (reader == null)
504             {
505                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
506             }
507 
508             EntitiesDescriptor resultEntityGroup = CreateEntitiesDescriptorInstance();
509 
510             //
511             // There may be embedded signed XML elements. So we need to plumb the SecurityTokenSerializer and tokenResolver
512             //
513             EnvelopedSignatureReader envelopeReader = new EnvelopedSignatureReader(reader, SecurityTokenSerializer, tokenResolver, false, false, true);
514 
515             string name = envelopeReader.GetAttribute(Saml2MetadataConstants.Attributes.EntityGroupName, null);
516             if (!String.IsNullOrEmpty(name))
517             {
518                 resultEntityGroup.Name = name;
519             }
520 
521             ReadCustomAttributes<EntitiesDescriptor>(envelopeReader, resultEntityGroup);
522 
523             bool isEmpty = envelopeReader.IsEmptyElement;
524             envelopeReader.ReadStartElement(); // <EntitiesDescriptor>
525             if (!isEmpty)
526             {
527                 while (envelopeReader.IsStartElement())
528                 {
529                     if (envelopeReader.IsStartElement(Saml2MetadataConstants.Elements.EntityDescriptor, Saml2MetadataConstants.Namespace))
530                     {
531                         resultEntityGroup.ChildEntities.Add(ReadEntityDescriptor(envelopeReader, tokenResolver));
532                     }
533                     else if (envelopeReader.IsStartElement(Saml2MetadataConstants.Elements.EntitiesDescriptor, Saml2MetadataConstants.Namespace))
534                     {
535                         resultEntityGroup.ChildEntityGroups.Add(ReadEntitiesDescriptor(envelopeReader, tokenResolver));
536                     }
537                     else if (envelopeReader.TryReadSignature())
538                     {
539                         // Do nothng
540                     }
541                     else if (ReadCustomElement<EntitiesDescriptor>(envelopeReader, resultEntityGroup))
542                     {
543                         // Do nothing.
544                     }
545                     else
546                     {
547                         envelopeReader.Skip();
548                     }
549 
550                 }
551                 envelopeReader.ReadEndElement(); // </EntitiesDescriptor>
552             }
553 
554             resultEntityGroup.SigningCredentials = envelopeReader.SigningCredentials;
555 
556             if (resultEntityGroup.SigningCredentials != null)
557             {
558                 ValidateSigningCredential(resultEntityGroup.SigningCredentials);
559             }
560 
561             if (resultEntityGroup.ChildEntityGroups.Count == 0 && resultEntityGroup.ChildEntities.Count == 0)
562             {
563                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3200, Saml2MetadataConstants.Elements.EntityDescriptor)));
564             }
565             foreach (EntityDescriptor entity in resultEntityGroup.ChildEntities)
566             {
567                 if (!String.IsNullOrEmpty(entity.FederationId))
568                 {
569                     if (!StringComparer.Ordinal.Equals(entity.FederationId, resultEntityGroup.Name))
570                     {
571                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, WSFederationMetadataConstants.Attributes.FederationId, entity.FederationId)));
572                     }
573                 }
574             }
575             return resultEntityGroup;
576         }
577 
578         /// <summary>
579         /// Gets or sets the validation mode of the X509 certificate that is used to sign the metadata document.
580         /// </summary>
581         public X509CertificateValidationMode CertificateValidationMode
582         {
583             get;
584             set;
585         }
586 
587         /// <summary>
588         /// Gets or sets the revocation mode of the X509 certificate that is used to sign the metadata document.
589         /// </summary>
590         public X509RevocationMode RevocationMode
591         {
592             get;
593             set;
594         }
595 
596         /// <summary>
597         /// Gets or sets the trusted store location of the X509 certificate that is used to sign the metadata document.
598         /// </summary>
599         public StoreLocation TrustedStoreLocation
600         {
601             get;
602             set;
603         }
604 
605         /// <summary>
606         /// Gets or sets the certificate validator of the X509 certificate that is used to sign the metadata document.
607         /// </summary>
608         public X509CertificateValidator CertificateValidator
609         {
610             get;
611             set;
612         }
613 
614         /// <summary>
615         /// Gets the list of trusted issuer that this serializer instance trusts to sign the metadata docuemnt.
616         /// </summary>
617         public List<string> TrustedIssuers
618         {
619             get { return _trustedIssuers;  }
620         }
621 
622         /// <summary>
623         /// Validates the signing credential of the metadata document.
624         /// </summary>
625         /// <param name="signingCredentials">The signing credential used to sign the metadata document.</param>
626         /// <exception cref="ArgumentNullException">If <paramref name="signingCredentials"/> is null.</exception>
ValidateSigningCredential(SigningCredentials signingCredentials)627         protected virtual void ValidateSigningCredential(SigningCredentials signingCredentials)
628         {
629             if (signingCredentials == null)
630             {
631                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("signingCredentials");
632             }
633 
634             if (CertificateValidationMode != X509CertificateValidationMode.Custom)
635             {
636                 CertificateValidator = X509Util.CreateCertificateValidator(CertificateValidationMode, RevocationMode, TrustedStoreLocation);
637             }
638             else if (CertificateValidationMode == X509CertificateValidationMode.Custom && CertificateValidator == null)
639             {
640                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4280)));
641             }
642 
643             X509Certificate2 certificate = GetMetadataSigningCertificate(signingCredentials.SigningKeyIdentifier);
644 
645             ValidateIssuer(certificate);
646             CertificateValidator.Validate(certificate);
647         }
648 
649         /// <summary>
650         /// Validates the certificate that signed the metadata document against the TrustedIssuers. This method is invoked by the ValidateSigningCredential method.
651         /// By default, this method does not perform any validation. Provide your own implementation to perform trusted issuer validation.
652         /// </summary>
653         /// <param name="signingCertificate">The signing certificate.</param>
ValidateIssuer(X509Certificate2 signingCertificate)654         protected virtual void ValidateIssuer(X509Certificate2 signingCertificate)
655         {
656             // No-op by default.
657         }
658 
659         /// <summary>
660         /// Gets the <see cref="X509Certificate2"/> instance created from the <paramref name="ski"/>.
661         /// By default, this method only supports <see cref="X509RawDataKeyIdentifierClause"/>. Override this method
662         /// to support other key identifier clauses. This method is invoked by the ValidateSigningCredential method.
663         /// </summary>
664         /// <param name="ski">The security key identifier instance.</param>
665         /// <returns>An <see cref="X509Certificate2"/> instance.</returns>
GetMetadataSigningCertificate( SecurityKeyIdentifier ski )666         protected virtual X509Certificate2 GetMetadataSigningCertificate( SecurityKeyIdentifier ski )
667         {
668             if (ski == null)
669             {
670                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ski");
671             }
672 
673             X509RawDataKeyIdentifierClause clause = null;
674             if (ski.TryFind<X509RawDataKeyIdentifierClause>(out clause))
675             {
676                 return new X509Certificate2(clause.GetX509RawData());
677             }
678             else
679             {
680                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID8029)));
681             }
682         }
683 
684         /// <summary>
685         /// Reads an entity descriptor.
686         /// </summary>
687         /// <param name="inputReader">The xml reader.</param>
688         /// <param name="tokenResolver">The security token resolver.</param>
689         /// <returns>An entity descriptor.</returns>
690         /// <exception cref="ArgumentNullException">The parameter inputReader is null.</exception>
ReadEntityDescriptor(XmlReader inputReader, SecurityTokenResolver tokenResolver)691         protected virtual EntityDescriptor ReadEntityDescriptor(XmlReader inputReader, SecurityTokenResolver tokenResolver)
692         {
693             if (inputReader == null)
694             {
695                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inputReader");
696             }
697 
698             EntityDescriptor resultEntity = CreateEntityDescriptorInstance();
699 
700             //
701             // There may be embedded signed XML elements. So we need to plumb the SecurityTokenSerializer and tokenResolver
702             // IDFX
703 
704             EnvelopedSignatureReader reader = new EnvelopedSignatureReader(inputReader, SecurityTokenSerializer, tokenResolver, false, false, true);
705 
706             // EntityID is mandatory - relaxed as per FIP 9935
707             string entityId = reader.GetAttribute(Saml2MetadataConstants.Attributes.EntityId, null);
708             if (!String.IsNullOrEmpty(entityId))
709             {
710                 resultEntity.EntityId = new EntityId(entityId);
711             }
712 
713             // FederationID is optional
714             string fedId = reader.GetAttribute(WSFederationMetadataConstants.Attributes.FederationId, WSFederationMetadataConstants.Namespace);
715             if (!String.IsNullOrEmpty(fedId))
716             {
717                 resultEntity.FederationId = fedId;
718             }
719 
720             ReadCustomAttributes<EntityDescriptor>(reader, resultEntity);
721 
722             bool isEmpty = reader.IsEmptyElement;
723             reader.ReadStartElement();
724             if (!isEmpty)
725             {
726                 while (reader.IsStartElement())
727                 {
728                     if (reader.IsStartElement(Saml2MetadataConstants.Elements.SpssoDescriptor, Saml2MetadataConstants.Namespace))
729                     {
730                         resultEntity.RoleDescriptors.Add(ReadServiceProviderSingleSignOnDescriptor(reader));
731                     }
732                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.IdpssoDescriptor, Saml2MetadataConstants.Namespace))
733                     {
734                         resultEntity.RoleDescriptors.Add(ReadIdentityProviderSingleSignOnDescriptor(reader));
735                     }
736                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.RoleDescriptor, Saml2MetadataConstants.Namespace))
737                     {
738                         string xsiType = reader.GetAttribute("type", XmlSchema.InstanceNamespace);
739 
740                         if (!String.IsNullOrEmpty(xsiType))
741                         {
742                             int index = xsiType.IndexOf(":", 0, StringComparison.Ordinal);
743                             if (index < 0)
744                             {
745                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3207, "xsi:type", Saml2MetadataConstants.Elements.RoleDescriptor, xsiType)));
746                             }
747                             string prefix = xsiType.Substring(0, index);
748                             string ns = reader.LookupNamespace(prefix);
749 
750                             if (String.IsNullOrEmpty(ns))
751                             {
752                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, prefix, ns)));
753                             }
754                             else if (!StringComparer.Ordinal.Equals(ns, FederationMetadataConstants.Namespace))
755                             {
756                                 ReadCustomRoleDescriptor(xsiType, reader, resultEntity);
757                             }
758                             else if (StringComparer.Ordinal.Equals(xsiType, prefix + ":" + FederationMetadataConstants.Elements.ApplicationServiceType))
759                             {
760                                 resultEntity.RoleDescriptors.Add(ReadApplicationServiceDescriptor(reader));
761                             }
762                             else if (StringComparer.Ordinal.Equals(xsiType, prefix + ":" + FederationMetadataConstants.Elements.SecurityTokenServiceType))
763                             {
764                                 resultEntity.RoleDescriptors.Add(ReadSecurityTokenServiceDescriptor(reader));
765                             }
766                             else
767                             {
768                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3207, "xsi:type", Saml2MetadataConstants.Elements.RoleDescriptor, xsiType)));
769                             }
770                         }
771                         else
772                         {
773                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID0001, "xsi:type", Saml2MetadataConstants.Elements.RoleDescriptor)));
774                         }
775                     }
776                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.Organization, Saml2MetadataConstants.Namespace))
777                     {
778                         resultEntity.Organization = ReadOrganization(reader);
779                     }
780                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.ContactPerson, Saml2MetadataConstants.Namespace))
781                     {
782                         resultEntity.Contacts.Add(ReadContactPerson(reader));
783                     }
784                     else if (reader.TryReadSignature())
785                     {
786                         // Do nothing
787                     }
788                     else if (ReadCustomElement<EntityDescriptor>(reader, resultEntity))
789                     {
790                         // Do nothing.
791                     }
792                     else
793                     {
794                         reader.Skip();
795                     }
796                 }
797                 reader.ReadEndElement();
798             }
799 
800             resultEntity.SigningCredentials = reader.SigningCredentials;
801             if (resultEntity.SigningCredentials != null)
802             {
803                 ValidateSigningCredential(resultEntity.SigningCredentials);
804             }
805 
806             // Elements are optional. Mandatory attributes already validated.
807 
808             return resultEntity;
809         }
810 
811         /// <summary>
812         /// Reads an idpsso descriptor.
813         /// </summary>
814         /// <param name="reader">The xml reader.</param>
815         /// <returns>An idpsso descriptor.</returns>
816         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadIdentityProviderSingleSignOnDescriptor(XmlReader reader)817         protected virtual IdentityProviderSingleSignOnDescriptor ReadIdentityProviderSingleSignOnDescriptor(XmlReader reader)
818         {
819             if (reader == null)
820             {
821                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
822             }
823 
824             IdentityProviderSingleSignOnDescriptor idpssoDescriptor = CreateIdentityProviderSingleSignOnDescriptorInstance();
825             ReadSingleSignOnDescriptorAttributes(reader, idpssoDescriptor);
826             ReadCustomAttributes<IdentityProviderSingleSignOnDescriptor>(reader, idpssoDescriptor);
827 
828             string wantAuthnRequestSignedAttribute = reader.GetAttribute(Saml2MetadataConstants.Attributes.WantAuthenticationRequestsSigned);
829             if (!String.IsNullOrEmpty(wantAuthnRequestSignedAttribute))
830             {
831                 try
832                 {
833                     idpssoDescriptor.WantAuthenticationRequestsSigned = XmlConvert.ToBoolean(wantAuthnRequestSignedAttribute.ToLowerInvariant());
834                 }
835                 catch (FormatException)
836                 {
837                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(
838                         SR.ID3202, Saml2MetadataConstants.Attributes.WantAuthenticationRequestsSigned, wantAuthnRequestSignedAttribute)));
839                 }
840             }
841 
842             bool isEmpty = reader.IsEmptyElement;
843             reader.ReadStartElement();
844             if (!isEmpty)
845             {
846                 while (reader.IsStartElement())
847                 {
848                     if (reader.IsStartElement(Saml2MetadataConstants.Elements.SingleSignOnService, Saml2MetadataConstants.Namespace))
849                     {
850                         ProtocolEndpoint endpoint = ReadProtocolEndpoint(reader);
851 
852                         // Relaxed check for endpoint.ResponseLocation as per FIP 9935
853                         idpssoDescriptor.SingleSignOnServices.Add(endpoint);
854                     }
855                     else if (reader.IsStartElement(Saml2Constants.Elements.Attribute, Saml2Constants.Namespace))
856                     {
857                         idpssoDescriptor.SupportedAttributes.Add(ReadAttribute(reader));
858                     }
859                     else if (ReadSingleSignOnDescriptorElement(reader, idpssoDescriptor))
860                     {
861                         // Do nothing
862                     }
863                     else if (ReadCustomElement<IdentityProviderSingleSignOnDescriptor>(reader, idpssoDescriptor))
864                     {
865                         // Do nothing.
866                     }
867                     else
868                     {
869                         reader.Skip();
870                     }
871                 }
872                 reader.ReadEndElement();
873             }
874 
875             // Relaxed check for( idpssoDescriptor.SingleSignOnServices.Count == 0 ) as per FIP 9935
876             return idpssoDescriptor;
877         }
878 
879         /// <summary>
880         /// Reads an indexed endpoint.
881         /// </summary>
882         /// <param name="reader">The xml reader.</param>
883         /// <returns>An indexed endpoint.</returns>
884         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadIndexedProtocolEndpoint(XmlReader reader)885         protected virtual IndexedProtocolEndpoint ReadIndexedProtocolEndpoint(XmlReader reader)
886         {
887             if (reader == null)
888             {
889                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
890             }
891 
892             IndexedProtocolEndpoint endpoint = CreateIndexedProtocolEndpointInstance();
893 
894             string binding = reader.GetAttribute(Saml2MetadataConstants.Attributes.Binding, null);
895             Uri bindingUri;
896             if (!UriUtil.TryCreateValidUri(binding, UriKind.RelativeOrAbsolute, out bindingUri))
897             {
898                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.Binding, binding)));
899             }
900             endpoint.Binding = bindingUri;
901 
902             string location = reader.GetAttribute(Saml2MetadataConstants.Attributes.Location, null);
903             Uri locationUri;
904             if (!UriUtil.TryCreateValidUri(location, UriKind.RelativeOrAbsolute, out locationUri))
905             {
906                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.Location, location)));
907             }
908             endpoint.Location = locationUri;
909 
910             string indexStr = reader.GetAttribute(Saml2MetadataConstants.Attributes.EndpointIndex, null);
911             int index;
912             if (!Int32.TryParse(indexStr, out index))
913             {
914                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.EndpointIndex, indexStr)));
915             }
916             endpoint.Index = index;
917 
918             // responseLocation is optional
919             string responseLocation = reader.GetAttribute(Saml2MetadataConstants.Attributes.ResponseLocation, null);
920             if (!String.IsNullOrEmpty(responseLocation))
921             {
922                 Uri responseUri;
923                 if (!UriUtil.TryCreateValidUri(responseLocation, UriKind.RelativeOrAbsolute, out responseUri))
924                 {
925                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.ResponseLocation, responseLocation)));
926                 }
927                 endpoint.ResponseLocation = responseUri;
928             }
929 
930             // isDefault is optional
931             string isDefaultString = reader.GetAttribute(Saml2MetadataConstants.Attributes.EndpointIsDefault, null);
932             if (!String.IsNullOrEmpty(isDefaultString))
933             {
934                 try
935                 {
936                     endpoint.IsDefault = XmlConvert.ToBoolean(isDefaultString.ToLowerInvariant());
937                 }
938                 catch (FormatException)
939                 {
940                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.EndpointIsDefault, isDefaultString)));
941                 }
942             }
943 
944             ReadCustomAttributes<IndexedProtocolEndpoint>(reader, endpoint);
945 
946             bool isEmpty = reader.IsEmptyElement;
947             reader.ReadStartElement();
948             if (!isEmpty)
949             {
950                 while (reader.IsStartElement())
951                 {
952                     if (ReadCustomElement<IndexedProtocolEndpoint>(reader, endpoint))
953                     {
954                         // Do nothing.
955                     }
956                     else
957                     {
958                         // Move on
959                         reader.Skip();
960                     }
961                 }
962                 reader.ReadEndElement();
963             }
964 
965             // No elements to validate. Attributes are already validated
966             return endpoint;
967         }
968 
969         /// <summary>
970         /// Reads a key descriptor.
971         /// </summary>
972         /// <param name="reader">Xml reader.</param>
973         /// <returns>The key descriptor.</returns>
974         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadKeyDescriptor(XmlReader reader)975         protected virtual KeyDescriptor ReadKeyDescriptor(XmlReader reader)
976         {
977             if (reader == null)
978             {
979                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
980             }
981             KeyDescriptor resultKey = CreateKeyDescriptorInstance();
982 
983             // Use is optional
984             string use = reader.GetAttribute(Saml2MetadataConstants.Attributes.Use, null);
985             if (!String.IsNullOrEmpty(use))
986             {
987                 resultKey.Use = GetKeyDescriptorType(use);
988             }
989 
990             ReadCustomAttributes<KeyDescriptor>(reader, resultKey);
991 
992             bool isEmpty = reader.IsEmptyElement;
993             reader.ReadStartElement();
994             if (!isEmpty)
995             {
996                 while (reader.IsStartElement())
997                 {
998                     if (reader.IsStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace))
999                     {
1000                         resultKey.KeyInfo = SecurityTokenSerializer.ReadKeyIdentifier(reader);
1001                     }
1002                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.EncryptionMethod, Saml2MetadataConstants.Namespace))
1003                     {
1004                         // Read the required algorithm attribute - relaxed as per FIP 9935
1005                         string algorithm = reader.GetAttribute(Saml2MetadataConstants.Attributes.Algorithm);
1006                         if (!String.IsNullOrEmpty(algorithm) && UriUtil.CanCreateValidUri(algorithm, UriKind.Absolute))
1007                         {
1008                             resultKey.EncryptionMethods.Add(new EncryptionMethod(new Uri(algorithm)));
1009                         }
1010 
1011                         isEmpty = reader.IsEmptyElement;
1012                         reader.ReadStartElement(Saml2MetadataConstants.Elements.EncryptionMethod, Saml2MetadataConstants.Namespace);
1013                         if (!isEmpty)
1014                         {
1015                             while (reader.IsStartElement())
1016                             {
1017                                 if (ReadCustomElement<KeyDescriptor>(reader, resultKey))
1018                                 {
1019                                     // Do nothing for now
1020                                 }
1021                                 else
1022                                 {
1023                                     reader.Skip();
1024                                 }
1025                             }
1026                             reader.ReadEndElement();
1027                         }
1028                     }
1029                     else if (ReadCustomElement<KeyDescriptor>(reader, resultKey))
1030                     {
1031                         // Do nothing.
1032                     }
1033                     else
1034                     {
1035                         reader.Skip();
1036                     }
1037                 }
1038                 reader.ReadEndElement();
1039             }
1040 
1041             if (resultKey.KeyInfo == null)
1042             {
1043                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3200, XmlSignatureConstants.Elements.KeyInfo)));
1044             }
1045             return resultKey;
1046         }
1047 
1048         /// <summary>
1049         /// Reads a localized name.
1050         /// </summary>
1051         /// <param name="reader">The xml reader.</param>
1052         /// <returns>A localized name.</returns>
1053         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadLocalizedName(XmlReader reader)1054         protected virtual LocalizedName ReadLocalizedName(XmlReader reader)
1055         {
1056             if (reader == null)
1057             {
1058                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1059             }
1060 
1061             LocalizedName resultName = CreateLocalizedNameInstance();
1062 
1063             string lang = reader.GetAttribute(LanguageLocalName, LanguageNamespaceUri);
1064             try
1065             {
1066                 resultName.Language = CultureInfo.GetCultureInfo(lang);
1067             }
1068             catch (ArgumentNullException)
1069             {
1070                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, LanguageLocalName, "null")));
1071             }
1072             catch (ArgumentException)
1073             {
1074                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, LanguageLocalName, lang)));
1075             }
1076 
1077             ReadCustomAttributes<LocalizedName>(reader, resultName);
1078 
1079             bool isEmpty = reader.IsEmptyElement;
1080             string elementName = reader.Name;
1081             reader.ReadStartElement();
1082             if (!isEmpty)
1083             {
1084                 resultName.Name = reader.ReadContentAsString();
1085                 while (reader.IsStartElement())
1086                 {
1087                     if (ReadCustomElement<LocalizedName>(reader, resultName))
1088                     {
1089                         // Do nothing.
1090                     }
1091                     else
1092                     {
1093                         // Move on
1094                         reader.Skip();
1095                     }
1096                 }
1097                 reader.ReadEndElement();
1098             }
1099 
1100             if (String.IsNullOrEmpty(resultName.Name))
1101             {
1102                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3200, elementName)));
1103             }
1104             return resultName;
1105         }
1106 
1107         /// <summary>
1108         /// Reads a localized uri.
1109         /// </summary>
1110         /// <param name="reader">The xml reader.</param>
1111         /// <returns>A localized uri.</returns>
1112         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadLocalizedUri(XmlReader reader)1113         protected virtual LocalizedUri ReadLocalizedUri(XmlReader reader)
1114         {
1115             if (reader == null)
1116             {
1117                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1118             }
1119 
1120             LocalizedUri resultUri = CreateLocalizedUriInstance();
1121 
1122             string lang = reader.GetAttribute(LanguageLocalName, LanguageNamespaceUri);
1123             try
1124             {
1125                 resultUri.Language = CultureInfo.GetCultureInfo(lang);
1126             }
1127             catch (ArgumentNullException)
1128             {
1129                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, LanguageLocalName, "null")));
1130             }
1131             catch (ArgumentException)
1132             {
1133                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, LanguageLocalName, lang)));
1134             }
1135 
1136             ReadCustomAttributes<LocalizedUri>(reader, resultUri);
1137 
1138             bool isEmpty = reader.IsEmptyElement;
1139             string elementName = reader.Name;
1140             reader.ReadStartElement();
1141             if (!isEmpty)
1142             {
1143                 string uriContent = reader.ReadContentAsString();
1144                 Uri uri;
1145                 if (!UriUtil.TryCreateValidUri(uriContent, UriKind.RelativeOrAbsolute, out uri))
1146                 {
1147                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, elementName, uriContent)));
1148                 }
1149                 resultUri.Uri = uri;
1150                 while (reader.IsStartElement())
1151                 {
1152                     if (ReadCustomElement<LocalizedUri>(reader, resultUri))
1153                     {
1154                         // Do nothing.
1155                     }
1156                     else
1157                     {
1158                         reader.Skip();
1159                     }
1160                 }
1161                 reader.ReadEndElement();
1162             }
1163 
1164             if (resultUri.Uri == null)
1165             {
1166                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3200, elementName)));
1167             }
1168             return resultUri;
1169         }
1170 
1171         /// <summary>
1172         /// Reads the given stream to deserialize a FederationMetadata instance.
1173         /// </summary>
1174         /// <param name="stream">Stream to be read.</param>
1175         /// <returns>An FederationMetadata instance.</returns>
1176         /// <exception cref="ArgumentNullException">The parameter stream is null.</exception>
ReadMetadata(Stream stream)1177         public MetadataBase ReadMetadata(Stream stream)
1178         {
1179             if (stream == null)
1180             {
1181                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
1182             }
1183             XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max);
1184             return ReadMetadata(reader);
1185         }
1186 
1187         /// <summary>
1188         /// Read the given XmlReader to deserialize the FederationMetadata instance.
1189         /// </summary>
1190         /// <param name="reader">XmlReader to be read.</param>
1191         /// <returns>An FederationMetadata instance</returns>
ReadMetadata(XmlReader reader)1192         public MetadataBase ReadMetadata(XmlReader reader)
1193         {
1194             return ReadMetadata(reader, EmptySecurityTokenResolver.Instance);
1195         }
1196 
1197         /// <summary>
1198         /// Read the given XmlReader to deserialize the FederationMetadata instance.
1199         /// </summary>
1200         /// <param name="reader">XmlReader to be read.</param>
1201         /// <param name="tokenResolver">Token resolver to resolve the signature token.</param>
1202         /// <returns>An FederationMetadata instance.</returns>
1203         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadMetadata(XmlReader reader, SecurityTokenResolver tokenResolver)1204         public MetadataBase ReadMetadata(XmlReader reader, SecurityTokenResolver tokenResolver)
1205         {
1206             if (reader == null)
1207             {
1208                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1209             }
1210             if (tokenResolver == null)
1211             {
1212                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenResolver");
1213             }
1214             if (false == (reader is XmlDictionaryReader))
1215             {
1216                 reader = XmlDictionaryReader.CreateDictionaryReader(reader);
1217             }
1218 
1219             MetadataBase metadata = ReadMetadataCore(reader, tokenResolver);
1220             return metadata;
1221         }
1222 
1223         /// <summary>
1224         /// Reads metadata.
1225         /// </summary>
1226         /// <param name="reader">The xml reader.</param>
1227         /// <param name="tokenResolver">The security token resolver.</param>
1228         /// <returns>MetadataBase</returns>
1229         /// <exception cref="ArgumentNullException">The parameter reader or tokenReolver is null.</exception>
ReadMetadataCore(XmlReader reader, SecurityTokenResolver tokenResolver)1230         protected virtual MetadataBase ReadMetadataCore(XmlReader reader, SecurityTokenResolver tokenResolver)
1231         {
1232             if (reader == null)
1233             {
1234                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1235             }
1236             if (tokenResolver == null)
1237             {
1238                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenResolver");
1239             }
1240 
1241             MetadataBase metadataBase;
1242 
1243             if (reader.IsStartElement(Saml2MetadataConstants.Elements.EntitiesDescriptor, Saml2MetadataConstants.Namespace))
1244             {
1245                 metadataBase = ReadEntitiesDescriptor(reader, tokenResolver);
1246             }
1247             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.EntityDescriptor, Saml2MetadataConstants.Namespace))
1248             {
1249                 metadataBase = ReadEntityDescriptor(reader, tokenResolver);
1250             }
1251             else
1252             {
1253                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3260)));
1254             }
1255 
1256             return metadataBase;
1257         }
1258 
1259         /// <summary>
1260         /// Reads an organization.
1261         /// </summary>
1262         /// <param name="reader">The xml reader.</param>
1263         /// <returns>An organization.</returns>
1264         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadOrganization(XmlReader reader)1265         protected virtual Organization ReadOrganization(XmlReader reader)
1266         {
1267             if (reader == null)
1268             {
1269                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1270             }
1271             Organization resultOrg = CreateOrganizationInstance();
1272 
1273             ReadCustomAttributes<Organization>(reader, resultOrg);
1274 
1275             bool isEmpty = reader.IsEmptyElement;
1276             reader.ReadStartElement();
1277             if (!isEmpty)
1278             {
1279                 while (reader.IsStartElement())
1280                 {
1281                     if (reader.IsStartElement(Saml2MetadataConstants.Elements.OrganizationName, Saml2MetadataConstants.Namespace))
1282                     {
1283                         resultOrg.Names.Add(ReadLocalizedName(reader));
1284                     }
1285                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.OrganizationDisplayName, Saml2MetadataConstants.Namespace))
1286                     {
1287                         resultOrg.DisplayNames.Add(ReadLocalizedName(reader));
1288                     }
1289                     else if (reader.IsStartElement(Saml2MetadataConstants.Elements.OrganizationUrl, Saml2MetadataConstants.Namespace))
1290                     {
1291                         resultOrg.Urls.Add(ReadLocalizedUri(reader));
1292                     }
1293                     else if (ReadCustomElement<Organization>(reader, resultOrg))
1294                     {
1295                         // Do nothing.
1296                     }
1297                     else
1298                     {
1299                         reader.Skip();
1300                     }
1301                 }
1302                 reader.ReadEndElement();
1303             }
1304 
1305             // Relaxed as per FIP 9935
1306             // if ( resultOrg.DisplayNames.Count < 1 )
1307             // if ( resultOrg.Names.Count < 1 )
1308             // if ( resultOrg.Urls.Count < 1 )
1309 
1310             return resultOrg;
1311         }
1312 
1313         /// <summary>
1314         /// Reads an endpoint.
1315         /// </summary>
1316         /// <param name="reader">Xml reader.</param>
1317         /// <returns>An endpoint.</returns>
1318         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadProtocolEndpoint(XmlReader reader)1319         protected virtual ProtocolEndpoint ReadProtocolEndpoint(XmlReader reader)
1320         {
1321             if (reader == null)
1322             {
1323                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1324             }
1325 
1326             ProtocolEndpoint endpoint = CreateProtocolEndpointInstance();
1327 
1328             string binding = reader.GetAttribute(Saml2MetadataConstants.Attributes.Binding, null);
1329             Uri bindingUri;
1330             if (!UriUtil.TryCreateValidUri(binding, UriKind.RelativeOrAbsolute, out bindingUri))
1331             {
1332                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.Binding, binding)));
1333             }
1334             endpoint.Binding = bindingUri;
1335 
1336             string location = reader.GetAttribute(Saml2MetadataConstants.Attributes.Location, null);
1337             Uri locationUri;
1338             if (!UriUtil.TryCreateValidUri(location, UriKind.RelativeOrAbsolute, out locationUri))
1339             {
1340                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.Location, location)));
1341             }
1342             endpoint.Location = locationUri;
1343 
1344             string responseLocation = reader.GetAttribute(Saml2MetadataConstants.Attributes.ResponseLocation, null);
1345             if (!String.IsNullOrEmpty(responseLocation))
1346             {
1347                 Uri responseUri;
1348                 if (!UriUtil.TryCreateValidUri(responseLocation, UriKind.RelativeOrAbsolute, out responseUri))
1349                 {
1350                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.ResponseLocation, responseLocation)));
1351                 }
1352                 endpoint.ResponseLocation = responseUri;
1353             }
1354 
1355             ReadCustomAttributes<ProtocolEndpoint>(reader, endpoint);
1356 
1357             bool isEmpty = reader.IsEmptyElement;
1358             reader.ReadStartElement(); // <Endpoint>
1359             if (!isEmpty)
1360             {
1361                 while (reader.IsStartElement())
1362                 {
1363                     if (!ReadCustomElement<ProtocolEndpoint>(reader, endpoint))
1364                     {
1365                         // Move on
1366                         reader.Skip();
1367                     }
1368                 }
1369                 reader.ReadEndElement(); // </Endpoint>
1370             }
1371 
1372             return endpoint;
1373         }
1374 
1375         /// <summary>
1376         /// Reads role descriptor attributes.
1377         /// </summary>
1378         /// <param name="reader">The xml reader</param>
1379         /// <param name="roleDescriptor">The role descriptor.</param>
1380         /// <exception cref="ArgumentNullException">The parameter reader/roleDescriptor/roleDescriptor.ProtocolsSupported is null.</exception>
ReadRoleDescriptorAttributes(XmlReader reader, RoleDescriptor roleDescriptor)1381         protected virtual void ReadRoleDescriptorAttributes(XmlReader reader, RoleDescriptor roleDescriptor)
1382         {
1383             if (reader == null)
1384             {
1385                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1386             }
1387             if (roleDescriptor == null)
1388             {
1389                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
1390             }
1391             if (roleDescriptor.ProtocolsSupported == null)
1392             {
1393                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.ProtocolsSupported");
1394             }
1395 
1396             // Optional
1397             string validUntilString = reader.GetAttribute(Saml2MetadataConstants.Attributes.ValidUntil, null);
1398             if (!String.IsNullOrEmpty(validUntilString))
1399             {
1400                 DateTime validUntil;
1401                 if (!DateTime.TryParse(validUntilString, out validUntil))
1402                 {
1403                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.ValidUntil, validUntilString)));
1404                 }
1405                 roleDescriptor.ValidUntil = validUntil;
1406             }
1407 
1408             // Optional
1409             string errorUrlString = reader.GetAttribute(Saml2MetadataConstants.Attributes.ErrorUrl, null);
1410             if (!string.IsNullOrEmpty(errorUrlString))
1411             {
1412                 Uri errorUrl;
1413                 if (!UriUtil.TryCreateValidUri(errorUrlString, UriKind.RelativeOrAbsolute, out errorUrl))
1414                 {
1415                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.ErrorUrl, errorUrlString)));
1416                 }
1417                 roleDescriptor.ErrorUrl = errorUrl;
1418             }
1419 
1420             // Mandatory
1421             string protocols = reader.GetAttribute(Saml2MetadataConstants.Attributes.ProtocolsSupported, null);
1422             if (String.IsNullOrEmpty(protocols))
1423             {
1424                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, Saml2MetadataConstants.Attributes.ProtocolsSupported, protocols)));
1425             }
1426             foreach (string protocol in protocols.Split(' '))
1427             {
1428                 string toAdd = protocol.Trim();
1429                 if (!String.IsNullOrEmpty(toAdd))
1430                 {
1431                     roleDescriptor.ProtocolsSupported.Add(new Uri(toAdd));
1432                 }
1433             }
1434             ReadCustomAttributes<RoleDescriptor>(reader, roleDescriptor);
1435         }
1436 
1437         /// <summary>
1438         /// Reads role descriptor element.
1439         /// </summary>
1440         /// <param name="reader">The xml reader.</param>
1441         /// <param name="roleDescriptor">The role descriptor.</param>
1442         /// <returns>True if read.</returns>
1443         /// <exception cref="ArgumentNullException">The parameter reader/roleDescriptor/roleDescriptor.Contacts/rolDescriptor.Keys is null.</exception>
ReadRoleDescriptorElement(XmlReader reader, RoleDescriptor roleDescriptor)1444         protected virtual bool ReadRoleDescriptorElement(XmlReader reader, RoleDescriptor roleDescriptor)
1445         {
1446             if (reader == null)
1447             {
1448                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1449             }
1450             if (roleDescriptor == null)
1451             {
1452                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
1453             }
1454             if (roleDescriptor.Contacts == null)
1455             {
1456                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.Contacts");
1457             }
1458             if (roleDescriptor.Keys == null)
1459             {
1460                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.Keys");
1461             }
1462 
1463             if (reader.IsStartElement(Saml2MetadataConstants.Elements.Organization, Saml2MetadataConstants.Namespace))
1464             {
1465                 roleDescriptor.Organization = ReadOrganization(reader);
1466                 return true;
1467             }
1468             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.KeyDescriptor, Saml2MetadataConstants.Namespace))
1469             {
1470                 roleDescriptor.Keys.Add(ReadKeyDescriptor(reader));
1471                 return true;
1472             }
1473             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.ContactPerson, Saml2MetadataConstants.Namespace))
1474             {
1475                 roleDescriptor.Contacts.Add(ReadContactPerson(reader));
1476                 return true;
1477             }
1478             else
1479             {
1480                 return ReadCustomElement<RoleDescriptor>(reader, roleDescriptor);
1481             }
1482 
1483             // No mandatory elements. No validations
1484         }
1485 
1486         /// <summary>
1487         /// Reads security token service descriptor.
1488         /// </summary>
1489         /// <param name="reader">The xml reader.</param>
1490         /// <returns>A security token service descriptor.</returns>
1491         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
ReadSecurityTokenServiceDescriptor(XmlReader reader)1492         protected virtual SecurityTokenServiceDescriptor ReadSecurityTokenServiceDescriptor(XmlReader reader)
1493         {
1494             if (reader == null)
1495             {
1496                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1497             }
1498 
1499             SecurityTokenServiceDescriptor securityTokenServiceDescriptor = CreateSecurityTokenServiceDescriptorInstance();
1500             ReadWebServiceDescriptorAttributes(reader, securityTokenServiceDescriptor);
1501             ReadCustomAttributes<SecurityTokenServiceDescriptor>(reader, securityTokenServiceDescriptor);
1502 
1503             bool isEmpty = reader.IsEmptyElement;
1504             reader.ReadStartElement();
1505             if (!isEmpty)
1506             {
1507                 while (reader.IsStartElement())
1508                 {
1509                     if (reader.IsStartElement(FederationMetadataConstants.Elements.SecurityTokenServiceEndpoint, FederationMetadataConstants.Namespace))
1510                     {
1511                         isEmpty = reader.IsEmptyElement;
1512                         reader.ReadStartElement();
1513                         if (!isEmpty && reader.IsStartElement())
1514                         {
1515                             EndpointReference address = EndpointReference.ReadFrom(reader);
1516                             securityTokenServiceDescriptor.SecurityTokenServiceEndpoints.Add(address);
1517                             reader.ReadEndElement();
1518                         }
1519                     }
1520                     else if (reader.IsStartElement(FederationMetadataConstants.Elements.PassiveRequestorEndpoint, FederationMetadataConstants.Namespace))
1521                     {
1522                         isEmpty = reader.IsEmptyElement;
1523                         reader.ReadStartElement();
1524                         if (!isEmpty && reader.IsStartElement())
1525                         {
1526                             EndpointReference address = EndpointReference.ReadFrom(reader);
1527                             securityTokenServiceDescriptor.PassiveRequestorEndpoints.Add(address);
1528                             reader.ReadEndElement();
1529                         }
1530                     }
1531                     else if (ReadWebServiceDescriptorElement(reader, securityTokenServiceDescriptor))
1532                     {
1533                         // Do nothing
1534                     }
1535                     else if (ReadCustomElement<SecurityTokenServiceDescriptor>(reader, securityTokenServiceDescriptor))
1536                     {
1537                         // Do nothing.
1538                     }
1539                     else
1540                     {
1541                         reader.Skip();
1542                     }
1543                 }
1544 
1545                 reader.ReadEndElement(); // SecurityTokenService
1546             }
1547 
1548             // Relaxed as per FIP 9935
1549             // if ( securityTokenServiceDescriptor.SecurityTokenServiceEndpoints.Count == 0 )
1550 
1551             return securityTokenServiceDescriptor;
1552         }
1553 
1554         /// <summary>
1555         /// Reads spsso descriptor.
1556         /// </summary>
1557         /// <param name="reader">The xml reader.</param>
1558         /// <returns>An spsso descriptor.</returns>
1559         /// <exception cref="ArgumentNullException">The parameter reader is null.</exception>
1560         /// <exception cref="MetadataSerializationException">The XML was invalid.</exception>
ReadServiceProviderSingleSignOnDescriptor(XmlReader reader)1561         protected virtual ServiceProviderSingleSignOnDescriptor ReadServiceProviderSingleSignOnDescriptor(XmlReader reader)
1562         {
1563             if (reader == null)
1564             {
1565                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1566             }
1567 
1568             ServiceProviderSingleSignOnDescriptor spssoDescriptor = CreateServiceProviderSingleSignOnDescriptorInstance();
1569 
1570             string authnRequestsSignedAttribute = reader.GetAttribute(Saml2MetadataConstants.Attributes.AuthenticationRequestsSigned);
1571             if (!String.IsNullOrEmpty(authnRequestsSignedAttribute))
1572             {
1573                 try
1574                 {
1575                     spssoDescriptor.AuthenticationRequestsSigned = XmlConvert.ToBoolean(authnRequestsSignedAttribute.ToLowerInvariant());
1576                 }
1577                 catch (FormatException)
1578                 {
1579                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(
1580                         SR.ID3202, Saml2MetadataConstants.Attributes.AuthenticationRequestsSigned, authnRequestsSignedAttribute)));
1581                 }
1582             }
1583 
1584             string wantAssertionsSignedAttribute = reader.GetAttribute(Saml2MetadataConstants.Attributes.WantAssertionsSigned);
1585             if (!String.IsNullOrEmpty(wantAssertionsSignedAttribute))
1586             {
1587                 try
1588                 {
1589                     spssoDescriptor.WantAssertionsSigned = XmlConvert.ToBoolean(wantAssertionsSignedAttribute.ToLowerInvariant());
1590                 }
1591                 catch (FormatException)
1592                 {
1593                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(
1594                         SR.ID3202, Saml2MetadataConstants.Attributes.WantAssertionsSigned, wantAssertionsSignedAttribute)));
1595                 }
1596             }
1597 
1598             ReadSingleSignOnDescriptorAttributes(reader, spssoDescriptor);
1599             ReadCustomAttributes<ServiceProviderSingleSignOnDescriptor>(reader, spssoDescriptor);
1600 
1601             bool isEmpty = reader.IsEmptyElement;
1602             reader.ReadStartElement();
1603             if (!isEmpty)
1604             {
1605                 while (reader.IsStartElement())
1606                 {
1607                     if (reader.IsStartElement(Saml2MetadataConstants.Elements.AssertionConsumerService, Saml2MetadataConstants.Namespace))
1608                     {
1609                         IndexedProtocolEndpoint endpoint = ReadIndexedProtocolEndpoint(reader);
1610                         spssoDescriptor.AssertionConsumerServices.Add(endpoint.Index, endpoint);
1611                     }
1612                     else if (ReadSingleSignOnDescriptorElement(reader, spssoDescriptor))
1613                     {
1614                         // Do nothing
1615                     }
1616                     else if (ReadCustomElement<ServiceProviderSingleSignOnDescriptor>(reader, spssoDescriptor))
1617                     {
1618                         // Do nothing.
1619                     }
1620                     else
1621                     {
1622                         reader.Skip();
1623                     }
1624                 }
1625 
1626                 reader.ReadEndElement(); // SPSSODescriptor
1627             }
1628 
1629             // Relaxed as per FIP 9935
1630             // if ( spssoDescriptor.AssertionConsumerService.Count == 0 )
1631 
1632             return spssoDescriptor;
1633         }
1634 
1635         /// <summary>
1636         /// Reads sso descriptor attributes.
1637         /// </summary>
1638         /// <param name="reader">The xml reader.</param>
1639         /// <param name="roleDescriptor">The sso role descriptor.</param>
ReadSingleSignOnDescriptorAttributes(XmlReader reader, SingleSignOnDescriptor roleDescriptor)1640         protected virtual void ReadSingleSignOnDescriptorAttributes(XmlReader reader, SingleSignOnDescriptor roleDescriptor)
1641         {
1642             ReadRoleDescriptorAttributes(reader, roleDescriptor);
1643             ReadCustomAttributes<SingleSignOnDescriptor>(reader, roleDescriptor);
1644         }
1645 
1646         /// <summary>
1647         /// Reads sso descriptor element.
1648         /// </summary>
1649         /// <param name="reader">The xml reader.</param>
1650         /// <param name="singleSignOnDescriptor">The sso descriptor.</param>
1651         /// <returns>True if read.</returns>
ReadSingleSignOnDescriptorElement(XmlReader reader, SingleSignOnDescriptor singleSignOnDescriptor)1652         protected virtual bool ReadSingleSignOnDescriptorElement(XmlReader reader, SingleSignOnDescriptor singleSignOnDescriptor)
1653         {
1654             if (reader == null)
1655             {
1656                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1657             }
1658             if (singleSignOnDescriptor == null)
1659             {
1660                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ssoDescriptor");
1661             }
1662 
1663             if (ReadRoleDescriptorElement(reader, singleSignOnDescriptor))
1664             {
1665                 return true;
1666             }
1667             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.ArtifactResolutionService, Saml2MetadataConstants.Namespace))
1668             {
1669                 IndexedProtocolEndpoint endpoint = ReadIndexedProtocolEndpoint(reader);
1670 
1671                 // Relaxed check for endpoint.ResponseLocation != null as per FIP 9935
1672                 singleSignOnDescriptor.ArtifactResolutionServices.Add(endpoint.Index, endpoint);
1673                 return true;
1674             }
1675             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.SingleLogoutService, Saml2MetadataConstants.Namespace))
1676             {
1677                 singleSignOnDescriptor.SingleLogoutServices.Add(ReadProtocolEndpoint(reader));
1678                 return true;
1679             }
1680             else if (reader.IsStartElement(Saml2MetadataConstants.Elements.NameIDFormat, Saml2MetadataConstants.Namespace))
1681             {
1682                 string nameId = reader.ReadElementContentAsString(Saml2MetadataConstants.Elements.NameIDFormat, Saml2MetadataConstants.Namespace);
1683                 if (!UriUtil.CanCreateValidUri(nameId, UriKind.Absolute))
1684                 {
1685                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID0014, Saml2MetadataConstants.Elements.NameIDFormat)));
1686                 }
1687                 singleSignOnDescriptor.NameIdentifierFormats.Add(new Uri(nameId));
1688                 return true;
1689             }
1690             else
1691             {
1692                 return ReadCustomElement<SingleSignOnDescriptor>(reader, singleSignOnDescriptor);
1693             }
1694         }
1695 
1696         /// <summary>
1697         /// Reads web service descriptor attributes.
1698         /// </summary>
1699         /// <param name="reader">The xml reader.</param>
1700         /// <param name="roleDescriptor">The web service descriptor.</param>
1701         /// <exception cref="ArgumentNullException">The parameter reader/roleDescriptor is null.</exception>
ReadWebServiceDescriptorAttributes(XmlReader reader, WebServiceDescriptor roleDescriptor)1702         protected virtual void ReadWebServiceDescriptorAttributes(XmlReader reader, WebServiceDescriptor roleDescriptor)
1703         {
1704             if (reader == null)
1705             {
1706                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1707             }
1708             if (roleDescriptor == null)
1709             {
1710                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
1711             }
1712 
1713             ReadRoleDescriptorAttributes(reader, roleDescriptor);
1714             string displayName = reader.GetAttribute(Saml2MetadataConstants.Attributes.ServiceDisplayName, null);
1715             if (!String.IsNullOrEmpty(displayName))
1716             {
1717                 roleDescriptor.ServiceDisplayName = displayName;
1718             }
1719             string description = reader.GetAttribute(Saml2MetadataConstants.Attributes.ServiceDescription, null);
1720             if (!String.IsNullOrEmpty(description))
1721             {
1722                 roleDescriptor.ServiceDescription = description;
1723             }
1724             ReadCustomAttributes<WebServiceDescriptor>(reader, roleDescriptor);
1725 
1726             // All optional no validations
1727         }
1728 
1729         /// <summary>
1730         /// Reads web service descriptor element.
1731         /// </summary>
1732         /// <param name="reader">The xml reader.</param>
1733         /// <param name="roleDescriptor">The web service descriptor.</param>
1734         /// <returns>True if read.</returns>
1735         /// <exception cref="ArgumentNullException">The parameter reader/roleDescriptor/roleDescriptor.TargetScopes/roleDescriptor.TargetScopes/roleDescriptor.TokenTypesOffered
1736         /// is null.</exception>
ReadWebServiceDescriptorElement(XmlReader reader, WebServiceDescriptor roleDescriptor)1737         public virtual bool ReadWebServiceDescriptorElement(XmlReader reader, WebServiceDescriptor roleDescriptor)
1738         {
1739             if (reader == null)
1740             {
1741                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1742             }
1743             if (roleDescriptor == null)
1744             {
1745                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
1746             }
1747             if (roleDescriptor.TargetScopes == null)
1748             {
1749                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.TargetScopes");
1750             }
1751             if (roleDescriptor.ClaimTypesOffered == null)
1752             {
1753                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.TargetScopes");
1754             }
1755             if (roleDescriptor.TokenTypesOffered == null)
1756             {
1757                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.TokenTypesOffered");
1758             }
1759 
1760             if (ReadRoleDescriptorElement(reader, roleDescriptor))
1761             {
1762                 return true;
1763             }
1764             else if (reader.IsStartElement(FederationMetadataConstants.Elements.TargetScopes, FederationMetadataConstants.Namespace))
1765             {
1766                 bool isEmpty = reader.IsEmptyElement;
1767                 reader.ReadStartElement();
1768                 if (!isEmpty)
1769                 {
1770                     while (reader.IsStartElement())
1771                     {
1772                         roleDescriptor.TargetScopes.Add(EndpointReference.ReadFrom(reader));
1773                     }
1774 
1775                     reader.ReadEndElement();
1776                 }
1777 
1778                 return true;
1779             }
1780             else if (reader.IsStartElement(FederationMetadataConstants.Elements.ClaimTypesOffered, FederationMetadataConstants.Namespace))
1781             {
1782                 bool isEmpty = reader.IsEmptyElement;
1783                 reader.ReadStartElement();
1784                 if (!isEmpty)
1785                 {
1786                     while (reader.IsStartElement())
1787                     {
1788                         if (reader.IsStartElement(WSAuthorizationConstants.Elements.ClaimType, WSAuthorizationConstants.Namespace))
1789                         {
1790                             roleDescriptor.ClaimTypesOffered.Add(ReadDisplayClaim(reader));
1791                         }
1792                         else
1793                         {
1794                             // Move on
1795                             reader.Skip();
1796                         }
1797                     }
1798 
1799                     reader.ReadEndElement();
1800                 }
1801 
1802                 return true;
1803             }
1804             else if (reader.IsStartElement(FederationMetadataConstants.Elements.ClaimTypesRequested, FederationMetadataConstants.Namespace))
1805             {
1806                 bool isEmpty = reader.IsEmptyElement;
1807                 reader.ReadStartElement();
1808                 if (!isEmpty)
1809                 {
1810                     while (reader.IsStartElement())
1811                     {
1812                         if (reader.IsStartElement(WSAuthorizationConstants.Elements.ClaimType, WSAuthorizationConstants.Namespace))
1813                         {
1814                             roleDescriptor.ClaimTypesRequested.Add(ReadDisplayClaim(reader));
1815                         }
1816                         else
1817                         {
1818                             // Move on
1819                             reader.Skip();
1820                         }
1821                     }
1822 
1823                     reader.ReadEndElement();
1824                 }
1825 
1826                 return true;
1827             }
1828             else if (reader.IsStartElement(FederationMetadataConstants.Elements.TokenTypesOffered, FederationMetadataConstants.Namespace))
1829             {
1830                 bool isEmpty = reader.IsEmptyElement;
1831                 reader.ReadStartElement(FederationMetadataConstants.Elements.TokenTypesOffered, FederationMetadataConstants.Namespace);
1832 
1833                 if (!isEmpty)
1834                 {
1835                     while (reader.IsStartElement())
1836                     {
1837                         if (reader.IsStartElement(WSFederationMetadataConstants.Elements.TokenType, WSFederationMetadataConstants.Namespace))
1838                         {
1839                             string tokenType = reader.GetAttribute(WSFederationMetadataConstants.Attributes.Uri, null);
1840                             Uri tokenTypeUri;
1841                             if (!UriUtil.TryCreateValidUri(tokenType, UriKind.Absolute, out tokenTypeUri))
1842                             {
1843                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3202, WSFederationMetadataConstants.Elements.TokenType, tokenType)));
1844                             }
1845 
1846                             roleDescriptor.TokenTypesOffered.Add(tokenTypeUri);
1847 
1848                             isEmpty = reader.IsEmptyElement;
1849                             reader.ReadStartElement(); // TokenType
1850                             if (!isEmpty)
1851                             {
1852                                 reader.ReadEndElement(); // TokenType
1853                             }
1854                         }
1855                         else
1856                         {
1857                             reader.Skip();
1858                         }
1859                     }
1860 
1861                     reader.ReadEndElement(); // TokenTypeOffered
1862                 }
1863                 return true;
1864             }
1865             else
1866             {
1867                 return ReadCustomElement<WebServiceDescriptor>(reader, roleDescriptor);
1868             }
1869 
1870             // All optional. No Validations needed
1871         }
1872 
1873         /// <summary>
1874         /// Gets the SecurityTokenSerializer that this instance is using to serializer
1875         /// SecurityTokens.
1876         /// </summary>
1877         public SecurityTokenSerializer SecurityTokenSerializer
1878         {
1879             get
1880             {
1881                 return _tokenSerializer;
1882             }
1883         }
1884 
1885         /// <summary>
1886         /// Writes an application service descriptor.
1887         /// </summary>
1888         /// <param name="writer">The xml writer.</param>
1889         /// <param name="appService">The application service descriptor.</param>
1890         /// <exception cref="ArgumentNullException">The parameter writer/appService/appService.Endpoint/aappService.PassiveRequestorEndpoints is null.</exception>
WriteApplicationServiceDescriptor(XmlWriter writer, ApplicationServiceDescriptor appService)1891         protected virtual void WriteApplicationServiceDescriptor(XmlWriter writer, ApplicationServiceDescriptor appService)
1892         {
1893             if (writer == null)
1894             {
1895                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
1896             }
1897 
1898             if (appService == null)
1899             {
1900                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("appService");
1901             }
1902 
1903             if (appService.Endpoints == null)
1904             {
1905                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("appService.Endpoints");
1906             }
1907 
1908             if (appService.PassiveRequestorEndpoints == null)
1909             {
1910                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("appService.PassiveRequestorEndpoints");
1911             }
1912 
1913             writer.WriteStartElement(Saml2MetadataConstants.Elements.RoleDescriptor, Saml2MetadataConstants.Namespace);
1914             writer.WriteAttributeString("xsi", "type", XmlSchema.InstanceNamespace, FederationMetadataConstants.Prefix + ":" + FederationMetadataConstants.Elements.ApplicationServiceType);
1915 
1916             writer.WriteAttributeString("xmlns", FederationMetadataConstants.Prefix, null, FederationMetadataConstants.Namespace);
1917 
1918             WriteWebServiceDescriptorAttributes(writer, appService);
1919             WriteCustomAttributes<ApplicationServiceDescriptor>(writer, appService);
1920 
1921             WriteWebServiceDescriptorElements(writer, appService);
1922 
1923             // Optional ApplicationServiceEndpoints
1924             foreach (EndpointReference epr in appService.Endpoints)
1925             {
1926                 writer.WriteStartElement(FederationMetadataConstants.Elements.ApplicationServiceEndpoint, FederationMetadataConstants.Namespace);
1927                 epr.WriteTo(writer);
1928                 writer.WriteEndElement();
1929             }
1930 
1931             // Optional PassiveRequestorEndpoints
1932             foreach (EndpointReference epr in appService.PassiveRequestorEndpoints)
1933             {
1934                 writer.WriteStartElement(FederationMetadataConstants.Elements.PassiveRequestorEndpoint, FederationMetadataConstants.Namespace);
1935                 epr.WriteTo(writer);
1936                 writer.WriteEndElement();
1937             }
1938 
1939             WriteCustomElements<ApplicationServiceDescriptor>(writer, appService);
1940 
1941             writer.WriteEndElement();
1942         }
1943 
1944         /// <summary>
1945         /// Writes a contact person.
1946         /// </summary>
1947         /// <param name="writer">The xml writer.</param>
1948         /// <param name="contactPerson">The contact person.</param>
1949         /// <exception cref="ArgumentNullException">The parameter writer/contactPerson/contactPerson.EmaillAddresses/contactPerson.TelephoneNumbers is null.</exception>
WriteContactPerson(XmlWriter writer, ContactPerson contactPerson)1950         protected virtual void WriteContactPerson(XmlWriter writer, ContactPerson contactPerson)
1951         {
1952             if (writer == null)
1953             {
1954                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
1955             }
1956 
1957             if (contactPerson == null)
1958             {
1959                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contactPerson");
1960             }
1961 
1962             if (contactPerson.EmailAddresses == null)
1963             {
1964                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contactPerson.EmailAddresses");
1965             }
1966 
1967             if (contactPerson.TelephoneNumbers == null)
1968             {
1969                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contactPerson.TelephoneNumbers");
1970             }
1971 
1972             writer.WriteStartElement(Saml2MetadataConstants.Elements.ContactPerson, Saml2MetadataConstants.Namespace);
1973             if (contactPerson.Type == ContactType.Unspecified)
1974             {
1975                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.ContactType)));
1976             }
1977 
1978             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ContactType, null, contactPerson.Type.ToString().ToLowerInvariant());
1979 
1980             WriteCustomAttributes<ContactPerson>(writer, contactPerson);
1981 
1982             if (!String.IsNullOrEmpty(contactPerson.Company))
1983             {
1984                 writer.WriteElementString(Saml2MetadataConstants.Elements.Company, Saml2MetadataConstants.Namespace, contactPerson.Company);
1985             }
1986 
1987             if (!String.IsNullOrEmpty(contactPerson.GivenName))
1988             {
1989                 writer.WriteElementString(Saml2MetadataConstants.Elements.GivenName, Saml2MetadataConstants.Namespace, contactPerson.GivenName);
1990             }
1991 
1992             if (!String.IsNullOrEmpty(contactPerson.Surname))
1993             {
1994                 writer.WriteElementString(Saml2MetadataConstants.Elements.Surname, Saml2MetadataConstants.Namespace, contactPerson.Surname);
1995             }
1996 
1997             foreach (string email in contactPerson.EmailAddresses)
1998             {
1999                 writer.WriteElementString(Saml2MetadataConstants.Elements.EmailAddress, Saml2MetadataConstants.Namespace, email);
2000             }
2001 
2002             foreach (string phone in contactPerson.TelephoneNumbers)
2003             {
2004                 writer.WriteElementString(Saml2MetadataConstants.Elements.TelephoneNumber, Saml2MetadataConstants.Namespace, phone);
2005             }
2006 
2007             WriteCustomElements<ContactPerson>(writer, contactPerson);
2008 
2009             writer.WriteEndElement();
2010         }
2011 
2012         /// <summary>
2013         /// Extensible point to write custom attributes.
2014         /// </summary>
2015         /// <typeparam name="T">The type of the element whose attribute is being written</typeparam>
2016         /// <param name="writer">The xml writer.</param>
2017         /// <param name="source">The source element of type T.</param>
WriteCustomAttributes(XmlWriter writer, T source)2018         protected virtual void WriteCustomAttributes<T>(XmlWriter writer, T source)
2019         {
2020             // Extensibility point only. Do Nothing.
2021         }
2022 
2023         /// <summary>
2024         /// Extensible point to write custom elements.
2025         /// </summary>
2026         /// <typeparam name="T">The type of element being written.</typeparam>
2027         /// <param name="writer">The xml writer.</param>
2028         /// <param name="source">The source element of type T.</param>
WriteCustomElements(XmlWriter writer, T source)2029         protected virtual void WriteCustomElements<T>(XmlWriter writer, T source)
2030         {
2031             // Extensibility point only. Do Nothing.
2032         }
2033 
2034         /// <summary>
2035         /// Writes an endpoint.
2036         /// </summary>
2037         /// <param name="writer">The xml writer.</param>
2038         /// <param name="endpoint">The endpoint.</param>
2039         /// <param name="element">The xml qualified name element.</param>
2040         /// <exception cref="ArgumentNullException">The parameter writer/endpoint/element is null.</exception>
WriteProtocolEndpoint(XmlWriter writer, ProtocolEndpoint endpoint, XmlQualifiedName element)2041         protected virtual void WriteProtocolEndpoint(XmlWriter writer, ProtocolEndpoint endpoint, XmlQualifiedName element)
2042         {
2043             if (writer == null)
2044             {
2045                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2046             }
2047 
2048             if (endpoint == null)
2049             {
2050                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
2051             }
2052 
2053             if (element == null)
2054             {
2055                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
2056             }
2057 
2058             writer.WriteStartElement(element.Name, element.Namespace);
2059             if (endpoint.Binding == null)
2060             {
2061                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.Binding)));
2062             }
2063 
2064             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Binding, null, (endpoint.Binding.IsAbsoluteUri ? endpoint.Binding.AbsoluteUri : endpoint.Binding.ToString()));
2065 
2066             if (endpoint.Location == null)
2067             {
2068                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.Location)));
2069             }
2070 
2071             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Location, null, (endpoint.Location.IsAbsoluteUri ? endpoint.Location.AbsoluteUri : endpoint.Location.ToString()));
2072 
2073             if (endpoint.ResponseLocation != null)
2074             {
2075                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ResponseLocation, null, (endpoint.ResponseLocation.IsAbsoluteUri ? endpoint.ResponseLocation.AbsoluteUri : endpoint.ResponseLocation.ToString()));
2076             }
2077 
2078             WriteCustomAttributes<ProtocolEndpoint>(writer, endpoint);
2079 
2080             WriteCustomElements<ProtocolEndpoint>(writer, endpoint);
2081             writer.WriteEndElement();
2082         }
2083 
2084         /// <summary>
2085         /// Writes entities descriptor.
2086         /// </summary>
2087         /// <param name="writer">The <see cref="XmlWriter"/> to use.</param>
2088         /// <param name="claim">The <see cref="DisplayClaim"/> to write.</param>
WriteDisplayClaim(XmlWriter writer, DisplayClaim claim)2089         protected virtual void WriteDisplayClaim(XmlWriter writer, DisplayClaim claim)
2090         {
2091             // This is not extensible since it is defined in a different spec.
2092             writer.WriteStartElement(WSAuthorizationConstants.Prefix, WSAuthorizationConstants.Elements.ClaimType, WSAuthorizationConstants.Namespace);
2093 
2094             // ClaimType is mandatory
2095             if (String.IsNullOrEmpty(claim.ClaimType))
2096             {
2097                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, WSAuthorizationConstants.Elements.ClaimType)));
2098             }
2099 
2100             if (!UriUtil.CanCreateValidUri(claim.ClaimType, UriKind.Absolute))
2101             {
2102                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID0014, claim.ClaimType)));
2103             }
2104 
2105             writer.WriteAttributeString(WSFederationMetadataConstants.Attributes.Uri, claim.ClaimType);
2106 
2107             if (claim.WriteOptionalAttribute)
2108             {
2109                 writer.WriteAttributeString(WSFederationMetadataConstants.Attributes.Optional, XmlConvert.ToString(claim.Optional));
2110             }
2111 
2112             if (!String.IsNullOrEmpty(claim.DisplayTag))
2113             {
2114                 writer.WriteElementString(WSAuthorizationConstants.Prefix, WSAuthorizationConstants.Elements.DisplayName, WSAuthorizationConstants.Namespace, claim.DisplayTag);
2115             }
2116 
2117             if (!String.IsNullOrEmpty(claim.Description))
2118             {
2119                 writer.WriteElementString(WSAuthorizationConstants.Prefix, WSAuthorizationConstants.Elements.Description, WSAuthorizationConstants.Namespace, claim.Description);
2120             }
2121 
2122             writer.WriteEndElement(); // ClaimType
2123         }
2124 
2125         /// <summary>
2126         /// Writes entities descriptor.
2127         /// </summary>
2128         /// <param name="inputWriter">The <see cref="XmlWriter"/> to use.</param>
2129         /// <param name="entitiesDescriptor">The entities descriptor.</param>
2130         /// <exception cref="ArgumentNullException">The parameter inputWriter/entitiesDescriptor/entitiesDescriptor.ChildEntities/entitiesDescriptor.ChildEntityGroups
2131         /// is null.</exception>
WriteEntitiesDescriptor(XmlWriter inputWriter, EntitiesDescriptor entitiesDescriptor)2132         protected virtual void WriteEntitiesDescriptor(XmlWriter inputWriter, EntitiesDescriptor entitiesDescriptor)
2133         {
2134             if (inputWriter == null)
2135             {
2136                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inputWriter");
2137             }
2138 
2139             if (entitiesDescriptor == null)
2140             {
2141                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entitiesDescriptor");
2142             }
2143 
2144             if (entitiesDescriptor.ChildEntities == null)
2145             {
2146                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entitiesDescriptor.ChildEntities");
2147             }
2148 
2149             if (entitiesDescriptor.ChildEntityGroups == null)
2150             {
2151                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entitiesDescriptor.ChildEntityGroups");
2152             }
2153 
2154             string entityReference = "_" + Guid.NewGuid().ToString();
2155             XmlWriter writer = inputWriter;
2156             EnvelopedSignatureWriter signedWriter = null;
2157             if (entitiesDescriptor.SigningCredentials != null)
2158             {
2159                 signedWriter = new EnvelopedSignatureWriter(inputWriter, entitiesDescriptor.SigningCredentials, entityReference, SecurityTokenSerializer);
2160                 writer = signedWriter;
2161             }
2162 
2163             writer.WriteStartElement(Saml2MetadataConstants.Elements.EntitiesDescriptor, Saml2MetadataConstants.Namespace);
2164             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Id, null, entityReference);
2165 
2166             if (entitiesDescriptor.ChildEntities.Count == 0 && entitiesDescriptor.ChildEntityGroups.Count == 0)
2167             {
2168                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.EntitiesDescriptor)));
2169             }
2170 
2171             // Ensure FederationID in all children are valid.
2172             foreach (EntityDescriptor entity in entitiesDescriptor.ChildEntities)
2173             {
2174                 if (!String.IsNullOrEmpty(entity.FederationId))
2175                 {
2176                     if (!StringComparer.Ordinal.Equals(entity.FederationId, entitiesDescriptor.Name))
2177                     {
2178                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, WSFederationMetadataConstants.Attributes.FederationId)));
2179                     }
2180                 }
2181             }
2182 
2183             if (!String.IsNullOrEmpty(entitiesDescriptor.Name))
2184             {
2185                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.EntityGroupName, null, entitiesDescriptor.Name);
2186             }
2187 
2188             WriteCustomAttributes<EntitiesDescriptor>(writer, entitiesDescriptor);
2189 
2190             // WriteSamlMetadataBaseElements?
2191 
2192             if (null != signedWriter)
2193             {
2194                 // Write the signature at the top of the sequence
2195                 signedWriter.WriteSignature();
2196             }
2197 
2198             foreach (EntityDescriptor entity in entitiesDescriptor.ChildEntities)
2199             {
2200                 WriteEntityDescriptor(writer, entity);
2201             }
2202 
2203             foreach (EntitiesDescriptor entityGroup in entitiesDescriptor.ChildEntityGroups)
2204             {
2205                 WriteEntitiesDescriptor(writer, entityGroup);
2206             }
2207 
2208             WriteCustomElements<EntitiesDescriptor>(writer, entitiesDescriptor);
2209 
2210             writer.WriteEndElement(); // EntitiesDescriptor
2211         }
2212 
2213         /// <summary>
2214         /// Writes an entity descriptor.
2215         /// </summary>
2216         /// <param name="inputWriter">The xml writer.</param>
2217         /// <param name="entityDescriptor">The entity descriptor.</param>
2218         /// <exception cref="ArgumentNullException">The parameter inputWriter/entityDescriptor/entityDescriptor.Contacts/entityDescriptor.RoleDescriptors is null.</exception>
WriteEntityDescriptor(XmlWriter inputWriter, EntityDescriptor entityDescriptor)2219         protected virtual void WriteEntityDescriptor(XmlWriter inputWriter, EntityDescriptor entityDescriptor)
2220         {
2221             if (inputWriter == null)
2222             {
2223                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inputWriter");
2224             }
2225 
2226             if (entityDescriptor == null)
2227             {
2228                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entityDescriptor");
2229             }
2230 
2231             if (entityDescriptor.Contacts == null)
2232             {
2233                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entityDescriptor.Contacts");
2234             }
2235 
2236             if (entityDescriptor.RoleDescriptors == null)
2237             {
2238                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("entityDescriptor.RoleDescriptors");
2239             }
2240 
2241             string entityReference = "_" + Guid.NewGuid().ToString();
2242             XmlWriter writer = inputWriter;
2243             EnvelopedSignatureWriter signedWriter = null;
2244             if (entityDescriptor.SigningCredentials != null)
2245             {
2246                 signedWriter = new EnvelopedSignatureWriter(inputWriter, entityDescriptor.SigningCredentials, entityReference, SecurityTokenSerializer);
2247                 writer = signedWriter;
2248             }
2249 
2250             writer.WriteStartElement(Saml2MetadataConstants.Elements.EntityDescriptor, Saml2MetadataConstants.Namespace);
2251             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Id, null, entityReference);
2252 
2253             if (entityDescriptor.EntityId == null || entityDescriptor.EntityId.Id == null)
2254             {
2255                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.EntityId)));
2256             }
2257 
2258             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.EntityId, null, entityDescriptor.EntityId.Id);
2259 
2260             if (!String.IsNullOrEmpty(entityDescriptor.FederationId))
2261             {
2262                 writer.WriteAttributeString(WSFederationMetadataConstants.Attributes.FederationId, WSFederationMetadataConstants.Namespace, entityDescriptor.FederationId);
2263             }
2264 
2265             WriteCustomAttributes<EntityDescriptor>(writer, entityDescriptor);
2266 
2267             if (null != signedWriter)
2268             {
2269                 // Write the signature at the top of the sequence
2270                 signedWriter.WriteSignature();
2271             }
2272 
2273             if (entityDescriptor.RoleDescriptors.Count == 0)
2274             {
2275                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.RoleDescriptor)));
2276             }
2277 
2278             foreach (RoleDescriptor roleDescriptor in entityDescriptor.RoleDescriptors)
2279             {
2280                 ServiceProviderSingleSignOnDescriptor spDesc = roleDescriptor as ServiceProviderSingleSignOnDescriptor;
2281                 if (spDesc != null)
2282                 {
2283                     WriteServiceProviderSingleSignOnDescriptor(writer, spDesc);
2284                 }
2285 
2286                 IdentityProviderSingleSignOnDescriptor idpDesc = roleDescriptor as IdentityProviderSingleSignOnDescriptor;
2287                 if (idpDesc != null)
2288                 {
2289                     WriteIdentityProviderSingleSignOnDescriptor(writer, idpDesc);
2290                 }
2291 
2292                 ApplicationServiceDescriptor appService = roleDescriptor as ApplicationServiceDescriptor;
2293                 if (appService != null)
2294                 {
2295                     WriteApplicationServiceDescriptor(writer, appService);
2296                 }
2297 
2298                 SecurityTokenServiceDescriptor stsService = roleDescriptor as SecurityTokenServiceDescriptor;
2299                 if (stsService != null)
2300                 {
2301                     WriteSecurityTokenServiceDescriptor(writer, stsService);
2302                 }
2303             }
2304 
2305             if (entityDescriptor.Organization != null)
2306             {
2307                 WriteOrganization(writer, entityDescriptor.Organization);
2308             }
2309 
2310             foreach (ContactPerson person in entityDescriptor.Contacts)
2311             {
2312                 WriteContactPerson(writer, person);
2313             }
2314 
2315             WriteCustomElements<EntityDescriptor>(writer, entityDescriptor);
2316 
2317             writer.WriteEndElement(); // EntityDescriptor
2318         }
2319 
2320         /// <summary>
2321         /// Writes an idpsso descriptor.
2322         /// </summary>
2323         /// <param name="writer">The xml writer.</param>
2324         /// <param name="identityProviderSingleSignOnDescriptor">The idpsso descriptor.</param>
2325         /// <exception cref="ArgumentNullException">The parameter writer/idpssoDescriptor/idpssoDescriptor.SupportedAttributes/idpssoDescriptor.SingleSignOnServices
2326         /// is null.</exception>
WriteIdentityProviderSingleSignOnDescriptor(XmlWriter writer, IdentityProviderSingleSignOnDescriptor identityProviderSingleSignOnDescriptor)2327         protected virtual void WriteIdentityProviderSingleSignOnDescriptor(XmlWriter writer, IdentityProviderSingleSignOnDescriptor identityProviderSingleSignOnDescriptor)
2328         {
2329             if (writer == null)
2330             {
2331                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2332             }
2333 
2334             if (identityProviderSingleSignOnDescriptor == null)
2335             {
2336                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("idpssoDescriptor");
2337             }
2338 
2339             if (identityProviderSingleSignOnDescriptor.SupportedAttributes == null)
2340             {
2341                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("idpssoDescriptor.SupportedAttributes");
2342             }
2343 
2344             if (identityProviderSingleSignOnDescriptor.SingleSignOnServices == null)
2345             {
2346                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("idpssoDescriptor.SingleSignOnServices");
2347             }
2348 
2349             writer.WriteStartElement(Saml2MetadataConstants.Elements.IdpssoDescriptor, Saml2MetadataConstants.Namespace);
2350             if (identityProviderSingleSignOnDescriptor.WantAuthenticationRequestsSigned)
2351             {
2352                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.WantAuthenticationRequestsSigned, null,
2353                     XmlConvert.ToString(identityProviderSingleSignOnDescriptor.WantAuthenticationRequestsSigned));
2354             }
2355 
2356             WriteSingleSignOnDescriptorAttributes(writer, identityProviderSingleSignOnDescriptor);
2357             WriteCustomAttributes<IdentityProviderSingleSignOnDescriptor>(writer, identityProviderSingleSignOnDescriptor);
2358 
2359             WriteSingleSignOnDescriptorElements(writer, identityProviderSingleSignOnDescriptor);
2360 
2361             // Mandatory SingleSignonServiceEndpoint
2362             if (identityProviderSingleSignOnDescriptor.SingleSignOnServices.Count == 0)
2363             {
2364                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.SingleSignOnService)));
2365             }
2366 
2367             foreach (ProtocolEndpoint endpoint in identityProviderSingleSignOnDescriptor.SingleSignOnServices)
2368             {
2369                 if (endpoint.ResponseLocation != null)
2370                 {
2371                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3249, Saml2MetadataConstants.Attributes.ResponseLocation)));
2372                 }
2373 
2374                 XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.SingleSignOnService, Saml2MetadataConstants.Namespace);
2375                 WriteProtocolEndpoint(writer, endpoint, element);
2376             }
2377 
2378             // Optional SupportedAttributes
2379             foreach (Saml2Attribute attribute in identityProviderSingleSignOnDescriptor.SupportedAttributes)
2380             {
2381                 WriteAttribute(writer, attribute);
2382             }
2383 
2384             WriteCustomElements<IdentityProviderSingleSignOnDescriptor>(writer, identityProviderSingleSignOnDescriptor);
2385 
2386             writer.WriteEndElement();
2387         }
2388 
2389         /// <summary>
2390         /// Writes an indexed endpoint.
2391         /// </summary>
2392         /// <param name="writer">The xml writer.</param>
2393         /// <param name="indexedEP">The indexed endpoint.</param>
2394         /// <param name="element">The xml qualified element.</param>
2395         /// <exception cref="ArgumentNullException">The parameter writer/indexedEP/element is null.</exception>
WriteIndexedProtocolEndpoint(XmlWriter writer, IndexedProtocolEndpoint indexedEP, XmlQualifiedName element)2396         protected virtual void WriteIndexedProtocolEndpoint(XmlWriter writer, IndexedProtocolEndpoint indexedEP, XmlQualifiedName element)
2397         {
2398             if (writer == null)
2399             {
2400                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2401             }
2402 
2403             if (indexedEP == null)
2404             {
2405                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("indexedEP");
2406             }
2407 
2408             if (element == null)
2409             {
2410                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
2411             }
2412 
2413             writer.WriteStartElement(element.Name, element.Namespace);
2414             if (indexedEP.Binding == null)
2415             {
2416                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.Binding)));
2417             }
2418 
2419             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Binding, null, (indexedEP.Binding.IsAbsoluteUri ? indexedEP.Binding.AbsoluteUri : indexedEP.Binding.ToString()));
2420 
2421             if (indexedEP.Location == null)
2422             {
2423                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.Location)));
2424             }
2425 
2426             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Location, null, (indexedEP.Location.IsAbsoluteUri ? indexedEP.Location.AbsoluteUri : indexedEP.Location.ToString()));
2427 
2428             if (indexedEP.Index < 0)
2429             {
2430                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.EndpointIndex)));
2431             }
2432 
2433             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.EndpointIndex, null, indexedEP.Index.ToString(CultureInfo.InvariantCulture));
2434 
2435             if (indexedEP.ResponseLocation != null)
2436             {
2437                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ResponseLocation, null, (indexedEP.ResponseLocation.IsAbsoluteUri ? indexedEP.ResponseLocation.AbsoluteUri : indexedEP.ResponseLocation.ToString()));
2438             }
2439 
2440             if (indexedEP.IsDefault.HasValue)
2441             {
2442                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.EndpointIsDefault, null, XmlConvert.ToString(indexedEP.IsDefault.Value));
2443             }
2444 
2445             WriteCustomAttributes<IndexedProtocolEndpoint>(writer, indexedEP);
2446             WriteCustomElements<IndexedProtocolEndpoint>(writer, indexedEP);
2447             writer.WriteEndElement();
2448         }
2449 
2450         /// <summary>
2451         /// Writes a key descriptor.
2452         /// </summary>
2453         /// <param name="writer">The xml writer.</param>
2454         /// <param name="keyDescriptor">The key descriptor.</param>
2455         /// <exception cref="ArgumentNullException">The parameter writer/keyDescriptor is null.</exception>
WriteKeyDescriptor(XmlWriter writer, KeyDescriptor keyDescriptor)2456         protected virtual void WriteKeyDescriptor(XmlWriter writer, KeyDescriptor keyDescriptor)
2457         {
2458             if (writer == null)
2459             {
2460                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2461             }
2462 
2463             if (keyDescriptor == null)
2464             {
2465                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("keyDescriptor");
2466             }
2467 
2468             writer.WriteStartElement(Saml2MetadataConstants.Elements.KeyDescriptor, Saml2MetadataConstants.Namespace);
2469             if (keyDescriptor.Use == KeyType.Encryption || keyDescriptor.Use == KeyType.Signing)
2470             {
2471                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Use, null, keyDescriptor.Use.ToString().ToLowerInvariant());
2472             }
2473 
2474             WriteCustomAttributes<KeyDescriptor>(writer, keyDescriptor);
2475 
2476             if (keyDescriptor.KeyInfo == null)
2477             {
2478                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, XmlSignatureConstants.Elements.KeyInfo)));
2479             }
2480 
2481             SecurityTokenSerializer.WriteKeyIdentifier(writer, keyDescriptor.KeyInfo);
2482 
2483             // Write the encryption method element.
2484             if (keyDescriptor.EncryptionMethods != null && keyDescriptor.EncryptionMethods.Count > 0)
2485             {
2486                 foreach (EncryptionMethod encryptionMethod in keyDescriptor.EncryptionMethods)
2487                 {
2488                     if (encryptionMethod.Algorithm == null)
2489                     {
2490                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.Algorithm)));
2491                     }
2492 
2493                     if (!encryptionMethod.Algorithm.IsAbsoluteUri)
2494                     {
2495                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID0014, Saml2MetadataConstants.Attributes.Algorithm)));
2496                     }
2497 
2498                     writer.WriteStartElement(Saml2MetadataConstants.Elements.EncryptionMethod, Saml2MetadataConstants.Namespace);
2499                     writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Algorithm, null, encryptionMethod.Algorithm.AbsoluteUri);
2500                     writer.WriteEndElement();
2501                 }
2502             }
2503 
2504             WriteCustomElements<KeyDescriptor>(writer, keyDescriptor);
2505             writer.WriteEndElement();
2506         }
2507 
2508         /// <summary>
2509         /// Writes a localized name.
2510         /// </summary>
2511         /// <param name="writer">The xml writer.</param>
2512         /// <param name="name">The localized name.</param>
2513         /// <param name="element">The xml qualified name.</param>
2514         /// <exception cref="ArgumentNullException">The parameter writer/name/element/name.Name is null.</exception>
WriteLocalizedName(XmlWriter writer, LocalizedName name, XmlQualifiedName element)2515         protected virtual void WriteLocalizedName(XmlWriter writer, LocalizedName name, XmlQualifiedName element)
2516         {
2517             if (writer == null)
2518             {
2519                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2520             }
2521 
2522             if (name == null)
2523             {
2524                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name");
2525             }
2526 
2527             if (element == null)
2528             {
2529                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
2530             }
2531 
2532             if (name.Name == null)
2533             {
2534                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name.Name");
2535             }
2536 
2537             writer.WriteStartElement(element.Name, element.Namespace);
2538             if (name.Language == null || String.IsNullOrEmpty(name.Name))
2539             {
2540                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, LanguageLocalName)));
2541             }
2542 
2543             writer.WriteAttributeString(LanguagePrefix, LanguageLocalName, LanguageNamespaceUri, name.Language.Name);
2544             WriteCustomAttributes<LocalizedName>(writer, name);
2545             writer.WriteString(name.Name);
2546             WriteCustomElements<LocalizedName>(writer, name);
2547             writer.WriteEndElement();
2548         }
2549 
2550         /// <summary>
2551         /// Writes localized uri
2552         /// </summary>
2553         /// <param name="writer">The xml writer.</param>
2554         /// <param name="uri">The localized uri.</param>
2555         /// <param name="element">The xml qualified name.</param>
2556         /// <exception cref="ArgumentNullException">The parameter writer/uri/element is null.</exception>
WriteLocalizedUri(XmlWriter writer, LocalizedUri uri, XmlQualifiedName element)2557         protected virtual void WriteLocalizedUri(XmlWriter writer, LocalizedUri uri, XmlQualifiedName element)
2558         {
2559             if (writer == null)
2560             {
2561                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2562             }
2563 
2564             if (uri == null)
2565             {
2566                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("uri");
2567             }
2568 
2569             if (element == null)
2570             {
2571                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
2572             }
2573 
2574             writer.WriteStartElement(element.Name, element.Namespace);
2575             if (uri.Language == null || uri.Uri == null)
2576             {
2577                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, LanguageLocalName)));
2578             }
2579 
2580             writer.WriteAttributeString(LanguagePrefix, LanguageLocalName, LanguageNamespaceUri, uri.Language.Name);
2581             WriteCustomAttributes<LocalizedUri>(writer, uri);
2582             writer.WriteString(uri.Uri.IsAbsoluteUri ? uri.Uri.AbsoluteUri : uri.Uri.ToString());
2583             WriteCustomElements<LocalizedUri>(writer, uri);
2584             writer.WriteEndElement();
2585         }
2586 
2587         /// <summary>
2588         /// Writes the federation metadata to the given stream.
2589         /// </summary>
2590         /// <param name="stream">Stream to write the Federation Metadata.</param>
2591         /// <param name="metadata">Metadata to write.</param>
2592         /// <exception cref="ArgumentNullException">The input argument is null.</exception>
WriteMetadata(Stream stream, MetadataBase metadata)2593         public void WriteMetadata(Stream stream, MetadataBase metadata)
2594         {
2595             if (stream == null)
2596             {
2597                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
2598             }
2599 
2600             if (metadata == null)
2601             {
2602                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("metadata");
2603             }
2604 
2605             using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
2606             {
2607                 WriteMetadata(writer, metadata);
2608             }
2609         }
2610 
2611         /// <summary>
2612         /// Writes the federation metadata to the given writer.
2613         /// </summary>
2614         /// <param name="writer">Writer to which to write the federation Metadata</param>
2615         /// <param name="metadata">Metadata to write.</param>
2616         /// <exception cref="ArgumentNullException">The input argument is null.</exception>
WriteMetadata(XmlWriter writer, MetadataBase metadata)2617         public void WriteMetadata(XmlWriter writer, MetadataBase metadata)
2618         {
2619             if (writer == null)
2620             {
2621                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2622             }
2623 
2624             if (metadata == null)
2625             {
2626                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("metadata");
2627             }
2628 
2629             WriteMetadataCore(writer, metadata);
2630         }
2631 
2632         /// <summary>
2633         /// Writes the metadata.
2634         /// </summary>
2635         /// <param name="writer">The xml writer.</param>
2636         /// <param name="metadataBase">The saml metadat base.</param>
2637         /// <exception cref="ArgumentNullException">The parameter writer/metadataBase is null.</exception>
WriteMetadataCore(XmlWriter writer, MetadataBase metadataBase)2638         protected virtual void WriteMetadataCore(XmlWriter writer, MetadataBase metadataBase)
2639         {
2640             if (writer == null)
2641             {
2642                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2643             }
2644 
2645             if (metadataBase == null)
2646             {
2647                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("metadataBase");
2648             }
2649 
2650             EntitiesDescriptor entitiesDescriptor = metadataBase as EntitiesDescriptor;
2651             if (entitiesDescriptor != null)
2652             {
2653                 WriteEntitiesDescriptor(writer, entitiesDescriptor);
2654             }
2655             else
2656             {
2657                 EntityDescriptor entityDescriptor = metadataBase as EntityDescriptor;
2658                 if (entityDescriptor == null)
2659                 {
2660                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.EntitiesDescriptor)));
2661                 }
2662 
2663                 WriteEntityDescriptor(writer, entityDescriptor);
2664             }
2665         }
2666 
2667         /// <summary>
2668         /// Writes an organization.
2669         /// </summary>
2670         /// <param name="writer">The xml writer.</param>
2671         /// <param name="organization">The organization.</param>
2672         /// <exception cref="ArgumentNullException">The parameter writer/organization is null.</exception>
WriteOrganization(XmlWriter writer, Organization organization)2673         protected virtual void WriteOrganization(XmlWriter writer, Organization organization)
2674         {
2675             if (writer == null)
2676             {
2677                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2678             }
2679 
2680             if (organization == null)
2681             {
2682                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("organization");
2683             }
2684 
2685             if (organization.DisplayNames == null)
2686             {
2687                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("organization.DisplayNames");
2688             }
2689 
2690             if (organization.Names == null)
2691             {
2692                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("organization.Names");
2693             }
2694 
2695             if (organization.Urls == null)
2696             {
2697                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("organization.Urls");
2698             }
2699 
2700             writer.WriteStartElement(Saml2MetadataConstants.Elements.Organization, Saml2MetadataConstants.Namespace);
2701 
2702             if (organization.Names.Count < 1)
2703             {
2704                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.OrganizationName)));
2705             }
2706 
2707             foreach (LocalizedName name in organization.Names)
2708             {
2709                 XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.OrganizationName, Saml2MetadataConstants.Namespace);
2710                 WriteLocalizedName(writer, name, element);
2711             }
2712 
2713             if (organization.DisplayNames.Count < 1)
2714             {
2715                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.OrganizationDisplayName)));
2716             }
2717 
2718             foreach (LocalizedName displayName in organization.DisplayNames)
2719             {
2720                 XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.OrganizationDisplayName, Saml2MetadataConstants.Namespace);
2721                 WriteLocalizedName(writer, displayName, element);
2722             }
2723 
2724             if (organization.Urls.Count < 1)
2725             {
2726                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.OrganizationUrl)));
2727             }
2728 
2729             foreach (LocalizedUri uri in organization.Urls)
2730             {
2731                 XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.OrganizationUrl, Saml2MetadataConstants.Namespace);
2732                 WriteLocalizedUri(writer, uri, element);
2733             }
2734 
2735             WriteCustomAttributes<Organization>(writer, organization);
2736             WriteCustomElements<Organization>(writer, organization);
2737             writer.WriteEndElement(); // Organization
2738         }
2739 
2740         /// <summary>
2741         /// Writes role descriptor attibutes.
2742         /// </summary>
2743         /// <param name="writer">The xml writer.</param>
2744         /// <param name="roleDescriptor">The role descriptor.</param>
2745         /// <exception cref="ArgumentNullException">The parameter writer/roleDescriptor/roleDescriptor.ProtocolsSupporeted is null.</exception>
WriteRoleDescriptorAttributes(XmlWriter writer, RoleDescriptor roleDescriptor)2746         protected virtual void WriteRoleDescriptorAttributes(XmlWriter writer, RoleDescriptor roleDescriptor)
2747         {
2748             if (writer == null)
2749             {
2750                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2751             }
2752 
2753             if (roleDescriptor == null)
2754             {
2755                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
2756             }
2757 
2758             if (roleDescriptor.ProtocolsSupported == null)
2759             {
2760                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.ProtocolsSupported");
2761             }
2762 
2763             // Optional
2764             if (roleDescriptor.ValidUntil != null && roleDescriptor.ValidUntil != DateTime.MaxValue)
2765             {
2766                 // Write the date in a sortable form.
2767                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ValidUntil, null, roleDescriptor.ValidUntil.ToString("s", CultureInfo.InvariantCulture));
2768             }
2769 
2770             // Optional
2771             if (roleDescriptor.ErrorUrl != null)
2772             {
2773                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ErrorUrl, null, (roleDescriptor.ErrorUrl.IsAbsoluteUri ? roleDescriptor.ErrorUrl.AbsoluteUri : roleDescriptor.ErrorUrl.ToString()));
2774             }
2775 
2776             // Mandatory
2777             if (roleDescriptor.ProtocolsSupported.Count == 0)
2778             {
2779                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Attributes.ProtocolsSupported)));
2780             }
2781 
2782             StringBuilder sb = new StringBuilder();
2783             foreach (Uri protocol in roleDescriptor.ProtocolsSupported)
2784             {
2785                 sb.AppendFormat("{0} ", (protocol.IsAbsoluteUri ? protocol.AbsoluteUri : protocol.ToString()));
2786             }
2787 
2788             string protocolsString = sb.ToString();
2789             writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ProtocolsSupported, null, protocolsString.Trim());
2790 
2791             WriteCustomAttributes<RoleDescriptor>(writer, roleDescriptor);
2792         }
2793 
2794         /// <summary>
2795         /// Writes the role descriptor element.
2796         /// </summary>
2797         /// <param name="writer">The xml writer.</param>
2798         /// <param name="roleDescriptor">The role descriptor.</param>
2799         /// <exception cref="ArgumentNullException">The parameter writer/roleDescriptor/roleDescriptor.Contacts/roleDescriptor.Keys is null.</exception>
WriteRoleDescriptorElements(XmlWriter writer, RoleDescriptor roleDescriptor)2800         protected virtual void WriteRoleDescriptorElements(XmlWriter writer, RoleDescriptor roleDescriptor)
2801         {
2802             if (writer == null)
2803             {
2804                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2805             }
2806 
2807             if (roleDescriptor == null)
2808             {
2809                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor");
2810             }
2811 
2812             if (roleDescriptor.Contacts == null)
2813             {
2814                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.Contacts");
2815             }
2816 
2817             if (roleDescriptor.Keys == null)
2818             {
2819                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("roleDescriptor.Keys");
2820             }
2821 
2822             // Optional
2823             if (roleDescriptor.Organization != null)
2824             {
2825                 WriteOrganization(writer, roleDescriptor.Organization);
2826             }
2827 
2828             // Optional
2829             foreach (KeyDescriptor key in roleDescriptor.Keys)
2830             {
2831                 WriteKeyDescriptor(writer, key);
2832             }
2833 
2834             // Optional
2835             foreach (ContactPerson contact in roleDescriptor.Contacts)
2836             {
2837                 WriteContactPerson(writer, contact);
2838             }
2839 
2840             WriteCustomElements<RoleDescriptor>(writer, roleDescriptor);
2841         }
2842 
2843         /// <summary>
2844         /// Writes a security token service descriptor.
2845         /// </summary>
2846         /// <param name="writer">The xml writer.</param>
2847         /// <param name="securityTokenServiceDescriptor">The <see cref="SecurityTokenServiceDescriptor"/>.</param>
2848         /// <exception cref="ArgumentNullException">The parameter writer/securityTokenServiceDescriptor/securityTokenServiceDescriptor.Endpoint/
2849         /// securityTokenServiceDescriptor.PassiveRequestorEndpoints is null.</exception>
WriteSecurityTokenServiceDescriptor(XmlWriter writer, SecurityTokenServiceDescriptor securityTokenServiceDescriptor)2850         protected virtual void WriteSecurityTokenServiceDescriptor(XmlWriter writer, SecurityTokenServiceDescriptor securityTokenServiceDescriptor)
2851         {
2852             if (writer == null)
2853             {
2854                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2855             }
2856 
2857             if (securityTokenServiceDescriptor == null)
2858             {
2859                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenServiceDescriptor");
2860             }
2861 
2862             if (securityTokenServiceDescriptor.SecurityTokenServiceEndpoints == null)
2863             {
2864                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenServiceDescriptor.Endpoints");
2865             }
2866 
2867             if (securityTokenServiceDescriptor.PassiveRequestorEndpoints == null)
2868             {
2869                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenServiceDescriptor.PassiveRequestorEndpoints");
2870             }
2871 
2872             writer.WriteStartElement(Saml2MetadataConstants.Elements.RoleDescriptor, Saml2MetadataConstants.Namespace);
2873             writer.WriteAttributeString("xsi", "type", XmlSchema.InstanceNamespace, FederationMetadataConstants.Prefix + ":" + FederationMetadataConstants.Elements.SecurityTokenServiceType);
2874 
2875             writer.WriteAttributeString("xmlns", FederationMetadataConstants.Prefix, null, FederationMetadataConstants.Namespace);
2876 
2877             WriteWebServiceDescriptorAttributes(writer, securityTokenServiceDescriptor);
2878             WriteCustomAttributes<SecurityTokenServiceDescriptor>(writer, securityTokenServiceDescriptor);
2879 
2880             WriteWebServiceDescriptorElements(writer, securityTokenServiceDescriptor);
2881 
2882             if (securityTokenServiceDescriptor.SecurityTokenServiceEndpoints.Count == 0)
2883             {
2884                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, FederationMetadataConstants.Elements.SecurityTokenServiceEndpoint)));
2885             }
2886 
2887             foreach (EndpointReference epr in securityTokenServiceDescriptor.SecurityTokenServiceEndpoints)
2888             {
2889                 writer.WriteStartElement(FederationMetadataConstants.Elements.SecurityTokenServiceEndpoint, FederationMetadataConstants.Namespace);
2890                 epr.WriteTo(writer);
2891                 writer.WriteEndElement();
2892             }
2893 
2894             foreach (EndpointReference epr in securityTokenServiceDescriptor.PassiveRequestorEndpoints)
2895             {
2896                 writer.WriteStartElement(FederationMetadataConstants.Elements.PassiveRequestorEndpoint, FederationMetadataConstants.Namespace);
2897                 epr.WriteTo(writer);
2898                 writer.WriteEndElement();
2899             }
2900 
2901             WriteCustomElements<SecurityTokenServiceDescriptor>(writer, securityTokenServiceDescriptor);
2902 
2903             writer.WriteEndElement();
2904         }
2905 
2906         /// <summary>
2907         /// Writes an spsso descriptor.
2908         /// </summary>
2909         /// <param name="writer">The xml writer.</param>
2910         /// <param name="serviceProviderSingleSignOnDescriptor">The spsso descriptor.</param>
2911         /// <exception cref="ArgumentNullException">The input parameter is null.</exception>
WriteServiceProviderSingleSignOnDescriptor(XmlWriter writer, ServiceProviderSingleSignOnDescriptor serviceProviderSingleSignOnDescriptor)2912         protected virtual void WriteServiceProviderSingleSignOnDescriptor(XmlWriter writer, ServiceProviderSingleSignOnDescriptor serviceProviderSingleSignOnDescriptor)
2913         {
2914             if (writer == null)
2915             {
2916                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2917             }
2918 
2919             if (serviceProviderSingleSignOnDescriptor == null)
2920             {
2921                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("spssoDescriptor");
2922             }
2923 
2924             if (serviceProviderSingleSignOnDescriptor.AssertionConsumerServices == null)
2925             {
2926                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("spssoDescriptor.AssertionConsumerService");
2927             }
2928 
2929             writer.WriteStartElement(Saml2MetadataConstants.Elements.SpssoDescriptor, Saml2MetadataConstants.Namespace);
2930             if (serviceProviderSingleSignOnDescriptor.AuthenticationRequestsSigned)
2931             {
2932                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.AuthenticationRequestsSigned, null,
2933                     XmlConvert.ToString(serviceProviderSingleSignOnDescriptor.AuthenticationRequestsSigned));
2934             }
2935 
2936             if (serviceProviderSingleSignOnDescriptor.WantAssertionsSigned)
2937             {
2938                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.WantAssertionsSigned, null,
2939                     XmlConvert.ToString(serviceProviderSingleSignOnDescriptor.WantAssertionsSigned));
2940             }
2941 
2942             WriteSingleSignOnDescriptorAttributes(writer, serviceProviderSingleSignOnDescriptor);
2943             WriteCustomAttributes<ServiceProviderSingleSignOnDescriptor>(writer, serviceProviderSingleSignOnDescriptor);
2944 
2945             WriteSingleSignOnDescriptorElements(writer, serviceProviderSingleSignOnDescriptor);
2946             if (serviceProviderSingleSignOnDescriptor.AssertionConsumerServices.Count == 0)
2947             {
2948                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, Saml2MetadataConstants.Elements.AssertionConsumerService)));
2949             }
2950 
2951             foreach (IndexedProtocolEndpoint ep in serviceProviderSingleSignOnDescriptor.AssertionConsumerServices.Values)
2952             {
2953                 XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.AssertionConsumerService, Saml2MetadataConstants.Namespace);
2954                 WriteIndexedProtocolEndpoint(writer, ep, element);
2955             }
2956 
2957             WriteCustomElements<ServiceProviderSingleSignOnDescriptor>(writer, serviceProviderSingleSignOnDescriptor);
2958             writer.WriteEndElement(); // SPSSODescriptor
2959         }
2960 
2961         /// <summary>
2962         /// Writes the sso descriptor attributers.
2963         /// </summary>
2964         /// <param name="writer">The xml writer.</param>
2965         /// <param name="singleSignOnDescriptor">The sso descriptor.</param>
WriteSingleSignOnDescriptorAttributes(XmlWriter writer, SingleSignOnDescriptor singleSignOnDescriptor)2966         protected virtual void WriteSingleSignOnDescriptorAttributes(XmlWriter writer, SingleSignOnDescriptor singleSignOnDescriptor)
2967         {
2968             WriteRoleDescriptorAttributes(writer, singleSignOnDescriptor);
2969             WriteCustomAttributes<SingleSignOnDescriptor>(writer, singleSignOnDescriptor);
2970         }
2971 
2972         /// <summary>
2973         /// Writes the sso descriptor element.
2974         /// </summary>
2975         /// <param name="writer">The xml writer.</param>
2976         /// <param name="singleSignOnDescriptor">The sso descriptor.</param>
WriteSingleSignOnDescriptorElements(XmlWriter writer, SingleSignOnDescriptor singleSignOnDescriptor)2977         protected virtual void WriteSingleSignOnDescriptorElements(XmlWriter writer, SingleSignOnDescriptor singleSignOnDescriptor)
2978         {
2979             if (writer == null)
2980             {
2981                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
2982             }
2983 
2984             if (singleSignOnDescriptor == null)
2985             {
2986                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ssoDescriptor");
2987             }
2988 
2989             WriteRoleDescriptorElements(writer, singleSignOnDescriptor);
2990 
2991             if (singleSignOnDescriptor.ArtifactResolutionServices != null && singleSignOnDescriptor.ArtifactResolutionServices.Count > 0)
2992             {
2993                 // Write the artifact resolution services
2994                 foreach (IndexedProtocolEndpoint ep in singleSignOnDescriptor.ArtifactResolutionServices.Values)
2995                 {
2996                     if (ep.ResponseLocation != null)
2997                     {
2998                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3249, Saml2MetadataConstants.Attributes.ResponseLocation)));
2999                     }
3000 
3001                     XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.ArtifactResolutionService, Saml2MetadataConstants.Namespace);
3002                     WriteIndexedProtocolEndpoint(writer, ep, element);
3003                 }
3004             }
3005 
3006             if (singleSignOnDescriptor.SingleLogoutServices != null && singleSignOnDescriptor.SingleLogoutServices.Count > 0)
3007             {
3008                 // Write the single logout service endpoints.
3009                 foreach (ProtocolEndpoint endpoint in singleSignOnDescriptor.SingleLogoutServices)
3010                 {
3011                     XmlQualifiedName element = new XmlQualifiedName(Saml2MetadataConstants.Elements.SingleLogoutService, Saml2MetadataConstants.Namespace);
3012                     WriteProtocolEndpoint(writer, endpoint, element);
3013                 }
3014             }
3015 
3016             if (singleSignOnDescriptor.NameIdentifierFormats != null && singleSignOnDescriptor.NameIdentifierFormats.Count > 0)
3017             {
3018                 // Write the name id formats
3019                 foreach (Uri nameId in singleSignOnDescriptor.NameIdentifierFormats)
3020                 {
3021                     if (!nameId.IsAbsoluteUri)
3022                     {
3023                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID0014, Saml2MetadataConstants.Elements.NameIDFormat)));
3024                     }
3025 
3026                     writer.WriteStartElement(Saml2MetadataConstants.Elements.NameIDFormat, Saml2MetadataConstants.Namespace);
3027                     writer.WriteString(nameId.AbsoluteUri);
3028                     writer.WriteEndElement();
3029                 }
3030             }
3031 
3032             WriteCustomElements<SingleSignOnDescriptor>(writer, singleSignOnDescriptor);
3033         }
3034 
3035         /// <summary>
3036         /// Write a web service description's attributes.
3037         /// </summary>
3038         /// <param name="writer">The xml writer.</param>
3039         /// <param name="wsDescriptor">The web service desriptor.</param>
3040         /// <exception cref="ArgumentNullException">The input parameter is null.</exception>
WriteWebServiceDescriptorAttributes(XmlWriter writer, WebServiceDescriptor wsDescriptor)3041         protected virtual void WriteWebServiceDescriptorAttributes(XmlWriter writer, WebServiceDescriptor wsDescriptor)
3042         {
3043             if (writer == null)
3044             {
3045                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
3046             }
3047 
3048             if (wsDescriptor == null)
3049             {
3050                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsDescriptor");
3051             }
3052 
3053             WriteRoleDescriptorAttributes(writer, wsDescriptor);
3054 
3055             if (!String.IsNullOrEmpty(wsDescriptor.ServiceDisplayName))
3056             {
3057                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ServiceDisplayName, null, wsDescriptor.ServiceDisplayName);
3058             }
3059 
3060             if (!String.IsNullOrEmpty(wsDescriptor.ServiceDescription))
3061             {
3062                 writer.WriteAttributeString(Saml2MetadataConstants.Attributes.ServiceDescription, null, wsDescriptor.ServiceDescription);
3063             }
3064 
3065             WriteCustomAttributes<WebServiceDescriptor>(writer, wsDescriptor);
3066         }
3067 
3068         /// <summary>
3069         /// Write a web service description element.
3070         /// </summary>
3071         /// <param name="writer">The xml writer.</param>
3072         /// <param name="wsDescriptor">The web service desriptor.</param>
3073         /// <exception cref="ArgumentNullException">The input parameter is null.</exception>
WriteWebServiceDescriptorElements(XmlWriter writer, WebServiceDescriptor wsDescriptor)3074         protected virtual void WriteWebServiceDescriptorElements(XmlWriter writer, WebServiceDescriptor wsDescriptor)
3075         {
3076             if (writer == null)
3077             {
3078                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
3079             }
3080 
3081             if (wsDescriptor == null)
3082             {
3083                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsDescriptor");
3084             }
3085 
3086             if (wsDescriptor.TargetScopes == null)
3087             {
3088                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsDescriptor.TargetScopes");
3089             }
3090 
3091             if (wsDescriptor.ClaimTypesOffered == null)
3092             {
3093                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsDescriptor.ClaimTypesOffered");
3094             }
3095 
3096             if (wsDescriptor.TokenTypesOffered == null)
3097             {
3098                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsDescriptor.TokenTypesOffered");
3099             }
3100 
3101             WriteRoleDescriptorElements(writer, wsDescriptor);
3102 
3103             if (wsDescriptor.TokenTypesOffered.Count > 0)
3104             {
3105                 writer.WriteStartElement(FederationMetadataConstants.Elements.TokenTypesOffered, FederationMetadataConstants.Namespace);
3106                 foreach (Uri tokenType in wsDescriptor.TokenTypesOffered)
3107                 {
3108                     writer.WriteStartElement(WSFederationMetadataConstants.Elements.TokenType, WSFederationMetadataConstants.Namespace);
3109                     if (!tokenType.IsAbsoluteUri)
3110                     {
3111                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MetadataSerializationException(SR.GetString(SR.ID3203, WSAuthorizationConstants.Elements.ClaimType)));
3112                     }
3113 
3114                     writer.WriteAttributeString(WSFederationMetadataConstants.Attributes.Uri, tokenType.AbsoluteUri);
3115                     writer.WriteEndElement();
3116                 }
3117 
3118                 writer.WriteEndElement();
3119             }
3120 
3121             if (wsDescriptor.ClaimTypesOffered.Count > 0)
3122             {
3123                 writer.WriteStartElement(FederationMetadataConstants.Elements.ClaimTypesOffered, FederationMetadataConstants.Namespace);
3124                 foreach (DisplayClaim claim in wsDescriptor.ClaimTypesOffered)
3125                 {
3126                     WriteDisplayClaim(writer, claim);
3127                 }
3128 
3129                 writer.WriteEndElement();
3130             }
3131 
3132             if (wsDescriptor.ClaimTypesRequested.Count > 0)
3133             {
3134                 writer.WriteStartElement(FederationMetadataConstants.Elements.ClaimTypesRequested, FederationMetadataConstants.Namespace);
3135                 foreach (DisplayClaim claim in wsDescriptor.ClaimTypesRequested)
3136                 {
3137                     WriteDisplayClaim(writer, claim);
3138                 }
3139 
3140                 writer.WriteEndElement();
3141             }
3142 
3143             if (wsDescriptor.TargetScopes.Count > 0)
3144             {
3145                 writer.WriteStartElement(FederationMetadataConstants.Elements.TargetScopes, FederationMetadataConstants.Namespace);
3146                 foreach (EndpointReference address in wsDescriptor.TargetScopes)
3147                 {
3148                     address.WriteTo(writer);
3149                 }
3150 
3151                 writer.WriteEndElement();
3152             }
3153 
3154             WriteCustomElements<WebServiceDescriptor>(writer, wsDescriptor);
3155         }
3156 
3157         /// <summary>
3158         /// Reads the &lt;saml:Attribute> element.
3159         /// </summary>
3160         /// <remarks>
3161         /// The default implementation requires that the content of the
3162         /// Attribute element be a simple string. To handle complex content
3163         /// or content of declared simple types other than xs:string, override
3164         /// this method.
3165         /// </remarks>
3166         /// <param name="reader">The xml reader.</param>
3167         /// <returns>A Saml2 attribute.</returns>
3168         /// <exception cref="ArgumentNullException">The input parameter is null.</exception>
ReadAttribute(XmlReader reader)3169         protected virtual Saml2Attribute ReadAttribute(XmlReader reader)
3170         {
3171             if (null == reader)
3172             {
3173                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
3174             }
3175 
3176             // throw if wrong element
3177             if (!reader.IsStartElement(Saml2Constants.Elements.Attribute, Saml2Constants.Namespace))
3178             {
3179                 reader.ReadStartElement(Saml2Constants.Elements.Attribute, Saml2Constants.Namespace);
3180             }
3181 
3182             try
3183             {
3184                 Saml2Attribute attribute;
3185                 bool isEmpty = reader.IsEmptyElement;
3186 
3187                 // @attributes
3188                 string value;
3189 
3190                 // @xsi:type
3191                 XmlUtil.ValidateXsiType(reader, Saml2Constants.Types.AttributeType, Saml2Constants.Namespace);
3192 
3193                 // @Name - required
3194                 value = reader.GetAttribute(Saml2Constants.Attributes.Name);
3195                 if (String.IsNullOrEmpty(value))
3196                 {
3197                     throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.Name, Saml2Constants.Elements.Attribute));
3198                 }
3199 
3200                 attribute = new Saml2Attribute(value);
3201 
3202                 // @NameFormat - optional
3203                 value = reader.GetAttribute(Saml2Constants.Attributes.NameFormat);
3204                 if (!String.IsNullOrEmpty(value))
3205                 {
3206                     if (!UriUtil.CanCreateValidUri(value, UriKind.Absolute))
3207                     {
3208                         throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID0011, Saml2Constants.Attributes.Namespace, Saml2Constants.Elements.Action));
3209                     }
3210 
3211                     attribute.NameFormat = new Uri(value);
3212                 }
3213 
3214                 // @FriendlyName - optional
3215                 attribute.FriendlyName = reader.GetAttribute(Saml2Constants.Attributes.FriendlyName);
3216 
3217                 // content
3218                 reader.Read();
3219                 if (!isEmpty)
3220                 {
3221                     while (reader.IsStartElement(Saml2Constants.Elements.AttributeValue, Saml2Constants.Namespace))
3222                     {
3223                         bool isEmptyValue = reader.IsEmptyElement;
3224                         bool isNil = XmlUtil.IsNil(reader);
3225 
3226                         // For now, the value must be a string
3227                         XmlUtil.ValidateXsiType(reader, "string", XmlSchema.Namespace);
3228 
3229                         if (isNil)
3230                         {
3231                             reader.Read();
3232                             if (!isEmptyValue)
3233                             {
3234                                 reader.ReadEndElement();
3235                             }
3236 
3237                             attribute.Values.Add(null);
3238                         }
3239                         else if (isEmptyValue)
3240                         {
3241                             reader.Read();
3242                             attribute.Values.Add("");
3243                         }
3244                         else
3245                         {
3246                             attribute.Values.Add(reader.ReadElementString());
3247                         }
3248                     }
3249 
3250                     reader.ReadEndElement();
3251                 }
3252 
3253                 return attribute;
3254             }
3255             catch (Exception e)
3256             {
3257                 if (System.Runtime.Fx.IsFatal(e))
3258                     throw;
3259 
3260                 Exception wrapped = TryWrapReadException(reader, e);
3261                 if (null == wrapped)
3262                 {
3263                     throw;
3264                 }
3265                 else
3266                 {
3267                     throw wrapped;
3268                 }
3269             }
3270         }
3271 
3272         /// <summary>
3273         /// Writes the &lt;saml:Attribute> element.
3274         /// </summary>
3275         /// <param name="writer">The xml writer.</param>
3276         /// <param name="data">The Saml2 attibute.</param>
3277         /// <exception cref="ArgumentNullException">The input parameter is null.</exception>
WriteAttribute(XmlWriter writer, Saml2Attribute data)3278         protected virtual void WriteAttribute(XmlWriter writer, Saml2Attribute data)
3279         {
3280             if (null == writer)
3281             {
3282                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
3283             }
3284 
3285             if (null == data)
3286             {
3287                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("data");
3288             }
3289 
3290             // <Attribute>
3291             writer.WriteStartElement(Saml2Constants.Elements.Attribute, Saml2Constants.Namespace);
3292 
3293             // @Name - required
3294             writer.WriteAttributeString(Saml2Constants.Attributes.Name, data.Name);
3295 
3296             // @NameFormat - optional
3297             if (null != data.NameFormat)
3298             {
3299                 writer.WriteAttributeString(Saml2Constants.Attributes.NameFormat, data.NameFormat.AbsoluteUri);
3300             }
3301 
3302             // @FriendlyName - optional
3303             if (null != data.FriendlyName)
3304             {
3305                 writer.WriteAttributeString(Saml2Constants.Attributes.FriendlyName, data.FriendlyName);
3306             }
3307 
3308             // <AttributeValue> 0-OO (nillable)
3309             foreach (string value in data.Values)
3310             {
3311                 writer.WriteStartElement(Saml2Constants.Elements.AttributeValue, Saml2Constants.Namespace);
3312 
3313                 if (null == value)
3314                 {
3315                     writer.WriteAttributeString("nil", XmlSchema.InstanceNamespace, XmlConvert.ToString(true));
3316                 }
3317                 else if (value.Length > 0)
3318                 {
3319                     writer.WriteString(value);
3320                 }
3321 
3322                 writer.WriteEndElement();
3323             }
3324 
3325             // </Attribute>
3326             writer.WriteEndElement();
3327         }
3328 
3329         // Wraps common data validation exceptions with an XmlException
3330         // associated with the failing reader
TryWrapReadException(XmlReader reader, Exception inner)3331         private static Exception TryWrapReadException(XmlReader reader, Exception inner)
3332         {
3333             if (inner is FormatException
3334                 || inner is ArgumentException
3335                 || inner is InvalidOperationException
3336                 || inner is OverflowException)
3337             {
3338                 return DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4125), inner);
3339             }
3340 
3341             return null;
3342         }
3343     }
3344 }
3345