I’m not sure how to condense 3 days of pain and desperation into a tip of the day but I shall try.
Do not use the same base domain for ADFS and CRM if you have other applications (e.g. a web site) requiring Single Sing-On (SSO) with CRM.
If you ever set up Internet Facing Deployment for CRM On-premises, you know that it is generally a small PITA. Some even make a living out of solving mysteries of IFD configurations. All you need is a CRM server, say crm.contoso.com, and an ADFS server, say adfs.contoso.com, both accessible from the outside (whatever outside means to you, it does not need necessarily to be public). Then a bit of magic grease and it’s all up and running.
The problems begin when you try to create a website that uses the same ADFS for user authentication. Thanks to Owin and Katana, it’s now a point-and-click exercise. Why would you want an SSO between CRM and the website? Well, how about hosting an ASP.NET page in IFRAME inside CRM form and passing the information between the form/CRM and the site? All without asking people to authenticate twice. (While we’re on the subject – the SDK sample is awfully out of date, don’t try this at home, I’ll get to it in a separate tip.)
In the configuration above, all works fine in ADFS 2.0 but fails in ADFS 3.0 (Windows Server 2012 R2). Both web site and CRM can authenticate independently, if you authenticate to the web site first, CRM will honor that authentication and won’t prompt, however, going from authenticated CRM session to the web site (the scenario that we actually need) fails miserably in an endless “please login” loop.
In the end I managed to trace it down to the web site sending existing cookies (that CRM authentication process has created) to ADFS but ADFS logs an obscure and exceptionally brief error “Ignore corrupted SSO cookie” and promptly redirects the web site to login. I even checked the cookies by hand. Yep, the very first one MSISAuth cookie (the one holding authentication information) is not a valid base64 string. Huh?
Digging deeper; there are two MSISAuth cookies, one for .contoso.com domain and another for adfs.contoso.com, latter being the invalid one. Huh?!
Long string of coffee cups, trials and errors followed by almost accidental discovery:
Using different domain name for ADFS server allows flawless SSO in both directions between your CRM and the web site
In the scenario above replacing adfs.contoso.com with adfs.osotnoc.com, for example, would do the trick. Of course you’ll need a domain and an SSL certificate but those can be had for less than all those cups of coffee put together. Changing name of your ADFS service is a bit tricky but can also be done.
To be honest, I still have no idea why it was happening but in the absence of any other information I squarely blame it on ADFS 3.0. People who actually know a thing or two about claims, authentication, tickets, cookies and goblins are more than welcome to drop a note or two shedding some light on the behavior.
Sounds like a similar issue I had integrating with Experlogix on a demo environment, this is a KB article from Microsoft https://support.microsoft.com/en-us/kb/3045286. Not sure if this explains things
Brilliant. I wish I found that 3 days ago but my weak google-fu failed me. On the positive note, I’m glad I didn’t find it because I would have reconfigured CRM URL instead of simply using a different domain for ADFS. I’ve been observing a slightly different behavior though as my duplicate cookie was coming across to ADFS as invalid but the core reason seems to be the same – duplicate cookie. ADFS is off the hook, CRM to blame 🙂
So you sign on to CRM with a lullaby? Single-Sing On….
In my opinion this is a 20/80 blame between CRM / ADFS
The main problem is that when adfs issues the cookie it stores it under the /adfs/ location (from memory, actual location could be different).
So you end up with two cookies on the contoso.com domain:
/MSAuth -> created by CRM
/adfs/MSAuth -> created by adfs
When ADFS tries to read the cookie it does not read the cookie from the location where it created it but rather it takes the first one that it finds in the domain. In my opinion, it it bothers to store a cookie in a predetermined location in should then use it to retrieve it.
It took me a few days to realise what was going on and come up with the same solution of changing the adfs domain.
Not sure why CRM has the cookie name hard coded rather than using the web.config as any other .NET web app. so simple web.config change would have fixed the problem!
Thanks, this problem has haunted us for many days. We use ADFS extensively, so we’re changing the domain name of our CRM application. We’ll use a new domain name (*.mynewdomain.com) for our CRM application versus going another level deep (*.crm.mydomain.com). Wonder why Microsoft did this?
We ran into this issue for a recent client we are working with. I had the opportunity to talk to the Microsoft PM that is responsible for Hybrid integration between AzureAD and on-Prem infrastructure. ADFS is a big part of that story and so I mentioned this issue to him. He was not aware of it and was going to reach out to the CRM team about why they issue a cookie with the same name, scoped to the domain which affects ADFS. I agree with Luis in that this is an 80% blame on CRM and 20% on ADFS for all the same reasons he noted.
In the end changing your ADFS domain or your CRM domain will do the trick.
Note that moving your ADFS Domain to a sub domain of say adfs.sub1.example.com will not do the trick when CRM is still issuing cookies as .example.com as browsers send domain scoped cookies to ALL hosts or sub domains in that domain. You have to get them on different domains, or in theory, move CRM to a sub domain of crm.sub1.example.com so that its cookies are then scoped to .sub1.example.com. I like moving to different domains as noted in this tip.
Does anyone know if this is resolved with ADFS 4.0?
as per the comments earlier, this smells like CRM issue and not ADFS. Having said that, ADFS 4.0 (Windows Server 2016) may or may not help but whatever the situation is, some re-testing will be due once Dynamics 365 On-premises is released
Any chance you’ve had reason to test this with Dynamics 365 on-premise or with ADFS 4? Are you still force to use a different subdomain for CRM and SharePoint with the same ADFS namespace?
We have the some problem. We have CRM and web resources in IFRAME accessing external web services using JQUERY. we could not share token between CRM and exernal web services.
is that possible?
Token-sharing is a no-no – creates nice security holes in your application. Instead, you should be using SSO approach if authentication to the web services is required.
Hello George. Thank you for the tip.
If we can get into the details a little bit more that would be great. We had prepared an enviroment with CRM IFD (crm.contoso.com) + ADFS (adfs.contoso.com) and a seperate web application (independent from crm – mywebsite.com). We had made our web application claims aware running with ADFS authentication. Then, had updated a crm form to include an iframe to display one of the web pages in web application. And as you have mentioned the SSO didn’t worked.
We have investigated it for a very long time and realized that when user sign on to CRM, ADFS creates 2 tokens just as you mentioned. One for ADFS and the second was for CRM. Since these cookies are HttpOnly, Secure and marked with private Path It’s not possible to share them with any other web application. Even if you can use the ADFS related cookie (created on CRM sign-on) for the external webpage it didn’t worked. I’ve also decrypted the MSISAuth tokens inside the cookies; Even the ADFS token was related to CRM. I mean when you browse CRM from the browser, you’re redirected to ADFS login page and the url contains wtrealm=https://crm.contoso.com. That means you’re making an authentication request to ADFS which is special to CRM website, and you definately cannot use that genereted ADFS token to access for another website. In fact it requires you to sign-in again for the new website you’re trying to access. So, SSO is not working with CRM IFD. And I’ve even discussed this with Microsoft officials and they claimed that this type of usage is not supported :).
Do you think changing the adresses will fix the issue?
we found that using a different [sub]domain works best. For example, we host Dynamics for customers using domain like https://foobar.crm2016.net while authentication is residing on https://login.elsewhere.com. It works for us well because we have multiple CRM versions, multiple domains, and multiple 3rd-party web applications all authenticating via the same domain-agnostic ADFS.
If you’re working in a specific domain, e.g. https://adfs.contoso.com, try using subdomain, e.g. https://org.crm.contoso.com as your organization endpoint.
As far as Microsoft officials are concerned, don’t believe everything you hear from them (whoever they are!). We have iframed scenarios up and running perfectly well (but we did go through the same hell before splitting the domains).
… and what to do for AJAX request to web applicaitons?
Consider that you have a web service (.aspx, .ashx, .svc, .whatever) and you have to call it via AJAX (jquery, angular, xmlhttprequest) from CRM Web Resource (not from an iframe or from a Crm Form itself). And the web service is hosted in IIS and configured for ADFS Authentication (instead of Windows Authentication). How can we make a HTTP call to web service? How can I access it?
I’ve been trying this for a very long time and gave up actually. I undertood that you were using iframes in Crm Form or in Crm Web Resource and the address of the iframe is an external domain (other than crm domain). In that situation your tip is working. Do you think the same solution may work in my case too? Have you ever tried it?
…And thank you for the fast response.
We are also facing this problem when windows hello came in the game, when user are logged on with user name an password sso works fine with adfs and crm 2013, but when users are loged on with face recognition or pin for windows hellow then SSO doesnt work any moren!
We have our crm and adfs in a specific domain.
e.g. https://adfs.contoso.com, and https://org.contoso.com
I’m trying to get to use subdomain, https://org.crm.contoso.com
Do i need to specify the bindings to accomodate the certificate for domain *.crm.contoso.com
which DNS entry’s do i need.
Does anybody have a clue what the steps are to get an existing crm organization to be changed to use the subdomain.
any help is appreciated,
there is a solution.
Please check Token decryption cert keyspec -if you see corrupted sso cookies error on ADFS
Thanks for the tip. We are seeing the same behavior after configuring CRM 2016 On-Prem to SharePoint Online integration. ADFS service name sts.contoso.com and CRM org.contoso.com. What we found interesting is that when a user sign into Office 365 first then login to CRM and from that point navigate to a SharePoint document location from CRM all works fine. However when a user login to CRM first then navigate to SP document location they a presented with ADFS login and fall into the infinite loop.
If we were to change the service name to sts.adfscontso.com will this fix our issue? I would prefer changing the service name instead of CRM since the users are already familiar with it.
Also would SharePoint integration need to be reconfigured?
You’re experiencing the exact behavior described. Works in one direction but not the other.
Renaming adfs will address the problem but you will have to reconfigure both CRM and sharepoint to use new adfs url. Use the links in the article to check how to rename your adfs domain – there is some magic involved.
Thanks George. I will be sure to post the the results after making the changes suggested.
I just want to give and update. I was able to successfully change adfs service name to a new domain.
However there were a few things that needed to be changed manually.
see link below for things that don’t change when you changed adfs service name to a new domain.
Even in the year 2022 this post is helping people. Thank you for this discussion, it is very appreciated. It is beyond me that they would pipe in all and take the last one, when there is a perfectly reasonable array type key to check first.