Forcing IIS to rewrite all requests to HTTPS

I often need to ensure that an IIS web site uses HTTPS instead of HTTP. The easiest way to do this is with a URL rewriting rule. The rule I use is below.

<rule name="Redirect to HTTPS" stopProcessing="true">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
        <add input="{HTTPS}" pattern="^OFF$" />
    </conditions>
    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>

This will redirect any request that is not “HTTPS” to an “HTTPS” address.

Stopping Internet Explorer 11 from showing the mobile express version of Dynamics CRM 2011

If you have a Dynamics CRM 2011 installation, and users have started using Internet Explorer 11 (either by upgrading from IE10, or by installing Windows 8), then you’ve undoubtedly noticed that, when an IE11 user goes to your CRM site, they are greeted by the Mobile Express version, rather than the standard site. There are a few manual workarounds to this:

  • Downgrade from IE11 to IE10 (not an option for Windows 8).
  • Add your CRM domain name to the compatibility list in IE11 (not an option if you don’t want the entire domain to be in compatibility mode, or if you have group policy settings which prohibit this).
  • Instruct users to go to https://yourcrmdomain.com/main.aspx.

That third bullet is interesting… If you go to the root of your CRM domain name in IE11, you will be redirected to the Mobile Express site. If you go to the “main.aspx” page on the root, you go to the full CRM site. Which got me thinking… How can we identify IE11 users accessing the Mobile Express site, and redirect them to /main.aspx?

The solution is in IIS’s URL Rewrite library, which, if you don’t already have, you should get, because I’ve used it before to fix issues related to Dynamics CRM (not to mention its multitude of other uses).

Here’s what our rewrite rule will do:

The full IIS rewrite rule is below. You can drop this into the web.config in the root of your Dynamics CRM 2011 web site, or set it up manually using the URL Rewrite wizard. Either way, when you’re done, you’ll always get the full version of Dynamics CRM when using the IE11 browser.

<rule name="Redirect IE11 from mobile site to main.aspx" patternSyntax="Wildcard" stopProcessing="true">
 <match url="*m/default.aspx" />
 <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
 <add input="{HTTP_USER_AGENT}" pattern="*; rv:11.0) like Gecko" />
 </conditions>
 <action type="Redirect" url="https://crm.innovatix.com/main.aspx" redirectType="Temporary" />
</rule>

By the way, there is only one gotcha: You can’t use IE11 and deliberately go to the Mobile Express site. A small price to pay to fix a much larger problem.

URL Rewriting for user-friendly URLs with Dynamics CRM 2011

Anyone who has attempted to configure Dynamics CRM 2011 with an Internet-Facing Deployment (IFD) knows that it is no trivial task. Where there are blog posts that discuss setting up an IFD, and Microsoft documentation for configuring the IFD, they often assume that ADFS and Dynamics CRM are installed on the same server, and that there is only one Dynamics CRM front-end server. Unfortunately, real-world implementations don’t always follow that.

For example, take the following configuration:

  • a Dynamics CRM front-end server on the internal network, providing services to internal clients
  • a Dynamics CRM front-end server in an Internet-facing zone, providing services to external clients
  • a separate ADFS server accessible to internal and external clients

Dynamics CRM with IFD requires a combination of ADFS relaying party trusts and DNS configuration to get things working. One caveat with IFDs is that the internal and external host names for the Dynamics CRM front-end servers must be different because, externally, the host name includes the CRM organization name. Where, internally, you may have https://icrm.contoso.com/crm, externally you would have https://crm.contoso.com.

Let’s flesh out our sample implementation and requirements:

  • icrm.contoso.com is our internal Dynamics CRM front-end server, accessible only on the internal network
  • ecrm.contoso.com is our external Dynamics CRM front-end server, accessible to our internal network and the public Internet
  • adfs.contoso.com is our ADFS server, accessible to our internal network and the public Internet
  • We have two Dynamics CRM organizations: CRM and CRM-Test.
  • We want our internal and external (public Internet) clients to access CRM using the same URLs: crm.contoso.com and crm-test.contoso.com. In other words, we don’t want the two-URL problem outlined above.

The last bit has nothing to do with Dynamics CRM: it is all done in IIS. Let me explain how. Continue reading

Troubleshooting Windows Authentication in IIS

In a recent deployment of Microsoft Dynamics CRM 2011, users were accessing the application via the server’s host name, e.g. https://crmserver01.company.com. That is rather unfriendly, so we created a new DNS record for crm.company.com — giving users the easier-to-remember https://crm.company.com (and removing a dependency on a server name).

Unfortunately, authenticating to https://crm.company.com didn’t work for Internet Explorer users. IE would prompt for the credentials, but they were never accepted. Authentication did work for other browsers, and all browsers — including IE — were able to authenticate to https://crmserver01.company.com without issue.

This didn’t make sense. The domain name of the server shouldn’t matter (both were in IE’s Local Intranet Zone), nor should the browser version. But the different experience between browsers was all I had to go on, so I did some (network) sniffing.

Using Fiddler2 to monitor the network traffic created by web browsers, I opened Firefox and connected to http://crm.company.com (no SSL, so it’s easier to monitor network traffic). Firefox prompted me for my password, I typed it in, and was taken to the Dynamics CRM “unsupported browser” page. (That lack of support for non-IE browsers is a separate issue, but a fix is supposedly in the works.)

Here’s what Fiddler reported for those requests. I’ve truncated the request/response text to only show what’s relevant.

  1. Request
    GET http://crm.company.com
  2. Response
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
  3. Request
    GET http://crm.company.com
    Authorization: NTLM <token>

The responses after that don’t matter; I’m connected. I then did the same steps with Internet Explorer: connected to http://crm.company.com, get prompted for the password, type the password, get prompted again, wash rinse repeat two times, then get the boilerplate “401 Unauthorize” page. Here’s the Fiddler report:

  1. Request
    GET http://crm.company.com
  2. Response
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
  3. Request
    GET http://crm.company.com
    Authorization: Negotiate <token>

IIS7 comes with Negotiate (Kerberos) and NTLM providers for Windows AuthenticationNote the difference? Firefox uses NTLM to authenticate; IE uses Negotiate (Kerberos). This was the root of the problem: Kerberos isn’t permitted to authorize users accessing crm.company.com, but it is permitted to authorize users accessing crmserver01.company.com. NTLM doesn’t have that restriction. So, it’ll always work in non-IE (non-Kerberos) browsers; and it will work to the host name URL in IE browsers; but it won’t work to the alternate host name in IE.

How do you fix this? By reading the blog post, Configuring and Troubleshooting NTLM and Kerberos on Windows 7 (Windows Server 2008) and IIS7. Essentially, you tell the server to allow Kerberos to the “other” domain name by running the following command from the console: setspn -A HTTP/crm.company.com crmserver01

Another solution is to configure your web site to only use NTLM authentication, or to give NTLM authentication higher priority than Kerberos. However, this is more a workaround than a fix: the point of IE/Windows is to use Kerberos, not to avoid it. Still, it’s an option if you can’t run the setspn command for some reason.

Once you do either of those, all browsers will work to either domain name, as you would expect, and your users will be happy. :)

Installing and configuring memcached and PHP on Windows

After upgrading the CSFBL forums to vBulletin 4.0, I noticed that performance was slightly worse than in the previous version. A little searching revealed that vBulletin supports memcached (an in-memory distributed caching system). Since I’ve got RAM to spare, I figured this is worth a shot.

Unfortunately, getting memcached running on the server (Windows Server 2008 R2 64-bit) took a few tricks, and getting memached running through IIS/PHP was another. To help other people through the same process (and to remind myself in the future), I’ll share the installation and configuration steps that worked for me below.

Downloading and configuring memcached

The official distributions of memcached are written for Linux systems, so the first task is finding Windows binaries. The memcached project site, fortunately, has links to Windows binaries, which are hosted by NorthScale. Both 32-bit and 64-bit versions are available.

(Note that NorthScale also offers their own free distribution of memcached, but I was unable to get this to run on my system.)

Versions of memcached prior to 1.4.5 supported a command-line option that would register memcached as a Windows service (as in memcached -d install), but this option was removed in version 1.4.5. The simple alternative is to schedule memcached.exe to run using the Task Scheduler service (Windows 2008/Vista/7).

You can create a task to run memcached on system startup using the following command line:

schtasks /create /sc onstart /tn memcached /tr "'c:\dev\utils\memcached-amd64\memcached.exe' -m 128"

Note the -m 128 argument; this tells memcached to use up to 128MB of RAM. There are other command line arguments available; most useful aside from -m are -l (to specify what IP addresses to bind to) and -vv (to add verbose logging to the console, useful for testing).

Integrating memcached with PHP

In order for PHP to use memcached, you must download the PHP memcached library and add it as an extension to PHP.

PHP extensions can be downloaded from http://downloads.php.net/pierre. Many different extensions are in here; the one I used was php_memcache-5.2-nts-Win32-vc6-x86-20090408.zip. This extension matches two key requirements:

Getting the right version of the extension is important; download the thread-safe version, or the PHP 5.3 version, and it simply won’t work.

Once downloaded, take the php_memcache.dll and put it in the ext folder in your PHP directory (for me, c:\Program Files (x86)\PHP\ext). Then, open the php.ini file (in your PHP directory) and add the following line to the end:

extension=php_memcache.dll

Restart IIS (from the command line, type iisreset), and if you did everything right, memcached should now be available to PHP. If you want to check, you can create a phpinfo page; if php_memcache is listed in the output, the extension is registered correctly.

Other links

To find out more about PHP, memcached, and Windows, check out the following links.