Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protection API Exceptions when scaling Azure Web Roles using ACS

I have been using Azure ACS against Windows Live and Google and its been running without any problems. Last night we scaled instances from 1 running instance to 3 and since then people have reported issues when accessing our site. We've traced this to the following exception which is occuring on a fairly regular basis.

We assume we have a problem somewhere in our configuration but aren't sure what we're missing. We set the machine key...

<machineKey decryption="AES" decryptionKey="F7_SOMETHING_SOMETHING_FA" validation="SHA1" validationKey="63_SOMETHING_SOMETHING_BF" />

Can anyone shed some light on this problem?

System.InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false.  ---> System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.

   at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
   at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)
   at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
   at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
   at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver)
   at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
   at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
   at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Note: For context. this is running in a Windows Azure Web Role and is MVC 4.

like image 347
JoeGeeky Avatar asked Dec 19 '12 12:12

JoeGeeky


3 Answers

Now that you've scaled out and since your application is hosted behind a load balancer, then it is possible that your user navigated to Server A, got the session cookie protected by DPAPI on Server A, but as they continue to browse around the site the load balancer redirects the request to execute on Server B. When this happens, Server B does not have a matching machine key, so it is unable to decrypt the session cookie and throws the above error. Here are three ways in which you can resolve this issue.

Windows Identity Foundation (WIF) is an out-of-band runtime that must be installed on the computer so that your claims-aware application can use it. WIF is not installed by default on Windows Azure instances. To run your cloud claims-aware application, you must make WIF runtime available on the Windows Azure instance. The easiest way is to do this is to include the WIF assembly with the deployment package.

To include the WIF assembly with the Windows Azure deployment package

  1. In the Solution Explorer, locate your claims-aware application.
  2. Expand the References folder.
  3. Locate the Microsoft.IdentityModel assembly under the References folder.
  4. Right-click the assembly, and then click Properties.
  5. In the properties window, specify Copy Local as True and Specific Version as False.

By default, WIF protects cookies cryptographically using data protection application programming interfaces (DPAPI). DPAPI is not available on Windows Azure. To make sure that your cloud claims-aware web application functions correctly when it is deployed to Windows Azure, you must add cookies encryption functionality using RSA.

To encrypt cookies using RSA

  1. In the Solution Explorer, locate your cloud claims-aware web application.
  2. Open the global.asax.cs file, which is the code behind the global.asax file, in the Visual Studio editor.

Add the following declarations:

using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Web;
using Microsoft.IdentityModel.Web.Configuration;

Add the following code:

void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
    //
    // Use the <serviceCertificate> to protect the cookies that are
    // sent to the client.
    //
    List<CookieTransform> sessionTransforms =
        new List<CookieTransform>(new CookieTransform[] {
        new DeflateCookieTransform(), 
        new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
        new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate)  });
    SessionSecurityTokenHandler sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
    e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}

void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;

More information can be found here: http://msdn.microsoft.com/en-us/library/hh289318.aspx

like image 91
Brian Knight Avatar answered Nov 05 '22 07:11

Brian Knight


This is common exception when using WIF in farm environment. The point is that the default behavior is to use DPAPI to encrypt the cookie. However DPAPI is MachineKey bound.

You have to make a small change in the Global.Asax and use RSA Crypto service provider to encrypt/decrypt the FedAuth Cookie. Take a look at this article on how to achieve that.

like image 27
astaykov Avatar answered Nov 05 '22 06:11

astaykov


I ran into a similar issue while trying to utilize ACS with an MVC 4 app deployed as a Windows Azure Website instance vs. a cloud service. The following helped me to resolve the problem. http://msdn.microsoft.com/en-us/library/hh568644.aspx

Scroll to the very bottom and find the example which shows removing the SessionSecurityTokenHandler and replacing it with the MachineKeySessionSecurityTokenHandler .

like image 42
Kevin Rivers Avatar answered Nov 05 '22 06:11

Kevin Rivers