Thursday, July 12, 2012

CRM 2011 / ADFS / IFD / 401 Global.ashx (now fixed, scroll to the end for the fix)

Recently I have been helping diagnose a problem with CRM and authentication.

This was not an issue before roll up 7, You do not get this issue with roll up 6 but you do get this issue with roll up 7 and 8.

CRM is hosted in our data centre and ADFS is used to authenticate. The issue reported was

“User can log in from a test PC in the data centre using the ADFS server in our data centre but user on the customer site cannot login, they keep getting a login box”.

 

Other symptoms are, a blank screen like :

image

If you are not a member of a group, you will see the user not a role message.

A work around is to enter a user name and password from our data centre’s domain. In other words log in as follows:

Login to CRM using the customers ADFS server but when we get challenged for a username and password enter it from the data centre’s AD. This is counter intuitive but does work and the user you are logged into CRM as is not the data centre account.

For example ( I use in inprivate session to make sure no auth cookies are cached )

I navigate to CRM and select the ADFS server that's in the domain that my PC belongs to, CRM is not in this domain.

Note, our ADFS server is sts1 (see the url) but I have selected dsladfs.diagonal-solutions.local (NT4 name MFTDEV) (this is a test domain and our old company name :) )

image

I then get asked for a username and password again.

image

As we can see, its asking to connect to crm.xxxx.local this is the CRM application hosted in our data centre not the selected ADFS log on server so this challenge is coming from CRM and not the ADFS server. If I put a user from the data centre it works, if I cancel I get the blank screen.

Now lets look at fiddler :

 

image

I have started from the crm.xxxx.local, got a 302 redirection this sends me to ADFS (sts1) and select diagonal (MFTDEV) as my auth domain this challenges me as I am part of this domain IE just handles this. I then get sent back the CRM. main.aspx loads correctly, but when IE requests global.ashx I get a 401. If we look at this in more detail we can see that the cookies are being sent :

image

 

Technical Investigation

We have now seen the problem, for further testing I just used fiddler, if I just reissue the request I get the same issue.

Do we get this for other files? If I copy global.ashx to test.ashx and used fiddler I don’t see this issue.

If I create a new file :

image

Then use fiddler to ‘get’ this

image

It works, HTTP 200 result and I can see the script. (Bottom right hand pain).

if I remove the cookie, i get the following :

image

I used Composer to edit the headers and remove all cookies, I get a 302 and a redirect the the STS server. This is what I would expect as I have no auth tokens.

If I do the same, but with Global.ashx I see (first one with cookies, second without)

image

 

As you can see, both request get a 401. One should get a 302 and the other a 200.

I am going to raise this with MS and while they look into it I am going to see if I can find a work around (watch this space).

 

What is causing this?

A colleague of mine (Terry Rogers) have helped decompile the code we can see that

There is a check in the MainApplication HttpApplication class (which would have been compiled from the global.asax file) that checks for certain page requests, including global.ashx.

It looks like this check is to determine does the current user have any role (either against the user, or against a team they are a member of), and if not redirect to the error page indicating there is no role.

It seems likely that this check, at the PostAuthenticateRequest phase of the application lifecycle, is getting the details of the user in a way that can cause IIS/asp.net to challenge for a windows authentication, where the claims based identity should be used.    

The Fix

We need to trick the code into not checking perms to serve this file. This is not a security risk as this is just static script files loaded from the server.

Step 1

Open C:\Program Files\Microsoft Dynamics CRM\CRMWeb\_common  ( or your CRMWeb\_common folder)

Copy _Global.ashx to _Global_.ashx and ScriptResx.ashx to ScriptResx_.ashx

You will now have

image

Step 2

 

Edit web.config under C:\Program Files\Microsoft Dynamics CRM\CRMWeb

Just before the </rules> add

        <rule name="globalashx" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/_Common/global.ashx" />
          <action type="Rewrite" url="{R:1}/_Common/global_.ashx" />
        </rule>
        <rule name="ScriptResx.ashx" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/_Common/ScriptResx.ashx" />
          <action type="Rewrite" url="{R:1}/_Common/ScriptResx_.ashx" />
        </rule>

Your <rules> section will now look like

      <rules>
        <rule name="ClientGlobalContextRule" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/?((?:%7b|\{)[^/]*(?:%7d|\}))?/?(WebResources|Handlers)/ClientGlobalContext.js.aspx" />
          <action type="Rewrite" url="/{R:1}/_Common/ClientGlobalContext.js.aspx" />
        </rule>
        <rule name="WebResourcesRule" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/?((?:%7b|\{)[^/]*(?:%7d|\}))?/?webresources/([^\\?]+)" />
          <action type="Rewrite" url="/{R:1}/Handlers/WebResource.ashx?name={R:3}" />
        </rule>
        <rule name="FederationMetadataRule" stopProcessing="true">
          <match url="FederationMetadata/2007-06/FederationMetadata.xml" />
          <action type="Rewrite" url="/Handlers/FederationMetadata.ashx" />
        </rule>
        <rule name="globalashx" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/_Common/global.ashx" />
          <action type="Rewrite" url="{R:1}/_Common/global_.ashx" />
        </rule>
        <rule name="ScriptResx.ashx" stopProcessing="true">
          <match url="/?([0-9a-zA-Z][^/]*)?/_Common/ScriptResx.ashx" />
          <action type="Rewrite" url="{R:1}/_Common/ScriptResx_.ashx" />
        </rule>
      </rules>


What next?

Well…. lets hope its fixed in Roll Up 9 and if it isn't fixed lets hope that above fix still works :)