Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing / Deserializing GenericXmlSecurityToken and security - CRM Auth

I'm authenticating CRM users using Authenticate method from Microsoft.Xrm.Sdk.Client.IServiceManagement.
This method returns System.IdentityModel.Tokens.GenericXmlSecurityToken that I need to return as WebService response (JSON or XML format).

Plan is to have WebService Client to pass this token on subsequent request.
My problem is that I cannot construct token back...

My understanding is that I need to TokenXml, ProofToken, InternalTokenReference to construct valid GenericXmlSecurityToken that can be used for authentication.

My questions:

  • Can I send ProofToken and InternalTokenReference back to the WebService client, is it secure? I could easliy return TokenXML, ProofToken and InternalTokenReference, but I'm not sure whether it's secure...
  • If the answer for above is no, is there any other way to serialise/deserialise this kind of token so it can be passed back to the client?

Thanks in advance for all the help!
Regards

like image 281
Lucas Avatar asked Dec 04 '25 08:12

Lucas


1 Answers

The following code is not guaranteed to be future proof, but works with currently used versions of Dynamics CRM (2011, 2013, and 2015). Starting with 2015, there is support for OAuth which seems to be a better way to pass tokens across the wire.

Convert a SecurityTokenResponse into a Base64 encoded string:

    public static string Serialize(SecurityTokenResponse securityTokenResponse)
    {
        XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
        xmlWriterSettings.Encoding = Encoding.UTF8;

        using (MemoryStream memoryStream = new MemoryStream())
        using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
        {
            WSTrust13ResponseSerializer serializer = new WSTrust13ResponseSerializer();
            WSTrustSerializationContext context = new WSTrustSerializationContext();
            serializer.WriteXml(securityTokenResponse.Response, xmlWriter, context);
            xmlWriter.Flush();

            return Convert.ToBase64String(memoryStream.ToArray());
        }
    }

Convert the Base64 encoded string back into a SecurityTokenResponse:

    public static SecurityTokenResponse ParseToken(string serializedToken)
    {
        RequestSecurityTokenResponse response;
        using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(serializedToken)))
        using (XmlReader xmlReader = XmlReader.Create(memoryStream))
        {
            WSTrust13ResponseSerializer serializer = new WSTrust13ResponseSerializer();
            WSTrustSerializationContext serializationContext = new WSTrustSerializationContext();
            response = serializer.ReadXml(xmlReader, serializationContext);
        }

        SecurityToken proofKey = new BinarySecretSecurityToken(response.RequestedProofToken.ProtectedKey.GetKeyBytes());
        DateTime? created = null;
        DateTime? expires = null;
        if (response.Lifetime != null)
        {
            created = response.Lifetime.Created;
            expires = response.Lifetime.Expires;
        }
        if (!created.HasValue)
        {
            throw new Exception("Created unspecified");
        }
        if (!expires.HasValue)
        {
            throw new Exception("Expires unspecified");
        }

        SecurityToken securityToken = new GenericXmlSecurityToken(
                response.RequestedSecurityToken.SecurityTokenXml,
                proofKey,
                created.Value,
                expires.Value,
                response.RequestedAttachedReference,
                response.RequestedUnattachedReference,
                new ReadOnlyCollection<IAuthorizationPolicy>(new List<IAuthorizationPolicy>())
            );

        return new SecurityTokenResponse()
        {
            Response = response,
            Token = securityToken
        };
    }

The reason for choosing Base64 as the encoding is because I am sending the token over an XML web-service. This eliminates the need for XML-escaping an XML string. This can lead to a lot of escaping: &gt;, &lt;, &amp;, etc. If you are not sending the serialized token over an XML web-service, you might want to use a more readable encoding such as UTF8.

like image 149
dana Avatar answered Dec 06 '25 01:12

dana



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!