使用 WSSecurityTokenSerializer 在 .Net 中读取验证 SAML 断言时出现问题

Posted

技术标签:

【中文标题】使用 WSSecurityTokenSerializer 在 .Net 中读取验证 SAML 断言时出现问题【英文标题】:Problems reading authenticating a SAML assertion in .Net using WSSecurityTokenSerializer 【发布时间】:2011-08-31 19:14:44 【问题描述】:

我有一个 SAML 断言,我希望使用 WSSecurityTokenSerializer 在 .Net 中进行身份验证。

尽管有a few issues,但我有钥匙链和 SAML XML。

首先我从 HTTPS POST 获得 SAML 断言:

// spec says "SAMLResponse=" 
string rawSamlData = Request["SAMLResponse"];

// read the base64 encoded bytes
byte[] samlData = Convert.FromBase64String(rawSamlData);

// read back into a UTF string
string samlAssertion = Encoding.UTF8.GetString(samlData);

// get the SAML data in an XML reader
var assertionPostStream = new StringReader(samlAssertion);
var reader = XmlReader.Create(assertionPostStream);

然后我得到 IdP 提供的密钥:

// get the key data
byte[] certificateData = System.IO.File.ReadAllBytes("myKeys.p7b");

// decode the keys
var cms = new SignedCms(SubjectIdentifierType.IssuerAndSerialNumber);
cms.Decode(certificateData);

// we have a keychain of X509Certificate2s, we need a collection of tokens
var certificatesAsTokens =
    from X509Certificate2 cert in cms.Certificates
    select new X509SecurityToken(cert) as SecurityToken;

// get a token resolver
var tokens = new ReadOnlyCollection<SecurityToken>(
    certificatesAsTokens.ToList());
var resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(
    tokens, true);

最后我在这里抛出一个错误:

// use the WS Security stuff to parse the reader
var securityToken = WSSecurityTokenSerializer.
    DefaultInstance.ReadToken(reader, resolver) as SamlSecurityToken;

调用ReadToken 时出现以下错误:

无法从带有“urn:oasis:names:tc:SAML:2.0:protocol”命名空间的 BinarySecretSecurityToken 和“ValueType”的“Response”元素中读取令牌。如果此元素预计有效,请确保将安全性配置为使用指定名称、命名空间和值类型的令牌。

我的 SAML XML 开头为:

<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ...

很明显我在urn:oasis:names:tc:SAML:2.0:protocol 命名空间中有一个Response 元素。

知道这里出了什么问题/遗漏了什么吗?

【问题讨论】:

经过几天的挖掘(关于这些东西的文档很糟糕)我认为这可能是由于 WSSecurityTokenSerializer 依赖于 SAML 1.1 的变体而不是 SAML 2.0 - 我已经转而尝试直接验证签名:***.com/questions/6126388 【参考方案1】:

您似乎收到了 SAML2 响应。尽管 .NET 4.5 支持 SAML2,但遗憾的是只支持断言,而不支持协议本身(包括响应消息)。

要在 .NET 中处理 SAML2 响应,您必须:

    验证整个响应消息的签名。 提取消息的断言部分。 使用Saml2SecurityTokenHandler.ReadToken() 读取令牌。 使用Saml2SecurityTokenHandler.DetectReplayedToken() 验证令牌。 使用Saml2SecurityTokenHandler.ValidateConditions() 验证令牌 使用Saml2SecurityTokenHandler.CreateClaims() 创建声明身份。

不幸的是,这些方法中的大多数都受到保护,但您可以将Saml2SecurityTokenHandler 子类化并访问它们。

可以在Sustainsys.Saml2 项目的Saml2Response 类中找到完整的工作示例。

【讨论】:

如果您设置配置文件并使用FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers,令牌处理程序会调用这些方法。见***.com/questions/28845076/… 实际上,当签名位于顶层而不是断言时,我发现我错了:***.com/questions/28883166/… 上面的 Saml2Response 类链接给出了 404。你有新路径吗? @BigJoe714 感谢您注意到断开的链接,现在已修复。然后 Saml2Response 类在写这篇文章后被移到了另一个命名空间。 Saml2Response 链接已损坏。你能更新链接吗?应该是这个github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2/SAML2P/…?

以上是关于使用 WSSecurityTokenSerializer 在 .Net 中读取验证 SAML 断言时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)