9

一般注意事项

我们正在使用IdentityServer3并且到目前为止对它非常满意。
在 MS 和 Thinktecture OWIN 中间件的帮助下,我们可以非常轻松地保护 MVC 和 ASP.NET Web API 应用程序。

我们为之工作的客户端仍然有很多 SOAP WCF 服务,而这正是我们遇到的问题。

设置

我不会撒谎,我对 WCF 的经验还很遥远,我只将它用于非常基本的场景 - 了解 basicHttpBinding,没有传输或消息安全性。

这就是我想要实现的目标:

  • 客户端从 IdentityServer 获取 JWT 访问令牌
  • 不知何故,令牌最终出现在 SOAP 消息头中
  • WCF 读取并验证令牌
  • WCF 检查声明并根据某些标准执行授权

我无法让第三步工作。

服务器设置

  • 我正在使用ws2007FederationHttpBinding安全TransportWithMessageCredential模式。消息包含 aBearerKey并且令牌的类型为urn:ietf:params:oauth:token-type:jwt
  • 该服务使用 WIF 身份管道,我在其中添加了JwtSecurityTokenHandler来自System.IdentityModel.Tokens.JwtNuGet 包的

客户端设置

  • STS 发出的 JWT 令牌被包装在一个BinarySecurityTokenXML 元素中,该元素本身被包装在一个GenericXmlSecurityElement
  • 此标记用作的CreateChannelWithIssuedToken参数ChannelFactory

怎么了

该令牌在 SOAP 标头中找到并传递给JwtSecurityTokenHandler.
但随后抛出异常:

System.ServiceModel.Security.MessageSecurityException: Message security verification failed. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Xml.XmlBufferReader.GetChars(Int32 offset, Int32 length, Char[] chars)
   at System.Xml.XmlBufferReader.GetString(Int32 offset, Int32 length)
   at System.Xml.StringHandle.GetString()
   at System.Xml.XmlBaseReader.ReadEndElement()
   at System.ServiceModel.Security.ReceiveSecurityHeader.ExecuteFullPass(XmlDictionaryReader reader)
   at System.ServiceModel.Security.ReceiveSecurityHeader.Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
   at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessageCore(Message& message, TimeSpan timeout)
   at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout)
   --- End of inner exception stack trace ---

JustDecompile 之后,在进一步读取 SOAP 标头中的 XML 元素时,似乎出现了错误。奇怪的是令牌是最后一个元素。这是整个消息的样子:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://tempuri.org/IService/GetListOfStrings</a:Action>
        <a:MessageID>urn:uuid:5c22d4e2-f9b8-451a-b4ca-a844f41f7231</a:MessageID>
        <ActivityId CorrelationId="554fc496-7c47-4063-9539-d25606f186b0" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">1213dcd7-55b7-4153-8a6d-92e0922f76dd</ActivityId>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo90CpMlUwLBOmEPkZ5C8fRQAAAAAVWkkf2rJS0qImBv+Yx1recUXdbBLjThDkAMkwfW3/2AACQAA</VsDebuggerCausalityData>
        <a:To s:mustUnderstand="1">https://localhost.fiddler:44322/Service.svc</a:To>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2015-05-21T06:41:45.362Z</u:Created>
                <u:Expires>2015-05-21T06:46:45.362Z</u:Expires>
            </u:Timestamp>
            <wsse:BinarySecurityToken ValueType="urn:ietf:params:oauth:token-type:jwt" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><!-- Removed --></wsse:BinarySecurityToken>
        </o:Security>
    </s:Header>
    <s:Body>
        <GetListOfStrings xmlns="http://tempuri.org/" />
    </s:Body>
</s:Envelope>

看起来没有什么畸形或任何东西。从堆栈跟踪来看,在读取结束元素时必须抛出异常,</o:Security>因为令牌已正确读取和处理。

复制品

我分叉了示例存储库,因此如果您愿意,可以查看一下。以下是相关项目:

  • SelfHost (Minimal)sources文件夹中。这是 STS
  • Clients解决方案中,WCF 服务位于APIs文件夹中
  • Clients解决方案中,WCF 客户端是Console Client Credentials With Wcf项目

启动它的最佳方法是先启动 STS,然后Right click -> Debug -> Start new instance在 WCF 服务上,然后在 WCF 客户端上同样如此。

提前致谢!

4

1 回答 1

11

我没能解决这个问题,但 IdentityServer 的开发人员之一 Dominick Baier 找到了一种解决方法。
他认为异常来自 WCF 中的错误或 WCF 与JwtSecurityTokenHandler. 既然他认为 WCF done,他不希望有人来看看它。

他的解决方案是将 JWT 令牌包装在 SAML 令牌中。然后,通过子类SamlSecurityTokenHandler化,将其取回并针对JwtSecurityTokenHandler.

以下是链接:

现在大家玩得开心:-)

于 2015-07-02T15:31:27.727 回答