/// <summary>
        /// Creates the necessary key descriptors for the metadata based on the certificate in the IDPConfig class.
        /// </summary>
        /// <returns></returns>
        private static KeyDescriptor[] CreateKeyDescriptors()
        {
            List<KeyDescriptor> keys = new List<KeyDescriptor>();

            // Pack the certificate.
            KeyInfo keyinfo = new KeyInfo();
            KeyInfoX509Data keyClause = new KeyInfoX509Data(IDPConfig.IDPCertificate, X509IncludeOption.EndCertOnly);
            keyinfo.AddClause(keyClause);

            { // Create signing key element.
                KeyDescriptor key = new KeyDescriptor();
                keys.Add(key);
                key.use = KeyTypes.signing;
                key.useSpecified = true;
                key.KeyInfo = Serialization.DeserializeFromXmlString<dk.nita.saml20.Schema.XmlDSig.KeyInfo>(keyinfo.GetXml().OuterXml);
            }

            { // Create encryption key element
                KeyDescriptor key = new KeyDescriptor();
                keys.Add(key);
                key.use = KeyTypes.encryption;
                key.useSpecified = true;
                key.KeyInfo = Serialization.DeserializeFromXmlString<dk.nita.saml20.Schema.XmlDSig.KeyInfo>(keyinfo.GetXml().OuterXml);
            }

            return keys.ToArray();
        }
        /// <summary>
        /// Takes the Safewhere configuration class and converts it to a SAML2.0 metadata document.
        /// </summary>        
        private void ConvertToMetadata(SAML20FederationConfig config, KeyInfo keyinfo)
        {
            EntityDescriptor entity = CreateDefaultEntity();
            entity.entityID = config.ServiceProvider.ID;
            entity.validUntil = DateTime.Now.AddDays(7);

            SPSSODescriptor spDescriptor = new SPSSODescriptor();
            spDescriptor.protocolSupportEnumeration = new string[] { Saml20Constants.PROTOCOL };
            spDescriptor.AuthnRequestsSigned = XmlConvert.ToString(true);
            spDescriptor.WantAssertionsSigned = XmlConvert.ToString(true);
            if(config.ServiceProvider.NameIdFormats.All)
            {
                spDescriptor.NameIDFormat = new string[] {Saml20Constants.NameIdentifierFormats.Email,
                                                          Saml20Constants.NameIdentifierFormats.Entity,
                                                          Saml20Constants.NameIdentifierFormats.Kerberos,
                                                          Saml20Constants.NameIdentifierFormats.Persistent,
                                                          Saml20Constants.NameIdentifierFormats.Transient,
                                                          Saml20Constants.NameIdentifierFormats.Unspecified,
                                                          Saml20Constants.NameIdentifierFormats.Windows,
                                                          Saml20Constants.NameIdentifierFormats.X509SubjectName};
            }else
            {
                spDescriptor.NameIDFormat = new string[config.ServiceProvider.NameIdFormats.NameIdFormats.Count];
                int count = 0;
                foreach(NameIdFormatElement elem in config.ServiceProvider.NameIdFormats.NameIdFormats)
                {
                    spDescriptor.NameIDFormat[count++] = elem.NameIdFormat;
                }
            }

            Uri baseURL = new Uri(config.ServiceProvider.Server);
            List<Endpoint> logoutServiceEndpoints = new List<Endpoint>();
            List<IndexedEndpoint> signonServiceEndpoints = new List<IndexedEndpoint>();

            List<IndexedEndpoint> artifactResolutionEndpoints = new List<IndexedEndpoint>(2);

            // Include endpoints.
            foreach (Saml20ServiceEndpoint endpoint in config.ServiceProvider.serviceEndpoints)
            {
                if (endpoint.endpointType == EndpointType.SIGNON)
                {
                    IndexedEndpoint loginEndpoint = new IndexedEndpoint();
                    loginEndpoint.index = endpoint.endPointIndex;
                    loginEndpoint.isDefault = true;
                    loginEndpoint.Location = new Uri(baseURL, endpoint.localPath).ToString();
                    loginEndpoint.Binding = GetBinding(endpoint.Binding, Saml20Constants.ProtocolBindings.HTTP_Post);
                    signonServiceEndpoints.Add(loginEndpoint);

                    IndexedEndpoint artifactSignonEndpoint = new IndexedEndpoint();
                    artifactSignonEndpoint.Binding = Saml20Constants.ProtocolBindings.HTTP_SOAP;
                    artifactSignonEndpoint.index = loginEndpoint.index;
                    artifactSignonEndpoint.Location = loginEndpoint.Location;
                    artifactResolutionEndpoints.Add(artifactSignonEndpoint);

                    continue;
                }

                if (endpoint.endpointType == EndpointType.LOGOUT)
                {
                    Endpoint logoutEndpoint = new Endpoint();
                    logoutEndpoint.Location = new Uri(baseURL, endpoint.localPath).ToString();
                    logoutEndpoint.ResponseLocation = logoutEndpoint.Location;
                    logoutEndpoint.Binding = GetBinding(endpoint.Binding, Saml20Constants.ProtocolBindings.HTTP_Post);
                    logoutServiceEndpoints.Add(logoutEndpoint);

                    logoutEndpoint = new Endpoint();
                    logoutEndpoint.Location = new Uri(baseURL, endpoint.localPath).ToString();
                    logoutEndpoint.ResponseLocation = logoutEndpoint.Location;
                    logoutEndpoint.Binding = GetBinding(endpoint.Binding, Saml20Constants.ProtocolBindings.HTTP_Redirect);
                    logoutServiceEndpoints.Add(logoutEndpoint);

                    IndexedEndpoint artifactLogoutEndpoint = new IndexedEndpoint();
                    artifactLogoutEndpoint.Binding = Saml20Constants.ProtocolBindings.HTTP_SOAP;
                    artifactLogoutEndpoint.index = endpoint.endPointIndex;
                    artifactLogoutEndpoint.Location = logoutEndpoint.Location;
                    artifactResolutionEndpoints.Add(artifactLogoutEndpoint);

                    continue;
                }
            }

            spDescriptor.SingleLogoutService = logoutServiceEndpoints.ToArray();
            spDescriptor.AssertionConsumerService = signonServiceEndpoints.ToArray();

            // NameIdFormat
            if (!string.IsNullOrEmpty(config.NameIdFormat))
            {
                spDescriptor.NameIDFormat = new string[] { config.NameIdFormat };
            }

            // Attribute consuming service.
            if (config.RequestedAttributes.Attributes.Count > 0)
            {
                AttributeConsumingService attConsumingService = new AttributeConsumingService();
                spDescriptor.AttributeConsumingService = new AttributeConsumingService[] { attConsumingService };
                attConsumingService.index = signonServiceEndpoints[0].index;
                attConsumingService.isDefault = true;
                attConsumingService.ServiceName = new LocalizedName[] { new LocalizedName("SP", "da") };

                attConsumingService.RequestedAttribute =
                    new RequestedAttribute[config.RequestedAttributes.Attributes.Count];

                for (int i = 0; i < config.RequestedAttributes.Attributes.Count; i++)
                {
                    attConsumingService.RequestedAttribute[i] = new RequestedAttribute();
                    attConsumingService.RequestedAttribute[i].Name = config.RequestedAttributes.Attributes[i].name;
                    if (config.RequestedAttributes.Attributes[i].IsRequired)
                        attConsumingService.RequestedAttribute[i].isRequired = true;
                    attConsumingService.RequestedAttribute[i].NameFormat = SamlAttribute.NAMEFORMAT_BASIC;
                }
            }
            else
            {
                spDescriptor.AttributeConsumingService = new AttributeConsumingService[0];
            }

            if(config.Metadata != null && config.Metadata.IncludeArtifactEndpoints)
                spDescriptor.ArtifactResolutionService = artifactResolutionEndpoints.ToArray();

            entity.Items = new object[] { spDescriptor };

            // Keyinfo
            KeyDescriptor keySigning = new KeyDescriptor();
            KeyDescriptor keyEncryption = new KeyDescriptor();
            spDescriptor.KeyDescriptor = new KeyDescriptor[] { keySigning, keyEncryption };

            keySigning.use = KeyTypes.signing;
            keySigning.useSpecified = true;

            keyEncryption.use = KeyTypes.encryption;
            keyEncryption.useSpecified = true;

            // Ugly conversion between the .Net framework classes and our classes ... avert your eyes!!
            keySigning.KeyInfo = Serialization.DeserializeFromXmlString<Schema.XmlDSig.KeyInfo>(keyinfo.GetXml().OuterXml);
            keyEncryption.KeyInfo = keySigning.KeyInfo;

            // apply the <Organization> element
            if (config.ServiceProvider.Organization != null)
                entity.Organization = config.ServiceProvider.Organization;

            if (config.ServiceProvider.ContactPerson != null && config.ServiceProvider.ContactPerson.Count > 0)
                entity.ContactPerson = config.ServiceProvider.ContactPerson.ToArray();
        }