【发布时间】:2016-01-19 02:55:49
【问题描述】:
在我的 MVC 站点上,如果我检测到正在使用 ADFS 帐户,我会重定向到 ADFS 登录页面。用户输入其 ADFS 凭据后,ADFS 站点会将WsFederationMessage 发回我的站点。如何验证作为 WsFederationMessage 的一部分呈现给我的网站的 ADFS 令牌?
在AuthenticationHandler 中间件类中,我有以下调用ValidateToken 方法的相关代码:
IFormCollection form = await Request.ReadFormAsync();
WsFederationMessage wsFederationMessage = new WsFederationMessage(form);
if (!wsFederationMessage.IsSignInMessage)
{
Request.Body.Seek(0, SeekOrigin.Begin);
return null;
}
var token = wsFederationMessage.GetToken();
if (wsFederationMessage.Wresult != null && Options.SecurityTokenHandlers.CanReadToken(token))
{
SecurityToken validatedToken;
ClaimsPrincipal principal = Options.SecurityTokenHandlers.ValidateToken(token, Options.TokenValidationParameters, out validatedToken);
...
}
当我尝试调用 ValidateToken 时出现此错误:
描述:执行过程中发生了未处理的异常 当前的网络请求。请查看堆栈跟踪以获取更多信息 有关错误的信息以及它在代码中的来源。
异常详情: System.IdentityModel.SignatureVerificationFailedException:ID4037: 验证签名所需的密钥无法从 以下安全密钥标识符 'SecurityKeyIdentifier (
IsReadOnly = False,计数 = 1,子句 [0] = X509RawDataKeyIdentifierClause(RawData = [作者删除]。确保 SecurityTokenResolver 填充了所需的密钥。
搜索分辨率时,我找到了this article,因此我使用this site's OpenSSL-based decoder 解码了上面代码中token 字符串对象中出现的X509Certificate,因为它是在<X509Certificate></X509Certificate> XAML 中进行PEM 编码的返回的token 字符串的标记。事实上,它是签名证书,正如决议文章所说的那样。所以我继续使用我的 ADFS 服务器,将签名证书导出为公共证书并将其安装在我网站的 Trusted Root Certificate Authorities 上。该链接还提到我必须:
将证书导入 RP 信任的签名选项卡
因此,我将签名证书添加到我的 ADFS 服务器上我的依赖方信任的签名选项卡中,其中我的机器标识符有一个信任规则。经过这一切,它仍然没有工作。虽然有一点背景知识,但我的网站在我的机器上通过 IIS 本地运行,并且我更改了主机文件设置以使其指向 https://adfs-example.local/。我的 ADFS 服务器目前是连接到我的站点的 VPN,所以我的意思是 ADFS 服务器本身永远不会正确解析 https://adfs-example.local/ 的标识符,如果它需要直接从这个 URI 请求某些东西,但事情仍然很明显一旦浏览器重定向到我的网站的登录页面并显示 ADFS 令牌,它就会工作。
再把我的上帝遗弃的头撞在墙上,我尝试添加自己的IssuerSigningKeyResolver:
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (token, securityToken, keyIdentifier, validationParameters) =>
{
var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Find(X509FindType.FindByThumbprint, "<My Certificate's Thumbprint>", true)[0];
store.Close();
var provider = (RSACryptoServiceProvider)cert.PublicKey.Key;
return new RsaSecurityKey(provider);
}
};
现在我有一个错误的美丽,不知道如何处理它:
IDX10213:必须对 SecurityTokens 进行签名。安全令牌:“{0}”。
描述:执行过程中发生了未处理的异常 当前的网络请求。请查看堆栈跟踪以获取更多信息 有关错误的信息以及它在代码中的来源。
异常详情: System.IdentityModel.Tokens.SecurityTokenValidationException: IDX10213:必须对 SecurityTokens 进行签名。安全令牌:“{0}”。
来源错误:
第 61 行:第 62 行:var validToken = (安全令牌)空;第 63 行:var principal = Options.SecurityTokenHandlers.ValidateToken(令牌, Options.TokenValidationParameters, outvalidatedToken);第 64 行:
var claimIdentity = principal.Identity 作为 ClaimsIdentity;第 65 行:
var ticket = new AuthenticationTicket(claimsIdentity, null);
处理程序被调用两次。在第一次通话中,这似乎成功了。似乎第一个令牌已签名。在第二次调用时,它失败了。似乎第二个令牌未签名。为什么我的一些安全令牌没有签名?我该如何进一步调试呢?任何人都必须处理这样的事情吗?
现在我别无选择,只能检查源代码,所以我拉出了AzureAD(也称为Wilson)的整个主干,我正在检查代码。它在 SAML 安全令牌处理程序的这一行失败:
if (samlToken.Assertion.SigningToken == null && validationParameters.RequireSignedTokens)
{
throw new SecurityTokenValidationException(ErrorMessages.IDX10213);
}
我不明白。这意味着签名令牌为空。为什么签名令牌为空?
编辑:再次检查 ADFS 服务器,我认为设置它的人忘记将私钥作为“令牌签名”和“令牌解密”证书的一部分包含在ADFS 管理单元的 AD FS -> 服务 -> 证书选项卡。但奇怪的是,通过与设置它的人交谈,显然它需要服务证书并吐出另外两个用于令牌签名和解密......虽然没有他们的私钥?
编辑:根据this article,这两个“令牌签名”和“令牌解密”证书应该是有效的,因为它们是自动生成的,只是存储了它们的私钥在活动目录中:
当您使用自签名证书进行令牌签名和 解密时,私钥存储在 Active Directory 中 以下容器:
CN=ADFS,CN=Microsoft,CN=Program Data,DC=domain,DC=com
因此,为 ADFS 安装安装私钥 进入此位置,您必须是域管理员才能安装 ADFS 或拥有 分配给此容器的适当权限。
【问题讨论】:
标签: c# asp.net asp.net-mvc ssl adfs