Azure Accenture Control Services (ACS) allows you to secure an application (i.e. Relying Party, RP), by federating to a variety of Identity Providers (IdPs). Once you set your Relying Party application to use federated security with Azure ACS, you can chose combinations of Facebook, Windows Live ID, Google and Yahoo to secure your application. You can also use a WS-Federation IdP. This is typically Active Directory Federation Services 2.0 (ADFS 2.0), but you can also write your own IdP.
In this post I am going to walk you through the process of creating your own IdP (based on one of the Windows Identity Foundation Visual Studio 2010 templates). I will configure ACS to use this, and build a Relying Party web application that is secured passively by ACS (in turn using my IdP).
Disclaimer: This walkthrough talks you through the key parts of creating a custom Identity Provider (IdP), but there are additional steps you would want to follow in order to build this for a production environment (such as encrypting tokens, using certificates signed by an appropriate certificate authority and restricting the custom Identity Provider to only allow it to be referenced from Azure ACS).
To create and configure your custom IdP you will need…
In my walkthrough, I will create two web applications on my local machine, one for my Identity Provider, and one for my test Relying Party.
Local URLs used:
When building our IdP, we need to sign the security token that it will generate. We will also run our custom IdP over SSL for enhanced security. To do this in a development scenario, we will use MakeCert.exe to generate a self-signed certificate. As mentioned above, on a production environment you should obtain a certificate signed by a trusted certificate authority.
To generate a self-signed cert, first open a Visual Studio Command Prompt (Start –> Microsoft Visual Studio 2010 –> Visual Studio Tools –> Visual Studio Command Prompt (2010)).
Run the following command (replacing the *.mcsuk.dev with the destination url of your IdentityProvider IdP).
MakeCert.exe -r -pe -n "CN=*.mcsuk.dev" -sky exchange -sr localmachine -ss my -len 2048 -e 10/25/2013
MakeCert.exe -r -pe -n "CN=*.mcsuk.dev" -sky exchange -sr localmachine -ss my -len 2048 -e 10/25/2013
Note: in this example, I generated a wildcard certificate. The reason for creating a wildcard cert is that this allows you to enter a host header in iis (otherwise, all HTTPS IIS requests on your local machine would need to use this certificate. NB. Make sure your wildcart cert contains at least two segments (you will receive a certificate error when you browse to your site otherwise, indicating that your website does not match the certificate.)
When building for development purposes on your local machine, if you browse to a site over https (that uses your self-signed certificate), you may experience a certificate error as follows:
To avoid such errors, locate and copy the certificate to “Trusted Root Certification Authorities\Certificate”. [Note, if you’ve got a certificate signed by a trusted root authority, as would be required for a production environment, these steps are not required]
The next step is to export your certificate as a Cer file, in order to obtain the Base-64 encoded public key (this is used by your IdP to sign the tokens that it issues). To do this…
Your certificates public key is used in the FederationMetadata.xml file of the Identity Provider that we will build. This is so that Relying Party applications that are secured using our Identity Provider (in this case Azure ACS) can verify that tokens are signed via a trusted authority. We obtain the Base-64 encoded public key (as a Cer file) for this.
So we can easily develop and test our IdP, add the following entry to your host file (changing to reflect the url you intend to use on your local machine for your IdP and RP). Your host file should exist at C:\Windows\System32\Drivers\etc\hosts. Note, if you plan to host production sites publically, you must instead ensure that the DNS for these is correctly set up.
Next we need to create a website to host our IdP. In IIS Manager, right click on the Sites node, and select “Add Web Site”, with the following settings (replacing the URLs as appropriate).
Whilst still in IIS Manager, navigate to the app pool (just created) and select “Advanced Settings”. Ensure that the .NET Framework version is set to 4.0 and Load User Profile is set to true.
Also, change the Identity in the Process Model section to LocalSystem. This is so that the application pool can access the private key of our certificate generated in step one. On a production environment, you would have a specific named account for this.
Navigate back to the newly created website in IIS Manager and click the “Bindings” link. Add a binding as follows (using your newly created certificate).
Now to finally create the IdP. In Visual Studio 2010, create a new website using the WIF Visual Studio Template “ASP.NET Secure Token Service Website”.
Optional: Once the solution template has loaded, you can directly launch the site to check that everything so-far has gone to plan. You should see the following, without any certificate errors.
We now need to make a few code changes to get our IdP ready for use by Azure ACS. The WIF Visual Studio Template “ASP.NET Secure Token Service Website” actually provides the majority of the functionality required for this example (albeit rather contrived).
In the AppCode folder, open the CustomSecurityTokenService.cs file and edit the GetOutputClaimsIdentity method. We will simply add an additional custom claim here as follows (to demonstrate how to pass additional information via Azure):
outputIdentity.Claims.Add(new Claim("http://sts.mcsuk.dev/claims/age", "33"));
IMPORTANT: Also in the CustomSecurityTokenService.cs file, change the setting of scope.ReplyToAddress = scope.AppliesToAddress; in the GetScope method. If this is not changed, the incorrect URL will be used when the browser is bounced from our custom Identity Provider to Windows Azure.
scope.ReplyToAddress = request.ReplyTo;
On my dev environment, because I’m a using a self-signed certificate, I need to make a couple of changes to make the STS look in the Root Trust store. Firstly, in the CustomSecurityTokenService.cs file I changed the EncryptingCredentials to use StoreName.Root (in the GetScope method).
scope.EncryptingCredentials = new X509EncryptingCredentials( CertificateUtil.GetCertificate( StoreName.Root, StoreLocation.LocalMachine, encryptingCertificateName ) );
In the CustomSecurityTokenServiceConfiguration.cs file, I also changed the constructor to also use StoreName.Root
: base( WebConfigurationManager.AppSettings[Common.IssuerName],
new X509SigningCredentials( CertificateUtil.GetCertificate(
WebConfigurationManager.AppSettings[Common.SigningCertificateName] ) ) )
this.SecurityTokenService = typeof( CustomSecurityTokenService );
We now need to make changes to the FederationMetadata\2007-06\FederationMetadata.xml file. Format the code (to do this, I select all the xml, copy it, cut and repaste. Visual Studio should format accordingly).
<auth:ClaimType Uri="http://sts.mcsuk.dev/claims/age" Optional="true" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
<auth:Description>The age of the subject.</auth:Description>
Update the appSettings in the web.config. Note that the IssuerName must match the EnitityId in the FederationMetadata.xml file.
<add key="IssuerName" value="https://sts.mcsuk.dev/"/>
<add key="SigningCertificateName" value="CN=*.mcsuk.dev"/>
<add key="EncryptingCertificateName" value=""/>
Build the solution.
To configure Azure to use our STS, you must create a namespace and enable ACS.
Once created, click into your ACS namespace.
Select Identity Providers and then click “add”
Add a WS-Federation identity provider and click next
Fill in the Identity Provider settings. Note that as your web application (STS) is not visible to Azure, you need to upload your FederationMetadata.xml file from your website as a file from your local machine.
Click save. Your IdP is now registered with Azure.
Now we need to register our Relying Party (i.e. our test app against ACS). For this, we just need the local url of where the app will run (i.e. http://rp.mcsuk.dev)
Click the relying party applications link. Fill in the following
This defines the claims that could be passed to the client (depending on which identity provider is selected).
Depending on what IdPs you have used, you should see the following
Finally, click on the application integration tab and get the WS-Federation Metadata url. You will need this to create a Relying Party.
To test our IdP, we need to create a new website in IIS as follows (replacing the site url as appropriate).
Navigate to the app pool (just created) and select “Advanced Settings”. Ensure that the .NET Framework version is set to 4.0 and Load User Profile is set to true.
In Visual Studio, create a new Claims Aware ASP.NET Web Site at the website just created in IIS.
Once create, in the solution explorer right click on the website and select “Add STS Reference” Walk through the subsequent dialog as follows…
Click next, you will get a warning “ID1007: The application is not hosted on a secure https connection.” As this is not production code, click yes to proceed.
On the next screen, specify to use and existing STS, and paste the FederationMetadata.xml url obtained from ACS.
As we are creating a demo, it is safe to disable certificate chain validation. Click next.
We will also not encrypt tokens. On a production environment, you should do this, as well as running the site over https.
Click ok on the confirm screen – note that it does not show all the claims potentially passed through from Identity Providers
Confirm the final screen and click finish
Phew – a lot of steps. The final stage is to test. Launch the relying party website. You should be taken to Azure ACS presenting a list of identity providers.
Select our identity provider (MCSUKTestIDP). Click submit to login.
If it all works, you should get the following. Note the identity provider claim issues by ACS refers to https://sts.mcsuk.dev. Also note that our additional claim (age) is shown.
Phew, that was a lot of steps. I hope it was useful!
Written by Rob Nowik
Note I have tested running the above on Azure. I obtained fully signed certificates in order to do this. Unfortunately, you cannot use the above Visual Studio templates directly when creating a Windows Azure Cloud Service project, but you can copy the code into an ASP.NET Web Role Azure Cloud Service. Note that you must ensure that your certificates are published to Azure.