Serializing SAML tokens using WIF 4.5


Recently, I had to find a way to serialize SAML tokens received by my application so that they could be saved as a session variable and reused. This allowed the application, running behind a load balancer to not use cookies (and security context) or to have to re-request tokens from the STS. It did not appear WIF (System.Identity) has an out-of-the-box API for serializing/deserializing tokens. Eventually, I ended up writing my own APIs, which rely on the GenericXmlSecurityToken class. An instance of that class is returned in the RSTR from the WS-Trust call. The class has a TokenXml method which serializes the token itself. However, the constructor of the GenericXmlSecurityToken requires some additional parameters in order to re-hydrate the token from the xml: proof key for a holder of key token and assertion ids. I therefore needed to serialize these values from the RSTR as well. The eventual code looks as follows. It works fine with my ActAs symmetric key token, I expect it to work with a bearer token but I do not expect it to work with an asymmetric key.

 

        static string nm = “http://mrochon.com/saml/token/v1“;
        static XNamespace nmx = nm;
        static string prfx = “ser”;

        static public string Serialize(this GenericXmlSecurityToken token, RequestSecurityTokenResponse rstr)
        {
            var serializedToken = new StringBuilder();
            var xmlWriter = XmlWriter.Create(serializedToken);
            xmlWriter.WriteStartDocument();
            xmlWriter.WriteStartElement(prfx, “serializedToken”, nm);

            // SAML token
            xmlWriter.WriteStartElement(prfx, “token”, nm);
            token.TokenXml.WriteTo(xmlWriter);
            xmlWriter.WriteEndElement();

            // Proof key for symmetric keys
            if (rstr.RequestedProofToken != null)
            {
                if (rstr.RequestedProofToken.ProtectedKey != null)
                {
                    xmlWriter.WriteStartElement(prfx, “proofKey”, nm);
                    var bytes = rstr.RequestedProofToken.ProtectedKey.GetKeyBytes();
                    xmlWriter.WriteBase64(rstr.RequestedProofToken.ProtectedKey.GetKeyBytes(), 0, bytes.Length);
                    xmlWriter.WriteEndElement();
                }
            }

            // Lifetime
            if (rstr.Lifetime != null)
            {
                xmlWriter.WriteStartElement(prfx, “lifeTime”, nm);
                if (rstr.Lifetime.Created.HasValue)
                {
                    xmlWriter.WriteStartElement(prfx, “created”, nm);
                    xmlWriter.WriteValue(rstr.Lifetime.Created.Value);
                    xmlWriter.WriteEndElement();
                }
                if (rstr.Lifetime.Expires.HasValue)
                {
                    xmlWriter.WriteStartElement(prfx, “expires”, nm);
                    xmlWriter.WriteValue(rstr.Lifetime.Expires.Value);
                    xmlWriter.WriteEndElement();
                }
                xmlWriter.WriteEndElement();
            }
            //  rstr.RequestedAttachedReference, rstr.RequestedUnattachedReference
            //TODO: Note: not saving other properties of SamlAssertionKeyIdentifier
            xmlWriter.WriteStartElement(prfx, “requestedAttachedReference”, nm);
            xmlWriter.WriteString(((SamlAssertionKeyIdentifierClause)rstr.RequestedAttachedReference).AssertionId);
            xmlWriter.WriteEndElement();
            xmlWriter.WriteStartElement(prfx, “requestedUnattachedReference”, nm);
            xmlWriter.WriteString(((SamlAssertionKeyIdentifierClause)rstr.RequestedUnattachedReference).AssertionId);
            xmlWriter.WriteEndElement();

            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndDocument();
            xmlWriter.Close();
            return serializedToken.ToString();
        }
        static public GenericXmlSecurityToken GetGenericXmlSecurityToken(this string buffer)
        {
            var doc = XDocument.Parse(buffer);
            var root = doc.Element(nmx + “serializedToken”);
            var tokenXElement = root.Element(nmx + “token”).FirstNode;
            var tokenXml = (XmlElement) new XmlDocument().ReadNode(tokenXElement.CreateReader());
            var lifeTime = root.Element(nmx + “lifetime”);
            DateTime created, expires;
            created = expires = DateTime.UtcNow;
            if (lifeTime != null)
            {
                if (lifeTime.Element(nmx + “created”) != null)
                    created = DateTime.Parse(lifeTime.Element(nmx + “created”).Value);
                if (lifeTime.Element(nmx + “expires”) != null)
                    expires = DateTime.Parse(lifeTime.Element(nmx + “expires”).Value);
            }
            var proofKey = root.Element(nmx + “proofKey”);
            byte[] proofKeyBytes = null;
            if (proofKey != null)
            {
                proofKeyBytes = Convert.FromBase64String(proofKey.Value);
            }
            var attachedReference = new SamlAssertionKeyIdentifierClause(root.Element(nmx + “requestedAttachedReference”).Value);
            var unAttachedReference = new SamlAssertionKeyIdentifierClause(root.Element(nmx + “requestedUnattachedReference”).Value);
            return new GenericXmlSecurityToken(tokenXml, new BinarySecretSecurityToken(proofKeyBytes), created, expires, attachedReference, unAttachedReference, new ReadOnlyCollection<IAuthorizationPolicy>(new List<IAuthorizationPolicy>()));
        }

 

 


Comments (0)

Skip to main content