Tutorial: Mvc application using Azure acs and forms authentication Part 1


A few months ago I created a post which described a method for adding single signon services to an asp.net mvc website using Windows Azure ACS. The workflow involved allowing users to signup using forms authentication then associating their on-site identities with their facboook, google, yahoo and windows live identities. This post is meant to be a more detailed followup which will take you through  some other things not covered in my original post.

The tutorial steps are as follows:

  • Create an asp.net mvc 3 web application with forms authentication
  • Register a new user
  • Add Azure ACS sts reference to application
  • Alter web.config to allow both sts and forms authentication
  • Add database table to store mappings between identities and user accounts
  • Create a custom class for extracting required claims
  • Create a special controller action which Azure ACS will call to sign users in
  • Create Hybrid login page with new functions
    • Login with forms
    • Login with ACS
    • Prompt user to login and complete association process

Here is the workflow from the original post:

Assumptions about audience

Please ensure you have the following before proceeding with this tutorial

  1. Windows aure account
  2. Azure Access Control Services (ACS) working
  3. Windows Identity Framework Installed and working
  4. Basic understanding of Asp.net memberships
  5. Comfortable with Asp.net MVC
  6. Visual Studio 2010
  7. You have SQL express installed with required permissions
  8. You have experience with ACS/STS either through your own projects or tutorials such as on acs.codeplex.com
Again, If you have not been able to get ACS working using other samples and tutorials then it will be very difficult for you to follow this tutorial as I will not go into detailed explanations about setting up ACS, installing the Windows Identity Framework and Asp.net memberships.


Creating the Project

We will start by creating a new Asp.net MVC 3 project. I called mine MVC3MixedAuthenticationSample

Use the “Internet Application” template

Once the project is created add a reference to the Microsoft.IdentityModel assembly.

You should have a working Asp.net MVC 3 application at this point. The asp.net database will be created in the App_Data folder when we run the application.

Now run the project and register a new user. I called mine bob and gave him the password ‘password’.

Your new user should now be logged into the site. You can also use the asp.net configuration tool to add a new user (you must build the project first). If you get any errors while attempting to add a new user you probably don’t have the correct permissions to the App_Data folder in the project or to sql express. There are several things you can try to resolve this issue that I can mention later if needed.

Our next step will be to include the newly created database in our project. This file is hidden by default so click the second icon from the left below “Solution Explorer” to show hidden files.

The database should now appear in the list of databases on the server explorer. Right click on the Tables node to add a new table.

The new table will store the mappings between the acs identities and the local users.

Remember to enable auto increment for the primary key (IdentityID)

Save table and call it UserIdentity

Now we need data access to our new table and any other tables related to it. I decided to use entity framework for this but you can use any ORM or simple ADO.NET if you like. Many people are reading this because they want to modify their existing projects so they may be using something else for data access. However, the principles are the same.

Create a new entity data model and opt to generate the entity from a database.

The “ApplicationServices” connection should already be selected. If not, select it. If it is not there, I would say add it but it not being there might be a symptom of a bigger issue.

Add the UserIdentity table to the model. I have the aspnet_users table selected but it is not required since we will be using the asp.net membership api for everything related to local users.

Now that the database and data access is setup we can add a reference to the Azure ACS STS.

Please fill in the url for the mvc application

Select “Use an existing STS” and paste in the link to your ACS metadata. This can be found in your Azure control panel.

The following claims will be used to associate users with their identities

The wizard automatically disables forms authentication so the next step is to edit our web.config and turn forms authentication back on.

Open the web.config and find the attribute passiveRedirectEnabled and set  it to false.

<wsFederation passiveRedirectEnabled="false" issuer="https://[namespace].accesscontrol.windows.net/v2/wsfederation" realm="http://localhost:52119/" requireHttps="false" />

Find the following and comment it out:

<authentication mode="None" />

Find the following and uncomment it:

<!--<authentication mode="Forms"><forms loginUrl="~/Account/LogOn" timeout="2880" /></authentication>-->

Find the following and comment it out:

<authorization>
 <deny users="?" />
 </authorization>

At this point you should be able to login to run the application and login with the user you created at the beginning.

Next we will Create a new class called IdentityClaim which we will use to extract the claims from the sts response. I added mine to the Models folder. Please note the using statement for Microsoft.IdentityModel.Claims.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.IdentityModel.Claims;

namespace MVC3MixedAuthenticationSample.Models
{
    public class IdentityClaim
    {
        private string _identityProvider;
        private string _identityValue;
        public const string ACSProviderClaim = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";

        public IdentityClaim(IClaimsIdentity identity)
        {

            if (identity != null)
            {
                foreach (var claim in identity.Claims)
                {
                    if (claim.ClaimType == ClaimTypes.NameIdentifier)
                    {
                        _identityValue = claim.Value;
                    }
                    if (claim.ClaimType == ACSProviderClaim)
                    {
                        _identityProvider = claim.Value;
                    }

                }
            }

        }

        public IdentityClaim()
        {
            _identityProvider = HttpContext.Current.Session["IdentityProvider"] as string;
            _identityValue = HttpContext.Current.Session["IdentityValue"] as string;
        }

        public bool HasIdentity
        {
            get
            {
                return (!string.IsNullOrEmpty(_identityProvider) && (!string.IsNullOrEmpty(_identityValue)));
            }
        }

        public string IdentityProvider
        {
            get
            {
                return _identityProvider;
            }
        }

        public string IdentityValue
        {
            get
            {
                return _identityValue;
            }
        }

        internal void SaveToSession()
        {
            HttpContext.Current.Session["IdentityProvider"] = _identityProvider;
            HttpContext.Current.Session["IdentityValue"] = _identityValue;
        }

        public static void ClearSession()
        {
            HttpContext.Current.Session.Remove("IdentityProvider");
            HttpContext.Current.Session.Remove("IdentityValue");
        }

        public static string ProviderNiceName(string identityProivder)
        {
            if (identityProivder.ToLower().Contains("windowslive"))
                return "Windows Live";

            if (identityProivder.ToLower().Contains("facebook"))
                return "Facebook";

            if (identityProivder.ToLower().Contains("yahoo"))
                return "Yahoo";

            if (identityProivder.ToLower().Contains("google"))
                return "Google";

            return identityProivder;
        }
    }

}

In my next post I will talk about creating the new controller action that will support Azure ACS signin and modifying the generated logOn page to include both the ACS buttons and the regular forms authentication option.

About these ads

13 Responses to Tutorial: Mvc application using Azure acs and forms authentication Part 1

  1. chikkanti says:

    hello…. i am venkat ur blog is very nice….
    i am also using wordpress blog… you displayed code in original coloured format as above it was nice,,, i am also trying to display like that but it is not possible,..
    will u plz tel me how to display the code in post as u displayed above….
    plz…

    • Garvin says:

      Hi, here is a sample

      [sourcecode language="csharp"]
      string greeting = "Hello World";
      [/sourcecode]
      
      [sourcecode language="xml"]
      <root>
      <node id="1">
      </node>
      </root>
      [/sourcecode]
      
      • chikkanti says:

        k… you are displaying ok… but i need how to display like that which options i need to use…
        don’t mind i am asking like this….

  2. Garvin says:

    I am not sure what you are asking. I showed you the tags you need to use to display formatted code.

  3. Pingback: Tutorial: Mvc application using Azure acs and forms authentication Part 2 « My Random Stuff

  4. kmatth007 says:

    I am using this example and I get the The remote server returned an error: (404) Not Found.
    This appears to be causing the code string response = client.DownloadString(request.GetUrlWithQueryString()); I used the FederationMetadata for my clients adfs server which I have not access to so that may be the problem. I am running from my dev box. Thanks

    • Garvin says:

      Hi, this part of the script is specific to azure ACS. If you are using adfs then you will need to generate your own singin links/buttons

  5. Lincoln says:

    this is for my own reference and may help other. I’m using VS Web Express 2010 under Win 7, option Add STS Reference is not available in VS. So to perform the same steps as I used the Windows Identity Foundation Federation Utility (under Start menu after install WIF).

    The link to FederationMetadata.xml is typically https://%5Bthenameyougivetoacs%5D.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml

    which can be found on your Access Control Service page (browse from WIndows Azure on web browser) > Application integration menu > in Endpoint reference listing: WS-Federation Metadata Exchange.

    • Lincoln says:

      my typo: “same steps as in the tutorial”

  6. Riccardo says:

    Nice blogpost. I followed a part of this blog post to realize my blog post, which explains using claims based authentication with OData (a rest based service hosted in Windows Azure). You can find it here if you are interested: http://riccardocorradin.wordpress.com/2012/09/20/claims-based-authentication-with-odata-and-windows-azure-3/

    • Garvin says:

      You are welcome. Would appreciate a link back!

  7. nikivancic says:

    Great article, I am quite happy that I found it. Is it possible that you have the most current version which uses WIF bundled with .NET 4.5 and Identity and Access Tool in VS 2012 context?

    • Garvin says:

      I do plan to release a supplemental post on wif in visual studio 2012 and asp.net 4. However, right now I cannot tell you when that will be.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: