SessionSecurityTokenHandler trying to decrypt SessionSecurityToken in RSA-encrypted cookie using DPAPI; why?

10,216

Solution 1

Well, after much searching, I've figured out what my problem was. Before I set up the ServiceConfigurationCreated, I was doing some configuration that caused an access to FederatedAuthentication.ServiceConfiguration. According to MSDN, "The ServiceConfigurationCreated event is raised when the first HTTP module in the web application references ServiceConfiguration". I moved the event handler setup to the top of Application_Start and everything worked as it should, which means that the event - which only fires once - was firing before I had the event handler set up.

Hopefully this will save someone the 4+ hours it took me to run this to ground.

Solution 2

Note that you can now use the MachineKeySessionSecurityTokenHandler to sign and encrypt session tokens across web farms.

To use this, you will need to remove the default SessionSecurityTokenHandler and add the MachineKeySessionSecurityTokenHandler in Web.config:

<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

The MachineKeySessionSecurityTokenHandler makes use of the machine key configured in Web.config so you will need to add that too:

<system.web>
  <machineKey validationKey="..." decryptionKey="..." validation="SHA1" decryption="AES" />
</system.web>

See this question on BrainThud

Share:
10,216
Evan Nagle
Author by

Evan Nagle

I work with Olo solving problems for people who want to order food online. I'm also a Stack Overflow alumnus and Microsoft alumnus. I love Jesus, my family, programming, Texas, and craft beer. Find me on twitter and GitHub as @aggieben.

Updated on June 27, 2022

Comments

  • Evan Nagle
    Evan Nagle almost 2 years

    I have read in MSDN forums, Dominic Baier's blog, and in other sources that DPAPI will not work out-of-the box in Azure, and that one approach to handling federated authentication in any kind of web farm scenario is to replace the DPAPI transforms with one that uses a private key available across the farm, such as RSA encryption using an X509 certificate. I have taken this approach in my Azure MVC application and configured the SessionSecurityTokenHandler like this:

    FederatedAuthentication.ServiceConfigurationCreated += (sender, args) =>
        {
            var sessionTransforms = new List<CookieTransform>(new CookieTransform[]
                {
                    new DeflateCookieTransform(),
                    new RsaEncryptionCookieTransform(args.ServiceConfiguration.ServiceCertificate),
                    new RsaSignatureCookieTransform(args.ServiceConfiguration.ServiceCertificate)
                });
            var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
            args.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);                    
        };
    

    Using this configuration, we are able to receive tokens from an identity provider and issue secure cookies encrypted using these transforms. Running in the Azure emulator, everything works as expected. However, in the Azure environment, we intermittently see the following error in the browser:

    Key not valid for use in specified state.
    
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
    
    Exception Details: System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.
    
    
    Source Error: 
    
    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
    
    Stack Trace: 
    
    
    [CryptographicException: Key not valid for use in specified state.
    ]
       System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +577
       Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +80
    
    [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. ]
       Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +433
       Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +189
       Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +862
       Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +109
       Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +356
       Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +123
       Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +61
       System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +270
    

    This seems to suggest that the SessionSecurityTokenHandler is trying to decrypt the cookie using DPAPI, but why? Didn't I configure it to use RSA above?

  • astaykov
    astaykov over 11 years
    Wow! Good catch! you have my up on that!
  • Maxim Kapitonov
    Maxim Kapitonov about 11 years
    Nice!!! But why you didn't it through config file? blogs.msdn.com/b/distributedservices/archive/2012/10/29/…
  • Evan Nagle
    Evan Nagle almost 11 years
    @antwoord that would be the more logical way to set it up. I think the reason it was done in the Application_Start handler was because the person who did it didn't realize it could be done in the web.config, and it just wasn't an issue I wanted to change (although it might have taken less time after all).
  • Evan Nagle
    Evan Nagle almost 11 years
    Good tip. I'm not sure this really buys anything over the RSA approach, but I'm glad to know that it's available.
  • Chris Fong
    Chris Fong over 8 years
    My machine key was already configured so this is a solid solution.