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!
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.
Once you sign in successfully you can see the home page of the application.
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!!!