Category Archives: IIS

ASP.NET OpenID/OAuth Login With ASP.NET 4.5 – Part 1

With ASP.NET 4.5 it is very easy to enable users to login to your site with their accounts from Facebook, Google, LinkedIn, Twitter, Yahoo, and Windows Live. In this 7 part series I’ll show you how for each of the identity providers.

Note: Out-of-the-box this only works with WebForms and MVC4. MVC3 is not supported by default.

Part 1: Setting up your development environment

Create a website project in Visual Studio

You’re going to need a website project for any of this to work, and you may have to configure some of it later. So first, let’s create a project.

  1. Fire up Visual Studio (Express will work just fine).
  2. From the menu select FILE > New Project…
  3. Select one of the Web Application projects. In this example I’ll use ASP.NET MVC 4 Web Application.
  4. Click OK.
  5. Select Internet Application. This is the only template that includes the OpenID/OAuth stuff by default.
  6. Click OK.
  7. The project is ready. You may want to run it once just to make sure everything works. Be sure to click Register and then register for an account to see if the database is working.

Setting up your development environment

In most cases you need to register you website with the identity provider to be able to authenticate users with that identity provider. The provider will ask for several pieces of information, most notably a URL. The problem is that this can’t be an IP-address, and can’t be localhost. Most identity providers also don’t allow a port number, so you will have to ensure that your development website can be reached at port 80 (or port 443) and on a valid URL.

Getting a valid URL

Getting a valid URL is mainly about using a domain that an identity provider will recognize as valid and public. You can get one setup for your application in three ways:

  1. Modify your hosts-file to contain the desired URL.
  2. Open notepad as Administrator.
  3. Click File > Open and navigate to the C:\Windows\System32\drivers\etc folder.
  4. Select All Files (*.*) as filter so the files with no extension show up, as shown below.
  5. Open the hosts file.
  6. Add a line for IP-address 127.0.0.1 with the domain you want to use with your application, as highlighted below.
  7. Save the file.
  8. Use a public domain of your own and modify add a DNS entry for your application. How this works depends on your hosting provider, so I won’t elaborate in this.
  9. Use the localtest.me domain. This is a very neat trick by some clever guys. They’ve setup a DNS that will route any localtest.me request to 127.0.0.1, your local computer. That includes the root domain itself, but any subdomain or sub-sub domain (or sub-sub-sub domain… you get the idea), will work. The only domain that doesn’t work is http://readme.localtest.me, because that’s where you can find the documentation and background. The great thing is that this works without registering or anything. For my demo’s I will use http://michiel-security-demo.localtest.me.

Setting up IIS

Besides having a public domain, your application needs to run on port 80. Although this is possible with IIS Express, it is much easier using IIS (if you want to tinker with IIS Express, check Scott Hanselman’s post Working with SSL at Development Time is easier with IISExpress). The one proviso is that IIS can’t work with LocalDB, so you will have to use SQL Server (Express) instead. For the description below I will assume you have SQL Server Express installed. The best way to go about this is creating a new Web Site in IIS with a custom host header. The steps are easy:

  1. Start the IIS Manager.
  2. In the Connections pane navigate the tree to the Sites folder.
  3. Right click Sites and select Add Website…
  4. Set the Site name and under Physical path browse for the application folder created by Visual Studio.
  5. Under Host name set the host header, in my case michiel-security-demo.localtest.me.
  6. Click OK.

Now you need to point Visual Studio to use IIS, instead of IIS Express when you debug.

  1. Open your project in Visual Studio (if not already open).
  2. Right click the project and select Properties.
  3. Select the Web tab, and scroll down to where it says Use Local IIS Web server.
  4. Uncheck Use IIS Express.
  5. You will be warned that you can’t use LocalDB with IIS with the dialog below. Click Yes.
  6. Enter the Project Url, in my case http://michiel-security-demo.localtest.me/. The settings now should look like the image below.
  7. Click Save.
  8. Start the project in debug mode to verify that everything is working under the specified URL.

Although IIS points to the right folder, it needs permissions to read the folder. If that is not the case, you will get a HTTP 500.19 error when you run the application. You can solve this as follows:

  1. Open Windows Explorer.
  2. Navigate to the application folder.
  3. Right click on the application folder and select Properties.
  4. Go to the Security tab and ensure IIS_IUSRS has read permissions. If so, skip the next steps.
  5. Click Edit…
  6. Click Add…
  7. Enter IIS_IUSRS and click OK.
  8. Click OK twice.

Intercepting a 404 in IIS 7 and up

Lately I’ve been working on a system that needs to serve flat files, which is what IIS is very good at. However, when a file does not exist (i.e. a 404 error occurs) there are several options:

  1. The file never existed: propagate the 404.
  2. The file did exist, but has been permanently removed: return a 410 (Gone).
  3. The file did exist, but a newer version is available. In our system a different version always gets a new identifier and as such a new URL, so this is a common scenario for us: redirect the user to the new version.

So the question is: How do we intercept the 404 error for any file?

The answer: With an IIS HttpModule, which is pretty much the same as an ASP.NET HttpModule, as the code below demonstrates.

using System;
using System.Net;
using System.Web;

namespace IisModule
{
    public class DemoModule : System.Web.IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(System.Web.HttpApplication context)
        {
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            var context = (HttpApplication)sender;
            if(context.Response.StatusCode == (int)HttpStatusCode.NotFound)
            {
                context.Response.Redirect(“http://michiel.vanotegem.nl/”);
            }
        }
    }
}

The only place where you can check for a 404 error is at EndRequest. Other events get bypassed, including the Error event. However, as you can see in the code, getting the response code is easy. And after checking it you can do a redirect or change the response and response code (don’t forget to clear the response stream). You need to add this code to a Class Library project in Visual Studio, to which you will have to add a reference to the System.Web assembly. Also, this does not work with .NET 4.0 and up (except in Windows Server 2012), so you’ll need to configure the project to target the .NET 2.0 runtime, which is the case for .NET 2.0 through 3.5, as is shown below.

Configuring IIS

First you have to create a /bin folder in the website you want the module to work in, and copy the DLL to the bin folder. If you want this on the Default Web Site, you need to add this to C:\inetpub\wwwroot (assumming C is your OS drive), as shown below.

Second, you need to fire up IIS Manager to add the Managed Module to the Web Site. Select the Website (in my case Default Web Site) and select Modules, as highlighted below.

Now click Add Managed Module… as highlighted below.

Finally, give the new module a name, so you can recognize it in the list of modules active for the website, and select the module in the dropdown, as shown below, and click OK.

That’s it! Now every 404 will redirect the user to the root of my blog.

Configuring IIS for all sites

If you don’t want to have a /bin folder in your site, and all sites hosted on the system require the same behavior, you can also sign the assemly, place it in the GAC, and configure the Module at server level.