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?
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;
}
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>