Exemplo n.º 1
0
        private XmlElement GetKeyIdentifierClause(X509SecurityToken certToken)

        {
            using (XmlDocumentWriterHelper documentWriterHelper = new XmlDocumentWriterHelper())

            {
                // The key is located in the same XML document, so referencing that

                // with a local key identifier.

                var keyIdentifierClause =

                    certToken.CreateKeyIdentifierClause <LocalIdKeyIdentifierClause>();

                Debug.Assert(keyIdentifierClause != null);



                _tokenSerializer.WriteKeyIdentifierClause(

                    documentWriterHelper.CreateDocumentWriter(), keyIdentifierClause);



                XmlDocument xmlDocument = documentWriterHelper.ReadDocument();



                return(xmlDocument.DocumentElement);
            }
        }
        private Saml2Assertion CreateSamlAssertionWithSymmetricKey(BinarySecretSecurityToken proofToken)
        {
            X509SecurityToken           x509SecurityToken           = new X509SecurityToken(base.ClientCredentials.ClientCertificate.Certificate);
            X509SecurityToken           x509SecurityToken2          = new X509SecurityToken(base.ClientCredentials.ServiceCertificate.DefaultCertificate);
            SecurityKey                 signatureKey                = x509SecurityToken.SecurityKeys[0];
            SecurityKeyIdentifierClause securityKeyIdentifierClause = x509SecurityToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       signatureKeyIdentifier      = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                securityKeyIdentifierClause
            });
            SecurityKey securityKey = x509SecurityToken2.SecurityKeys[0];
            SecurityKeyIdentifierClause securityKeyIdentifierClause2 = x509SecurityToken2.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       encryptingKeyIdentifier      = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                securityKeyIdentifierClause2
            });

            byte[] keyBytes     = proofToken.GetKeyBytes();
            byte[] encryptedKey = securityKey.EncryptKey(base.SecurityAlgorithmSuite.DefaultAsymmetricKeyWrapAlgorithm, keyBytes);
            SecurityKeyIdentifier proofKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                new EncryptedKeyIdentifierClause(encryptedKey, base.SecurityAlgorithmSuite.DefaultAsymmetricKeyWrapAlgorithm, encryptingKeyIdentifier)
            });

            return(this.CreateSamlAssertion(signatureKey, signatureKeyIdentifier, proofKeyIdentifier));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a SAML assertion based on a symmetric proof key
        /// </summary>
        /// <param name="claims">A ClaimSet containing the claims to be placed into the SAML assertion</param>
        /// <param name="signatureToken">An X509SecurityToken that will be used to sign the SAML assertion</param>
        /// <param name="encryptionToken">An X509SecurityToken that will be used to encrypt the proof key</param>
        /// <param name="proofToken">A BinarySecretSecurityToken containing the proof key</param>
        /// <param name="algoSuite">The algorithm suite to use when performing cryptographic operations</param>
        /// <returns>A SAML assertion containing the passed in claims and proof key, signed by the provided signature token</returns>
        public static SamlAssertion CreateSymmetricKeyBasedAssertion(ClaimSet claims, X509SecurityToken signatureToken, X509SecurityToken encryptionToken, BinarySecretSecurityToken proofToken, SecurityAlgorithmSuite algoSuite)
        {
            // Check various input parameters
            if (claims == null)
            {
                throw new ArgumentNullException("claims");
            }

            if (claims.Count == 0)
            {
                throw new ArgumentException("Provided ClaimSet must contain at least one claim");
            }

            if (proofToken == null)
            {
                throw new ArgumentNullException("proofToken");
            }

            if (signatureToken == null)
            {
                throw new ArgumentNullException("signatureToken");
            }

            if (encryptionToken == null)
            {
                throw new ArgumentNullException("encryptionToken");
            }

            if (proofToken == null)
            {
                throw new ArgumentNullException("proofToken");
            }

            if (algoSuite == null)
            {
                throw new ArgumentNullException("algoSuite");
            }

            // Get signing key and a key identifier for same
            SecurityKey signatureKey = signatureToken.SecurityKeys[0];
            SecurityKeyIdentifierClause signatureSkic          = signatureToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       signatureKeyIdentifier = new SecurityKeyIdentifier(signatureSkic);

            // Get encryption key and a key identifier for same
            SecurityKey encryptionKey = encryptionToken.SecurityKeys[0];
            SecurityKeyIdentifierClause encryptionSkic          = encryptionToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       encryptionKeyIdentifier = new SecurityKeyIdentifier(encryptionSkic);

            // Encrypt the proof key and create a key identifier for same
            byte[] proofKey        = proofToken.GetKeyBytes();
            byte[] encryptedSecret = new byte[proofKey.Length];
            encryptedSecret = encryptionKey.EncryptKey(algoSuite.DefaultAsymmetricKeyWrapAlgorithm, proofKey);
            SecurityKeyIdentifier proofKeyIdentifier = new SecurityKeyIdentifier(new EncryptedKeyIdentifierClause(encryptedSecret, algoSuite.DefaultAsymmetricKeyWrapAlgorithm, encryptionKeyIdentifier));

            // Create the assertion
            return(CreateAssertion(claims, signatureKey, signatureKeyIdentifier, proofKeyIdentifier, algoSuite));
        }
Exemplo n.º 4
0
        private RequestSecurityTokenResponseWSTrust13 Issue(RequestSecurityTokenWSTrust13 rst)
        {
            // If rst is null, an exception is thrown.
            if (rst == null)
            {
                throw new ArgumentNullException("rst");
            }

            // Create an RSTR object.
            RequestSecurityTokenResponseWSTrust13 rstr = new RequestSecurityTokenResponseWSTrust13();

            string tokenType = rst.TokenType;

            Console.WriteLine("Issue: Request for token type {0}", tokenType);
            if (tokenType != null && tokenType != "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1")
            {
                throw new NotSupportedException("Unsupported token type " + tokenType);
            }

            SecurityKey           signingKey           = issuerToken.SecurityKeys[0];
            SecurityKeyIdentifier signingKeyIdentifier = new SecurityKeyIdentifier(issuerToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>());
            SecurityKeyIdentifier proofKeyIdentifier   = null;

            if (rst.IsProofKeyAsymmetric())
            {
                throw new NotSupportedException("Public key issuance is not supported");
            }
            // Symmetric proof key.
            Console.WriteLine("Constructing Symmetric Proof Key");

            // Construct the session key. This is the symmetric key that the client and the service share.
            // It appears twice in the response message; once for the service and
            // once for the client. For the service, it is typically embedded in the issued token,
            // for the client, it is returned in a wst:RequestedProofToken element.
            byte[] sessionKey = GetSessionKey(rst, rstr);

            // Get a token to use when encrypting key material for the service.
            SecurityToken encryptingToken = DetermineEncryptingToken(rst);

            // Encrypt the session key for the service.
            GetEncryptedKey(encryptingToken, sessionKey, out proofKeyIdentifier);

            // Issued tokens are valid for 12 hours by default.
            DateTime      effectiveTime  = DateTime.Now;
            DateTime      expirationTime = DateTime.Now + new TimeSpan(12, 0, 0);
            SecurityToken samlToken      = CreateSAMLToken(effectiveTime, expirationTime, signingKey, signingKeyIdentifier, proofKeyIdentifier);

            rstr.RequestedSecurityToken = samlToken;
            rstr.Context   = rst.Context;
            rstr.TokenType = tokenType;
            SecurityKeyIdentifierClause samlReference = samlToken.CreateKeyIdentifierClause <SamlAssertionKeyIdentifierClause>();

            rstr.RequestedAttachedReference   = samlReference;
            rstr.RequestedUnattachedReference = samlReference;
            return(rstr);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Creates a SAML token for the specified email address and security token.
        /// </summary>
        private SamlSecurityToken CreateSAMLToken(
            string emailAddress,
            X509SecurityToken issuerToken)
        {
            // Create list of confirmation strings
            List <string> confirmations = new List <string>();

            // Add holder-of-key string to list of confirmation strings
            confirmations.Add("urn:oasis:names:tc:SAML:1.0:cm:bearer");

            // Create SAML subject statement based on issuer member variable, confirmation string collection
            // local variable and proof key identifier parameter
            SamlSubject subject =
                new SamlSubject("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", null, emailAddress);

            // Create a list of SAML attributes
            List <SamlAttribute> attributes = new List <SamlAttribute>();
            Claim claim = Claim.CreateNameClaim(emailAddress);

            attributes.Add(new SamlAttribute(claim));

            // Create list of SAML statements
            List <SamlStatement> statements = new List <SamlStatement>();

            // Add a SAML attribute statement to the list of statements. Attribute statement is based on
            // subject statement and SAML attributes resulting from claims
            statements.Add(new SamlAttributeStatement(subject, attributes));

            // Create a valid from/until condition
            DateTime validFrom = DateTime.UtcNow;
            DateTime validTo   = DateTime.UtcNow.AddHours(12);

            SamlConditions conditions = new SamlConditions(validFrom, validTo);

            // Create the SAML assertion
            SamlAssertion assertion = new SamlAssertion(
                "_" + Guid.NewGuid().ToString(),
                issuerToken.Certificate.Subject,
                validFrom,
                conditions,
                null,
                statements);

            SecurityKey signingKey =
                new System.IdentityModel.Tokens.RsaSecurityKey((RSA)issuerToken.Certificate.PrivateKey);

            // Set the signing credentials for the SAML assertion
            assertion.SigningCredentials = new SigningCredentials(
                signingKey,
                System.IdentityModel.Tokens.SecurityAlgorithms.RsaSha1Signature,
                System.IdentityModel.Tokens.SecurityAlgorithms.Sha1Digest,
                new SecurityKeyIdentifier(issuerToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>()));

            return(new SamlSecurityToken(assertion));
        }
Exemplo n.º 6
0
        public static SamlAssertion CreateSymmetricKeyBasedAssertion(ClaimSet claims, X509SecurityToken signatureToken, X509SecurityToken encryptionToken, BinarySecretSecurityToken proofToken, SecurityAlgorithmSuite algoSuite)
        {
            if (claims == null)
            {
                throw new ArgumentNullException("claims");
            }
            if (claims.Count == 0)
            {
                throw new ArgumentException("Provided ClaimSet must contain at least one claim");
            }
            if (proofToken == null)
            {
                throw new ArgumentNullException("proofToken");
            }
            if (signatureToken == null)
            {
                throw new ArgumentNullException("signatureToken");
            }
            if (encryptionToken == null)
            {
                throw new ArgumentNullException("encryptionToken");
            }
            if (proofToken == null)
            {
                throw new ArgumentNullException("proofToken");
            }
            if (algoSuite == null)
            {
                throw new ArgumentNullException("algoSuite");
            }
            SecurityKey signatureKey = signatureToken.SecurityKeys[0];
            SecurityKeyIdentifierClause securityKeyIdentifierClause = signatureToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       signatureKeyIdentifier      = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                securityKeyIdentifierClause
            });
            SecurityKey securityKey = encryptionToken.SecurityKeys[0];
            SecurityKeyIdentifierClause securityKeyIdentifierClause2 = encryptionToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       encryptingKeyIdentifier      = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                securityKeyIdentifierClause2
            });

            byte[] keyBytes     = proofToken.GetKeyBytes();
            byte[] encryptedKey = new byte[keyBytes.Length];
            encryptedKey = securityKey.EncryptKey(algoSuite.DefaultAsymmetricKeyWrapAlgorithm, keyBytes);
            SecurityKeyIdentifier proofKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                new EncryptedKeyIdentifierClause(encryptedKey, algoSuite.DefaultAsymmetricKeyWrapAlgorithm, encryptingKeyIdentifier)
            });

            return(SamlUtilities.CreateAssertion(claims, signatureKey, signatureKeyIdentifier, proofKeyIdentifier, algoSuite));
        }
        private Saml2Assertion CreateSamlAssertionWithAsymmetricKey(SecurityToken proofToken)
        {
            X509SecurityToken           x509SecurityToken           = new X509SecurityToken(base.ClientCredentials.ClientCertificate.Certificate);
            SecurityKey                 signatureKey                = x509SecurityToken.SecurityKeys[0];
            SecurityKeyIdentifierClause securityKeyIdentifierClause = x509SecurityToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>();
            SecurityKeyIdentifier       signatureKeyIdentifier      = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                securityKeyIdentifierClause
            });
            SecurityKeyIdentifier proofKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[]
            {
                proofToken.CreateKeyIdentifierClause <RsaKeyIdentifierClause>()
            });

            return(this.CreateSamlAssertion(signatureKey, signatureKeyIdentifier, proofKeyIdentifier));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Returns a SecurityTokenReference element which contains a reference
        /// by id to a client certificate that is located in the same XML document.
        /// </summary>
        private XmlElement GetKeyIdentifierClause(X509SecurityToken certToken)
        {
            var keyIdentifierClause =
                certToken.CreateKeyIdentifierClause <LocalIdKeyIdentifierClause>();

            Debug.Assert(keyIdentifierClause != null);

            using (XmlDocumentWriterHelper documentWriterHelper = new XmlDocumentWriterHelper())
            {
                _tokenSerializer.WriteKeyIdentifierClause(
                    documentWriterHelper.CreateDocumentWriter(), keyIdentifierClause);

                XmlDocument xmlDocument = documentWriterHelper.ReadDocument();

                return(xmlDocument.DocumentElement);
            }
        }
Exemplo n.º 9
0
        public static ExtendedEntityDescriptor CreateMetadata(this ISPOptions spOptions, AuthServicesUrls urls)
        {
            var ed = new ExtendedEntityDescriptor
            {
                EntityId      = spOptions.EntityId,
                Organization  = spOptions.Organization,
                CacheDuration = spOptions.MetadataCacheDuration
            };

            foreach (var contact in spOptions.Contacts)
            {
                ed.Contacts.Add(contact);
            }

            var spsso = new ExtendedServiceProviderSingleSignOnDescriptor();

            spsso.ProtocolsSupported.Add(new Uri("urn:oasis:names:tc:SAML:2.0:protocol"));

            spsso.AssertionConsumerServices.Add(0, new IndexedProtocolEndpoint()
            {
                Index     = 0,
                IsDefault = true,
                Binding   = Saml2Binding.HttpPostUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            spsso.AssertionConsumerServices.Add(1, new IndexedProtocolEndpoint()
            {
                Index     = 1,
                IsDefault = false,
                Binding   = Saml2Binding.HttpArtifactUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            foreach (var attributeService in spOptions.AttributeConsumingServices)
            {
                spsso.AttributeConsumingServices.Add(attributeService);
            }

            if (spOptions.ServiceCertificates != null)
            {
                var publishCertificates = spOptions.MetadataCertificates;
                foreach (var serviceCert in publishCertificates)
                {
                    using (var securityToken = new X509SecurityToken(serviceCert.Certificate))
                    {
                        spsso.Keys.Add(
                            new KeyDescriptor
                        {
                            Use     = (KeyType)(byte)serviceCert.Use,
                            KeyInfo = new SecurityKeyIdentifier(securityToken.CreateKeyIdentifierClause <X509RawDataKeyIdentifierClause>())
                        }
                            );
                    }
                }
            }

            if (spOptions.DiscoveryServiceUrl != null &&
                !string.IsNullOrEmpty(spOptions.DiscoveryServiceUrl.OriginalString))
            {
                spsso.Extensions.DiscoveryResponse = new IndexedProtocolEndpoint
                {
                    Binding   = Saml2Binding.DiscoveryResponseUri,
                    Index     = 0,
                    IsDefault = true,
                    Location  = urls.SignInUrl
                };
            }

            ed.RoleDescriptors.Add(spsso);

            return(ed);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Creates a SAML token for the specified email address.
        /// </summary>
        public static async System.Threading.Tasks.Task <UserIdentity> CreateSAMLTokenAsync(string emailAddress)
        {
            // Normally this would be done by a server that is capable of verifying that
            // the user is a legimate holder of email address. Using a local certficate to
            // signed the SAML token is a short cut that would never be done in a real system.
            CertificateIdentifier userid = new CertificateIdentifier();

            userid.StoreType   = CertificateStoreType.X509Store;
            userid.StorePath   = "LocalMachine\\My";
            userid.SubjectName = "UA Sample Client";

            X509Certificate2 certificate = await userid.Find();

            X509SecurityToken signingToken = new X509SecurityToken(certificate);

            // Create list of confirmation strings
            List <string> confirmations = new List <string>();

            // Add holder-of-key string to list of confirmation strings
            confirmations.Add("urn:oasis:names:tc:SAML:1.0:cm:bearer");

            // Create SAML subject statement based on issuer member variable, confirmation string collection
            // local variable and proof key identifier parameter
            SamlSubject subject = new SamlSubject("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", null, emailAddress);

            // Create a list of SAML attributes
            List <SamlAttribute> attributes = new List <SamlAttribute>();
            Claim claim = Claim.CreateNameClaim(emailAddress);

            attributes.Add(new SamlAttribute(claim));

            // Create list of SAML statements
            List <SamlStatement> statements = new List <SamlStatement>();

            // Add a SAML attribute statement to the list of statements. Attribute statement is based on
            // subject statement and SAML attributes resulting from claims
            statements.Add(new SamlAttributeStatement(subject, attributes));

            // Create a valid from/until condition
            DateTime validFrom = DateTime.UtcNow;
            DateTime validTo   = DateTime.UtcNow.AddHours(12);

            SamlConditions conditions = new SamlConditions(validFrom, validTo);

            // Create the SAML assertion
            SamlAssertion assertion = new SamlAssertion(
                "_" + Guid.NewGuid().ToString(),
                signingToken.Certificate.Subject,
                validFrom,
                conditions,
                null,
                statements);

            SecurityKey signingKey = new System.IdentityModel.Tokens.RsaSecurityKey((RSA)signingToken.Certificate.PrivateKey);

            // Set the signing credentials for the SAML assertion
            assertion.SigningCredentials = new SigningCredentials(
                signingKey,
                System.IdentityModel.Tokens.SecurityAlgorithms.RsaSha1Signature,
                System.IdentityModel.Tokens.SecurityAlgorithms.Sha1Digest,
                new SecurityKeyIdentifier(signingToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>()));
            // TODO
            // return new UserIdentity(new SamlSecurityToken(assertion));
            throw new NotImplementedException();
        }
Exemplo n.º 11
0
        /// <summary>
        /// Build the contents of the SAML token
        /// </summary>
        /// <param name="writer"><b>XmlDictionaryWriter</b> to write the contents of this token to</param>
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            // Subject
            SamlSubject subject = new SamlSubject();

            if (this.useKey != null)
            {
                // Add the key and the Holder-Of-Key confirmation method
                subject.KeyIdentifier = this.useKey;
                subject.ConfirmationMethods.Add(SamlConstants.HolderOfKey);
            }
            else
            {
                // This is a bearer token
                subject.ConfirmationMethods.Add(SamlConstants.SenderVouches);
            }


            // Attributes, statements, conditions, and assertions
            List <SamlStatement> statements = new List <SamlStatement>();
            List <SamlAttribute> attributes = GetTokenAttributes();


            statements.Add(new SamlAuthenticationStatement(subject, Constants.Saml.AuthenticationMethods.Unspecified, DateTime.Now, null, null, null));
            statements.Add(new SamlAttributeStatement(subject, attributes));
            SamlConditions conditions = new SamlConditions(DateTime.Now, (DateTime.Now + TimeSpan.FromHours(8.0)));
            SamlAssertion  assertion  = new SamlAssertion("uuid-" + Guid.NewGuid(), Program.Issuer, DateTime.Now, conditions, null, statements);

            // Build the signing token
            SecurityToken         signingToken       = new X509SecurityToken(Program.SigningCertificate);
            SecurityKeyIdentifier keyIdentifier      = new SecurityKeyIdentifier(signingToken.CreateKeyIdentifierClause <X509RawDataKeyIdentifierClause>());
            SigningCredentials    signingCredentials = new SigningCredentials(signingToken.SecurityKeys[0], SecurityAlgorithms.RsaSha1Signature, SecurityAlgorithms.Sha1Digest, keyIdentifier);

            assertion.SigningCredentials = signingCredentials;

            // Build the SAML token
            SamlSecurityToken           token               = new SamlSecurityToken(assertion);
            SecurityKeyIdentifierClause attachedReference   = token.CreateKeyIdentifierClause <SamlAssertionKeyIdentifierClause>();
            SecurityKeyIdentifierClause unattachedReference = token.CreateKeyIdentifierClause <SamlAssertionKeyIdentifierClause>();

            //
            // Write the XML
            //
            //writer = XmlDictionaryWriter.CreateTextWriter(File.CreateText("output.xml").BaseStream);

            // RSTR
            writer.WriteStartElement(Constants.WSTrust.NamespaceUri.Prefix, Constants.WSTrust.Elements.RequestSecurityTokenResponse, Constants.WSTrust.NamespaceUri.Uri);
            if (context != null)
            {
                writer.WriteAttributeString(Constants.WSTrust.Attributes.Context, context);
            }

            // TokenType
            writer.WriteElementString(Constants.WSTrust.NamespaceUri.Prefix, Constants.WSTrust.Elements.TokenType, Constants.WSTrust.NamespaceUri.Uri, Constants.WSTrust.TokenTypes.Saml10Assertion);

            // RequestedSecurityToken (the SAML token)
            SecurityTokenSerializer tokenSerializer = new WSSecurityTokenSerializer();

            writer.WriteStartElement(Constants.WSTrust.NamespaceUri.Prefix, Constants.WSTrust.Elements.RequestedSecurityToken, Constants.WSTrust.NamespaceUri.Uri);
            tokenSerializer.WriteToken(writer, token);
            writer.WriteEndElement();

            // RequestedAttachedReference
            writer.WriteStartElement(Constants.WSTrust.NamespaceUri.Prefix, Constants.WSTrust.Elements.RequestedAttachedReference, Constants.WSTrust.NamespaceUri.Uri);
            tokenSerializer.WriteKeyIdentifierClause(writer, attachedReference);
            writer.WriteEndElement();

            // RequestedUnattachedReference
            writer.WriteStartElement(Constants.WSTrust.NamespaceUri.Prefix, Constants.WSTrust.Elements.RequestedUnattachedReference, Constants.WSTrust.NamespaceUri.Uri);
            tokenSerializer.WriteKeyIdentifierClause(writer, unattachedReference);
            writer.WriteEndElement();

            // RequestedDisplayToken (display token)
            string displayTokenNS = "http://schemas.xmlsoap.org/ws/2005/05/identity";

            writer.WriteStartElement("wsid", "RequestedDisplayToken", displayTokenNS);
            writer.WriteStartElement("wsid", "DisplayToken", displayTokenNS);
            foreach (SamlAttribute attribute in attributes)
            {
                writer.WriteStartElement("wsid", "DisplayClaim", displayTokenNS);
                writer.WriteAttributeString("Uri", attribute.Namespace + "/" + attribute.Name);
                writer.WriteStartElement("wsid", "DisplayTag", displayTokenNS);
                writer.WriteValue(attribute.Name);
                writer.WriteEndElement();
                writer.WriteStartElement("wsid", "Description", displayTokenNS);
                writer.WriteValue(attribute.Namespace + "/" + attribute.Name);
                writer.WriteEndElement();
                foreach (string attributeValue in attribute.AttributeValues)
                {
                    writer.WriteStartElement("wsid", "DisplayValue", displayTokenNS);
                    writer.WriteValue(attributeValue);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.WriteEndElement();

            // RSTR End
            writer.WriteEndElement();

            //writer.Close();
        }