12

I'm trying to run WIF Relying Party application on a shared host. They will not set the IIS Setting LoadUserProfile to true and as such I'm getting the following error:

Message: The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating. ExceptionStackTrace: at System.Security.Cryptography.ProtectedData.Protect(Byte[] userData, Byte[] optionalEntropy, DataProtectionScope scope) at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Encode(Byte[] value)

Is there anyway around this?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Jonathon Kresner
  • 2,793
  • 5
  • 29
  • 40

2 Answers2

19

Yes, this is because you are using the default token encryption which relies on DPAPI. You can replace that with certficate based encryption. See here: http://msdn.microsoft.com/en-us/library/ff803371.aspx (scroll to "There is one further change to the application..." )

The code is:

void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
    var sessionTransforms =
        new List<CookieTransform>(
            new CookieTransform[] 
            {
                new DeflateCookieTransform(), 
                new RsaEncryptionCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate)  
            });
    var readOnlyTransforms = sessionTransforms.AsReadOnly();
    var sessionHandler = new SessionSecurityTokenHandler(readOnlyTransforms);

    e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}

and

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

Both on the global.asax.cs

BTW, this is also the "web farm friendly" way of configuring WIF, so it is machine (instance) independant. Windows Azure deployments are essentially web farms, so that's why you see it in that chapter.

Update: In newer versions the API has changed. The updated code would look like this

void OnFederationConfigurationCreated(object sender, FederationConfigurationCreatedEventArgs e)
{
    var sessionTransforms = new List<CookieTransform>(
        new CookieTransform[]
            {
                new DeflateCookieTransform(),
                new RsaEncryptionCookieTransform(e.FederationConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(e.FederationConfiguration.ServiceCertificate)
            });
    var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());

    e.FederationConfiguration
        .IdentityConfiguration
        .SecurityTokenHandlers
        .AddOrReplace(sessionHandler);
}

and

protected void Application_Start()
{
    FederatedAuthentication.FederationConfigurationCreated += OnFederationConfigurationCreated;
}
Simon
  • 33,714
  • 21
  • 133
  • 202
Eugenio Pace
  • 14,094
  • 1
  • 34
  • 43
  • I've created an MVC 4 Hello World app using Visual Studio 2010 following the Windows Azure Training Kit lab. This deployed to Azure using the Publish...Publish Web feature. I've then added an STS Reference to try and get it to authenticate via ACS and am hitting the error on this SO question. I've added your code and believe I also need to specify a serviceCertificate in web.config, but I'm stuck in figuring out how to deploy the certificate to the Azure web site. I can't find a link in the new Azure portal nor a setting in the VS project or Publish Profile. – robaker Feb 22 '13 at 12:19
  • 1
    Oh, hold on. I created an Azure Web Site, not a Cloud Service. If I create a Cloud Service (with nothing in it) I can see a Certificates tab in the management portal, so I guess I'm using the wrong Azure thing. Will try some other labs and then move the code over to right bit of Azure. – robaker Feb 22 '13 at 12:56
5

You could also use MachineKeySessionSecurityTokenHandler which is available in .net 4.5 in the namespace System.IdentityModel.Services.Tokens. You can enable this token handler by setting it in the configuration.

<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">        
      </add>
    </securityTokenHandlers>

  </identityConfiguration>
</system.identityModel>
Martijn B
  • 4,065
  • 2
  • 29
  • 41