This blog post is a continuation of my previous post in which I explained on how to get SAML Token programmatically for your Dynamics On-premise environment configured with claims. If you have not read the previous post, I strongly suggest to read it and come back to this.
In this blog post, I will show you how to read the SAML assertion token that was obtained in the previous step. This would be typically done by applications who are relying on your SAML token to authenticate the user and many cases would be handled by a separate. But knowing a bit more never really harms. So if you are interested, let’s proceed.
Our main intention here would be to parse the SAML token and get the user’s claims from that. But there is a problem here. The SAML assertion token would be encrypted by the certificate of your relying party. So the decrypting party would need to have the certificate to decrypt the SAML token. Just to give you an idea, the SAML assertion token would have the following format.
<samlp:Response ID=’_4172503e-7104-4382-8cda-6f93f65de530′ Version=’2.0′ IssueInstant=’2016-06-01T05:05:18.362Z’ Destination=‘https://SAMLAssertionendpoint” Consent=’urn:oasis:names:tc:SAML:2.0:consent:unspecified’ xmlns:samlp=’urn:oasis:names:tc:SAML:2.0:protocol’>
<Issuer xmlns=’urn:oasis:names:tc:SAML:2.0:assertion’>/adfs/services/trust">http://<federation serverl url>/adfs/services/trust</Issuer>
<samlp:Status>
<samlp:StatusCode Value=’urn:oasis:names:tc:SAML:2.0:status:Success’ />
</samlp:Status>
<EncryptedAssertion xmlns=’urn:oasis:names:tc:SAML:2.0:assertion’>
<xenc:EncryptedData Type=’http://www.w3.org/2001/04/xmlenc#Element’ xmlns:xenc=’http://www.w3.org/2001/04/xmlenc#’>
<xenc:EncryptionMethod Algorithm=’http://www.w3.org/2001/04/xmlenc#aes256-cbc’ />
<KeyInfo xmlns=’http://www.w3.org/2000/09/xmldsig#’>
<e:EncryptedKey xmlns:e=’http://www.w3.org/2001/04/xmlenc#’>
<e:EncryptionMethod Algorithm=’http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p’>
<DigestMethod Algorithm=’http://www.w3.org/2000/09/xmldsig#sha1′ />
</e:EncryptionMethod>
<KeyInfo>
<ds:X509Data xmlns:ds=’http://www.w3.org/2000/09/xmldsig#’>
<ds:X509IssuerSerial>
<ds:X509IssuerName><—Removed certificate details—-></ds:X509IssuerName>
&
#160; <ds:X509SerialNumber>2787593233934917942755289290276949976521129800</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</KeyInfo>
<e:CipherData>
<e:CipherValue>gj65thkZ4rB22ktgO6KdTsWLhyUy5gpvD2Jt94on4Z6ILT2VbpW/sMyFUVmdsY0dJ1nk8ijyhTt2w7T4HJf3Gl2OzB0LZm8S0KrjYtDGTUQetT08SI1puaXmN0JQMeiGWio/qyuJ8bUMGwMJnQbkZ6U/RMmICN8WQlErNI/ALux7n3SnI6kApA55UIP1OxnOglM6n8OzHwwnyCPBo6Je/impg3E5o1JtWC3tx6u2w2tOL3/kCWpZ9ELNMajcd8WeYXs8DAagHpoGVoqrmfL49dcnYhcWmEP+ROIRk6QerykmK1PVI3u0/mdCRAI6c+PlF4d2LPB9GZQyNGS78ch5UA==</e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>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</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</EncryptedAssertion>
</samlp:Response>
So let’s proceed with it.
- Since Dynamics CRM is configured as your relying party, login to your Dynamics CRM server, open IIS –> Server Certificates –> Select the encryption certificate and right click – > select export option from the menu
- Export it as .pfx file since you need the private key as well in the certificate to decrypt the SAML assertion. Since the certificate is exported as pfx file, you need to give a password here. Remember the password, this would be need later in code.
- Click OK. The pfx file would be created in the location that you provided. Copy the .pfx file and store it in a location from client application which consumes the SAML token, can access. The rest is very simple. Below is the sample code which would read the SAML assertion and get the claims back.
private static void SAMLParser()
{
string samlFilePath = @"saml.xml";
string certificatePath = @"<certificate path>.pfx";
X509Certificate2 cert = new X509Certificate2(certificatePath, "<password when exported>");
var serviceTokens = new List<SecurityToken>();
serviceTokens.Add(new X509SecurityToken(cert));
var issuers = new ConfigurationBasedIssuerNameRegistry();
issuers.AddTrustedIssuer(cert.Thumbprint, cert.IssuerName.Name);
var configuration = new SecurityTokenHandlerConfiguration
{
AudienceRestriction = { AudienceMode = AudienceUriMode.Never },
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
IssuerNameRegistry = issuers,
MaxClockSkew = TimeSpan.FromMinutes(5),
ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(serviceTokens.AsReadOnly(), false)<
/p>
};
var tokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(configuration);
using (StringReader sr = new StringReader(XDocument.Load(samlFilePath).ToString()))
{
using (XmlReader reader = XmlReader.Create(sr))
{
if (!reader.ReadToFollowing("EncryptedAssertion", "urn:oasis:names:tc:SAML:2.0:assertion"))
{
throw new Exception("Assertion not found!");
}
SecurityToken token = tokenHandlers.ReadToken(reader.ReadSubtree());
Saml2SecurityToken samlToken = token as Saml2SecurityToken; // Getting the SAML token here.
// This is where you get the claims of the user from the SAML assertion token
Dictionary<string, object> payload = new Dictionary<string, object>();
foreach (Saml2Statement statement in samlToken.Assertion.Statements)
{
Saml2AttributeStatement attributeStatement = statement as Saml2AttributeStatement;
if (null != attributeStatement)
{
foreach (Saml2Attribute attribute in attributeStatement.Attributes)
{
Console.WriteLine("Name: {0}, Value: {1} ValueType: {2}", attribute.Name, attribute.Values[0], attribute.AttributeValueXsiType);
payload.Add(attribute.Name, attribute.Values[0]);
}
}

0; }
// Use this to convert it into JWT token and pass on to the web-api.
}
}
}
Since you are able to decrypt and find out the claims, you application assumes that it is being originated from your Dynamics CRM.
You can use these claims and then convert it into JWT token.
Hope this helps!
Discover more from Debajit's Power Apps & Dynamics 365 Blog
Subscribe to get the latest posts sent to your email.