If you plan to use the Azure AppFabric Access Control Service (ACS) you might bump into some challenges to get everything working correctly. Let me give you an overview of issues that might arise and how you can quickly solve them.
Setting up your environment
ACS is based on Windows Identity Foundation and this doesn’t come by default with the .NET Framework. If you want to use ACS you’ll need to install the WIF runtime (and you might also want to install the SDK):
- Runtime: http://www.microsoft.com/download/en/details.aspx?id=17331
- SDK: http://www.microsoft.com/download/en/details.aspx?id=4451
A potentially dangerous Request.Form value was detected from the client (wresult=”<t:RequestSecurityTo…”).
You’ll get this error after a successful login when the identity provider redirects the user to your action. The reason is the following: when redirecting the user to the application the identity provider also passes some extra data containing the information regarding the user.
Take a look at what Fiddler is picking up, there’s a bunch of XML in the wresult key. ASP.NET sees this as a potentially dangerous value and will throw an exception.
Now to solve this you have a few options. First you could choose to turn off validation:
But that’s not such a good solution since this could make your application vulnerable to cross-site scripting attacks. A better way to solve this issue would be to write a custom WIF RequestValidator. The goal of a RequestValidator is to let you override the default ASP.NET validation if you think the request is not unsafe. In our case, if the request contains a sign in response we want the request to be valid and we’ll skip the default validation.
Note that you’ll need a reference to the WIF assembly: Microsoft.IdentityModel.dll
To use this RequestValidator you’ll also need to modify your web.config:
Now you’ll be able to login through your identity provider and be redirected to your application without any error. And maybe even more important, without making your application vulnerable to XSS attacks.
More information on TechNet.
Allowing anonymous users on some parts of your application
When you add an STS reference in Visual Studio and start the application you’ll notice that you are immediately required to logon. This might be acceptable for some applications but sometimes you’ll want to implement a homepage where a user could register, see more information, …
Remove the following lines from the web.config:
Removing the authorization element will cause the application to be freely accessibly by everyone. Then for each action you want to secure, you should add the Authorize attribute to it.
Updating your realm
Once you start using ACS in real projects you’ll notice a small annoyance: the audience Uris and the realm. When you add an STS reference in Visual Studio you’ll notice that the web.config gets filled up with all kinds of elements:
Now it’s great that we don’t have to fill up the web.config manually but on the other hand this will cause some problems once we start deploying. The relying parties in ACS have a specific return URL set that the user will be redirected to after a successful login. If we do our local, staging and production tests with the same realm we’ll always be redirected to the same page (this might be the production page for example).
You could start playing with forwarding, your hosts file, … but a better way to do this is by updating the realm based on the current url of the application. So if the application runs on http://localhost:90 the realm will also be set to this Uri. And if you create a relying party with this realm in ACS you could set it to forward to http://localhost:90/Customer/Detail for example.
Time for some code:
This code is pretty straightforward: each time the WSFederationAuthenticationModule is ready to redirect to the identity provider (ACS) we intercept this call to update the realm of the sign in request. You’ll see other examples where the Reply is updated instead of the Realm. I prefere not doing this to be able to configure the Reply Uri in ACS.
To make this work just add the function with that exact name in your global.asax file. At runtime you might also experience the following error:
The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.
To solve this issue you could change the mode to Never or add each Uri to the list of audienceUris (both in the web.config). Here is an example of the latter:
Server Error in ‘/’ Application.
When you deploy your application to Azure you might see the following yellow screen of death:
This might be a pain to debug, unless you use the Remote Desktop module. If you get this error and you connect to an instance using Remote Desktop you’ll see the following error in the Event Viewer:
Exception message: Could not load file or assembly ‘Microsoft.IdentityModel, Version=188.8.131.52, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ or one of its dependencies. The system cannot find the file specified. (E:\sitesroot\0\web.config line 33)
To solve this error, set Copy Local to true for the assembly: Microsoft.IdentityModel:
Server Error in ‘/’ Application when using multiple instances in Windows Azure
The same error we saw previously could also happen “sometimes” when you use more than 1 instance in Windows Azure, and this is caused because WIF uses DPAPI for encryption and decryption. This is the error you might see in Event Viewer:
[CryptographicException: Key not valid for use in specified state.]
System.Security.Cryptography.ProtectedData.Unprotect(Byte encryptedData, Byte optionalEntropy, DataProtectionScope scope) +450
Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte encoded) +150
To solve this issue we need to take a few steps. First you should start by creating a new certificate and adding it to the hosted service:
Write down the thumbprint and add it to the certificates of your service definition. If you don’t add it to the service definition you might bump into the following error on the server:
ID1039: The certificate’s private key could not be accessed. Ensure the access control list (ACL) on the certificate’s private key grants access to the application pool user.
Now in the web.config you should add the following block in the microsoft.identityModel element:
To use this service certificate you’ll need to overwrite the FederatedAuthentication‘s default behavior in the global.asax file:
And that’s all I have to say about this. Hopefully you’ll manage to get everything running with all this information. Shouldn’t this be enough you can always take a look at the following resources: