コード例 #1
0
 /// <summary>
 /// Constructs an encrypting credential based on the x509 token.
 /// </summary>
 /// <param name="token">The x509 security token.</param>
 internal X509EncryptingCredentials(X509SecurityToken token)
     : this(
     token,
     new SecurityKeyIdentifier(token.CreateKeyIdentifierClause<X509IssuerSerialKeyIdentifierClause>()),
     SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm)
 {
 }
コード例 #2
0
 /// <summary>
 /// Constructs an encrypting credential based on the x509 token.
 /// </summary>
 /// <param name="token">The x509 security token.</param>
 internal X509EncryptingCredentials(X509SecurityToken token)
     : this(
         token,
         new SecurityKeyIdentifier(token.CreateKeyIdentifierClause <X509IssuerSerialKeyIdentifierClause>()),
         SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm)
 {
 }
コード例 #3
0
ファイル: SamlUtilities.cs プロジェクト: spzenk/sfdocsamples
        /// <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);          
        }
コード例 #4
0
 /// <summary>
 /// Constructs an encrypting credential based on the x509 token and key wrapping algorithm.
 /// </summary>
 /// <param name="token">The x509 security token.</param>
 /// <param name="keyWrappingAlgorithm">The key wrapping al----htm.</param>
 internal X509EncryptingCredentials(X509SecurityToken token, string keyWrappingAlgorithm)
     : this(token, new SecurityKeyIdentifier(token.CreateKeyIdentifierClause <X509IssuerSerialKeyIdentifierClause>()), keyWrappingAlgorithm)
 {
 }
コード例 #5
0
ファイル: MainForm.cs プロジェクト: yuriik83/UA-.NET
        /// <summary>
        /// Creates a SAML token for the specified email address.
        /// </summary>
        public static UserIdentity CreateSAMLToken(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.Windows;
            userid.StorePath = "LocalMachine\\My";
            userid.SubjectName = "UA Sample Client";

            X509Certificate2 certificate = 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>()));

            return new UserIdentity(new SamlSecurityToken(assertion));
        }
コード例 #6
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
            });

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

            if (spOptions.ServiceCertificate != null)
            {
                using (var securityToken = new X509SecurityToken(spOptions.ServiceCertificate))
                {
                    spsso.Keys.Add(
                        new KeyDescriptor
                        {
                            Use = KeyType.Encryption,
                            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;
        }
コード例 #7
0
        public static ExtendedEntityDescriptor CreateMetadata(this ISPOptions spOptions, AuthServicesUrls urls, string entityIdSuffix)
        {
            var eid = string.IsNullOrEmpty(entityIdSuffix)
                ? spOptions.EntityId
                : new EntityId(spOptions.EntityId.Id + entityIdSuffix);

            var ed = new ExtendedEntityDescriptor
            {
                EntityId = eid,
                Organization = spOptions.Organization,
                CacheDuration = spOptions.MetadataCacheDuration,
            };

            if(spOptions.MetadataValidDuration.HasValue)
            {
                ed.ValidUntil = DateTime.UtcNow.Add(spOptions.MetadataValidDuration.Value);
            }

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

            var spsso = new ExtendedServiceProviderSingleSignOnDescriptor()
            {
                WantAssertionsSigned = spOptions.WantAssertionsSigned,
                AuthenticationRequestsSigned = spOptions.AuthenticateRequestSigningBehavior == SigningBehavior.Always
            };

            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.SigningServiceCertificate != null)
            {
                spsso.SingleLogoutServices.Add(new ProtocolEndpoint(
                    Saml2Binding.HttpRedirectUri, urls.LogoutUrl));
                spsso.SingleLogoutServices.Add(new ProtocolEndpoint(
                    Saml2Binding.HttpPostUri, urls.LogoutUrl));
            }

            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;
        }
コード例 #8
0
 /// <summary>
 /// Constructs an encrypting credential based on the x509 token and key wrapping algorithm.
 /// </summary>
 /// <param name="token">The x509 security token.</param>
 /// <param name="keyWrappingAlgorithm">The key wrapping al----htm.</param>
 internal X509EncryptingCredentials(X509SecurityToken token, string keyWrappingAlgorithm)
     : this(token, new SecurityKeyIdentifier(token.CreateKeyIdentifierClause<X509IssuerSerialKeyIdentifierClause>()), keyWrappingAlgorithm)
 {
 }
コード例 #9
0
		public void WriteWrappedKeySecurityToken ()
		{
			StringWriter sw = new StringWriter ();
			byte [] bytes = new byte [64];
			for (byte i = 1; i < 64; i++)
				bytes [i] = i;

			SecurityToken wt = new X509SecurityToken (cert);
			SecurityKeyIdentifier ski = new SecurityKeyIdentifier (
				wt.CreateKeyIdentifierClause< X509ThumbprintKeyIdentifierClause> ());
			WrappedKeySecurityToken t = new WrappedKeySecurityToken (
				"urn:wrapper-key:1", bytes, SecurityAlgorithms.RsaOaepKeyWrap, wt, ski);

			using (XmlWriter w = XmlWriter.Create (sw, GetWriterSettings ())) {
				WSSecurityTokenSerializer.DefaultInstance.WriteToken (w, t);
			}
			string actual = sw.ToString ();
			int idx = actual.IndexOf ("<e:CipherValue>", StringComparison.Ordinal);
			Assert.IsTrue (idx >= 0, "No <CipherValue>");
			actual = 
				actual.Substring (0, idx) +
				"<e:CipherValue>removed here" +
				actual.Substring (actual.IndexOf ("</e:CipherValue>", StringComparison.Ordinal));
			Assert.AreEqual ("GQ3YHlGQhDF1bvMixHliX4uLjlY=", Convert.ToBase64String (cert.GetCertHash ()), "premise#1");
			Assert.AreEqual (
				String.Format ("<e:EncryptedKey Id=\"urn:wrapper-key:1\" xmlns:e=\"{0}\"><e:EncryptionMethod Algorithm=\"{1}\"><DigestMethod Algorithm=\"{2}\" xmlns=\"{3}\" /></e:EncryptionMethod><KeyInfo xmlns=\"{3}\"><o:SecurityTokenReference xmlns:o=\"{4}\"><o:KeyIdentifier ValueType=\"{5}\">{6}</o:KeyIdentifier></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>removed here</e:CipherValue></e:CipherData></e:EncryptedKey>",
					EncryptedXml.XmlEncNamespaceUrl,
					SecurityAlgorithms.RsaOaepKeyWrap,
					SignedXml.XmlDsigSHA1Url,
					SignedXml.XmlDsigNamespaceUrl,
					"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
					"http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1",
					Convert.ToBase64String (cert.GetCertHash ())),// "GQ3YHlGQhDF1bvMixHliX4uLjlY="
				actual);
		}
コード例 #10
0
		public void WriteGenericXmlSecurityToken1 ()
		{
			StringWriter sw = new StringWriter ();

			XmlElement xml = new XmlDocument ().CreateElement ("foo");
			SecurityToken token = new X509SecurityToken (new X509Certificate2 ("Test/Resources/test.pfx", "mono"));
			SecurityKeyIdentifierClause intref =
				token.CreateKeyIdentifierClause<X509IssuerSerialKeyIdentifierClause> ();
			SecurityKeyIdentifierClause extref =
			null; //	token.CreateKeyIdentifierClause<X509IssuerSerialKeyIdentifierClause> ();
			ReadOnlyCollection<IAuthorizationPolicy> policies =
				new ReadOnlyCollection<IAuthorizationPolicy> (
					new IAuthorizationPolicy [0]);

			GenericXmlSecurityToken t = new GenericXmlSecurityToken (xml, token, DateTime.Now, new DateTime (2112, 9, 3), intref, extref, policies);
			using (XmlWriter w = XmlWriter.Create (sw, GetWriterSettings ())) {
				WSSecurityTokenSerializer.DefaultInstance.WriteToken (w, t);
			}
			// Huh?
			Assert.AreEqual ("<foo />", sw.ToString ());
		}
コード例 #11
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);
        }
コード例 #12
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();
        }