我的网络应用程序正在使用WIF根据自己的STS对用户进行身份验证(我无法控制他们的STS如何设置,我只是给他们联邦元数据的网址)。
我的Web应用程序正在运行2个负载均衡器,其后面有2个服务器,我也使用粘性会话,并且它们都有1小时超时,并且两台机器共享相同的机器密钥,我也在IIS中将LoadUserProfile设置为true。
当只有一个用户使用唯一的STS登录时似乎工作正常,但只要有一个以上,我就可以看到服务器在短时间内多次记录以下错误。
Key not valid for use in specified state.
Stack Trace: at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)\r\n at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)
如何解决此错误或诊断此问题的任何帮助?
答案 0 :(得分:1)
对于将来寻找同一问题的人,此处的信息解决了我的问题。 http://weblogs.asp.net/cibrax/the-system-cannot-find-the-file-specified-error-in-the-wif-fam-module(以下文章的副本)
作为WIF的一部分提供的联合身份验证模块(FAM)默认保护会话cookie在使用DPAPI的被动方案中被篡改。正如我在过去提到的,这种技术简化了整个解决方案的初始部署,因为没有额外的配置需要,自动生成的DPAPI密钥用于保护cookie,因此这可能是将其作为默认保护机制的理由在WSE,WCF和现在的WIF。
然而,从我的观点来看,这种技术有一些严重的缺点,使得它对真实的企业场景无用。
如果依赖于FAM进行身份验证的Web应用程序托管在IIS中。运行IIS进程的帐户需要创建一个配置文件才能使用DPAPI。解决方法是使用该帐户登录计算机以创建初始配置文件或运行一些脚本以自动执行此操作。
DPAPI不适用于Web场方案,因为计算机密钥用于保护Cookie。如果cookie受一个密钥保护,则必须将以下请求发送到同一台计算机。解决方法可能是使用粘性会话,因此来自同一台计算机的所有用户请求都由服务器场中的同一台计算机处理。
幸运的是,WIF已经提供了一些内置类来通过基于带有X509证书的RSA密钥的保护机制来替换这种默认机制。
“SecuritySessionHandler”是WIF中的处理程序,负责跟踪cookie中的身份验证会话。该处理程序默认接收一些内置类,这些类将转换应用于cookie内容,例如DeflatCookieTransform和ProtectedDataCookieTransform(用于使用DPAPI保护内容)。还有另外两个完全没有使用的CookieTransform派生类,并且非常便于启用企业场景,即RSAEncryptionCookieTransform和RSASignatureCookieTransform类。两个类都接收RSA密钥或X509证书,用于加密或签署cookie内容。
因此,您可以将以下代码放在global.asax文件中,以使用X509证书替换默认的cookie转换。
protected void Application_Start(object sender, EventArgs e)
{
FederatedAuthentication.ServiceConfigurationCreated += new EventHandler<Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs>(FederatedAuthentication_ServiceConfigurationCreated);
}
void FederatedAuthentication_ServiceConfigurationCreated(object sender, Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs e)
{
var cookieProtectionCertificate = CertificateUtil.GetCertificate(StoreName.My,
StoreLocation.LocalMachine, "CN=myTestCert");
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(
new SessionSecurityTokenHandler(new System.Collections.ObjectModel.ReadOnlyCollection<CookieTransform> (
new List<CookieTransform>
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform(cookieProtectionCertificate),
new RsaSignatureCookieTransform(cookieProtectionCertificate)
})
));
}
您需要更改的代码的唯一部分是它尝试在您的服务器上找到您的证书位置。
var cookieProtectionCertificate = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=myTestCert");