Gaurav Mantri's Personal Blog.

Using Windows Azure Access Control Service (ACS) in MVC 5 Application Using Visual Studio 2013

It has been a while that I wrote a technical post:). Today I ran into a post on Stack Overflow and that made me write this post. If you have used Visual Studio 2012, you would know how easy it is to implement Windows Azure Access Control Service (ACS) in your web applications. This is accomplished by Identity and Access Tools extension. Unfortunately this extension is not available for Visual Studio 2013.

There’s a saying that “Little knowledge is a dangerous thing” and today I fell victim of that :). Without realizing that there’s indeed a way to achieve this in VS 2013, I went all out and proposed a hack. Only after I published the blog, it has been brought to my attention that I was wrong (thank you Erik for that). So now we have 2 ways to achieve this: one elegant way and other the hacky way :).

The Elegant Way

To do so in VS 2013, the steps are rather simple. When you create an MVC Application click on “Change Authentication” button and then select “Organizational Accounts“. From the options dropdown, select “On-Premises” option. For “On-Premises Authority“, specify the Federation Metadata URL (https://{youracsnamespace}.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml) and for “App ID URI” specify your application URL and you should be good to go!

so

so2

The Hacky Way

The approach is rather simple. Assuming you have this Identity and Access Tools extension installed, what you do is you create a Web project in VS 2012 (an empty MVC application will do). Once the project is created, using this extension you configure ACS in your project. Once the ACS is configured, you would see that there’re a lot of entries in your web.config file related to ACS. You just copy them from your VS 2012 project and paste them into VS 2013 project’s web.config file. You may need to add some extra DLL references which we will talk below.

Changes

As mentioned above, what I did was created an empty MVC project in VS 2012 and then configured ACS for that project. Then I created an MVC application in VS 2013 and chose “No Authentication” option for my application. After that I made following changes to the web.config file in my VS 2013 project by copying some items from web.config of VS 2012 project.

Copy <system.identityModel> and <system.identityModel.services> Sections

Copy <system.identityModel> and <system.identityModel.services> sections in its entirety from source web.config file to destination web.config file.

  <system.identityModel>
    <identityConfiguration>
      <audienceUris>
        <add value="{yourwebapplicationurl}" />
      </audienceUris>
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="https://{youracsnamespace}.accesscontrol.windows.net/">
          <keys>
            <add thumbprint="{certificatethumbprint}" />
          </keys>
          <validIssuers>
            <add name="https://{youracsnamespace}.accesscontrol.windows.net/" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>
  <system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="https://{youracsnamespace}.accesscontrol.windows.net/v2/wsfederation" realm="{yourwebapplicationurl}" requireHttps="false" />
    </federationConfiguration>
  </system.identityModel.services>

Add system.identityModel and system.identityModel.services Sections to <configSections>

Copy system.identityModel and system.identityModel.services sections from source web.config file to destination web.config file by adding them under <configSections> node.

  <configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  </configSections>

<appSettings> Section Changes

Add the following settings to <appSettings> section of destination web.config file.

    <add key="ida:FederationMetadataLocation" value="https://<youracsnamespace>.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml" />
    <add key="ida:Issuer" value="https://{youracsnamespace}.accesscontrol.windows.net/v2/wsfederation" />
    <add key="ida:ProviderSelection" value="ACS" />

Copy “FederationMetadata” Folder

Copy “FederationMetadata” folder from source project to destination project and add following lines to destination web.config file.

  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>

Disable Anonymous Access

Next disable anonymous access by adding the following lines of code under <system.web> section of destination web.config file.

    <authorization>
      <deny users="?" />
    </authorization>
    <authentication mode="None" />

Add Authentication Module

Next add “WSFederationAuthenticationModule” and “SessionAuthenticationModule” by adding under <modules> section in <system.webServer> section in destination web.config file.

      <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />

System.IdentityModel.Tokens.ValidatingIssuerNameRegistry

You will need to add a reference to “System.IdentityModel.Tokens.ValidatingIssuerNameRegistry” library which you can do via Nuget.

That’s pretty much it. Now when you run the application, you will be redirected to ACS.

image

Once you sign in successfully you can see the home page of the application.

image

Complete Web.Config file

Here’s the complete web.config file which I used in my project. Please make appropriate changes to meet your requirements.

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=301880
  -->
<configuration>
  <configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  </configSections>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="ida:FederationMetadataLocation" value="https://{youracsnamespace}.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml" />
    <add key="ida:Issuer" value="https://{youracsnamespace}.accesscontrol.windows.net/v2/wsfederation" />
    <add key="ida:ProviderSelection" value="ACS" />
  </appSettings>
  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules>
      <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
    </modules>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.identityModel>
    <identityConfiguration>
      <audienceUris>
        <add value="{yourwebapplicationurl}" />
      </audienceUris>
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="https://{youracsnamespace}.accesscontrol.windows.net/">
          <keys>
            <add thumbprint="{certificatethumbprint}" />
          </keys>
          <validIssuers>
            <add name="https://{youracsnamespace}.accesscontrol.windows.net/" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>
  <system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="https://{youracsnamespace}.accesscontrol.windows.net/v2/wsfederation" realm="{yourwebapplicationurl}" requireHttps="false" />
    </federationConfiguration>
  </system.identityModel.services>
</configuration>

Summary

That’s it for this post. I did all of this in less than an hour so I’m pretty sure that there is certainly a lot of scope for improvement. If you think there’re some or I have made some errors, please let me know so that I can fix it ASAP.

Happy Coding!!!


[This is the latest product I'm working on]