Wednesday, March 18, 2015

System.InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details).

Last week I spend a lot of time searching for a specific WIF issue we encountered.

The Facts

Let’s first describe the situation before I come to the error itself. We have a root ASP.NET MVC Website e.g. portal.sample.be/ and a list of subsites portal.sample.be/subsite1, portal.sample.be/subbsite2,…  Users always have to login through the root site before they can use any of the subsites. Login is handled through WIF and a range of STS instances(depending on the  authentication type). Once logged in on the root site, users have Single-Sign-On and can connect to any of the subsites without authenticating again.

The Issue

Last week we upgraded the root site to ASP.NET MVC 5, .NET 4.5 and the build-in System.IdentityModel and System.IdentityModel.Services. The sub sites are still using .NET 4.0, System.IdentityModel and Microsoft.IdentityModel. Authentication on the root site works as expected, but when we try to connect to any of the subsites, SSO fails and WIF returns the following exception:

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: The data is invalid.

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

If you search for this fault on the Internet, you find a small range of possible reasons and solutions:

  • The LoadUserProfile setting in IIS is set to false. This should be true to make DPAPI work.
  • Switch to MachineKey protection in WIF for .NET 4.5.
  • You are using an old cookie. Clear the browser cache.

We tried them all but none of them brought a solution. After a long quest, we finally figured it out:

The internal format of the cookie has changed between WIF version for .NET 4.0 and .NET 4.5. So we can no longer share the cookie between sites as we are running multiple versions of .NET (and WIF). As a workaround, we switched back to the old WIF version on .NET 4.5. This solved the issue for now…

Remark: We are planning to implement a better solution in the long run by letting each site go back to the STS and use it’s own cookies.

No comments: