如何在WCF和WIF中使用JWT令牌? [英] How to use JWT tokens with WCF and WIF?
问题描述
我们正在使用 IdentityServer3 ,到目前为止,对此我们感到非常满意.
在MS和Thinktecture OWIN中间件的帮助下,我们已经非常轻松地保护MVC和ASP.NET Web API应用程序.
We're using IdentityServer3 and have been very happy with it so far.
We've gotten to secure MVC and ASP.NET Web API applications very easily with the help of both MS and Thinktecture OWIN middlewares.
我们正在工作的客户端仍然有很多SOAP WCF服务,这就是我们遇到的障碍.
The client we're working for still has a lot of SOAP WCF services, and this is where we're getting stuck.
我不会说谎,我对WCF经验还很远,我只在非常基本的情况下使用过它-了解basicHttpBinding,没有传输或消息安全性.
I'm not gonna lie, I'm far from being experienced with WCF, I've only used it for very basic scenarios - understand basicHttpBinding, no transport nor message security.
这是我要实现的目标:
- 客户端从IdentityServer获取JWT访问令牌
- 以某种方式令牌最终出现在SOAP消息头中
- WCF读取并验证令牌
- WCF根据某些标准检查索赔并执行授权
我无法执行第三步.
- 我正在将
ws2007FederationHttpBinding
和TransportWithMessageCredential
安全模式一起使用.该消息包含BearerKey
,令牌的类型为urn:ietf:params:oauth:token-type:jwt
- 该服务使用WIF身份管道,在其中添加了
System.IdentityModel.Tokens.Jwt
NuGet包中的JwtSecurityTokenHandler
- I'm using a
ws2007FederationHttpBinding
withTransportWithMessageCredential
security mode. The message contains aBearerKey
and the token is of typeurn:ietf:params:oauth:token-type:jwt
- The service uses the WIF identity pipeline, in which I added the
JwtSecurityTokenHandler
from theSystem.IdentityModel.Tokens.Jwt
NuGet package
- 由STS发出的JWT令牌包装在
BinarySecurityToken
XML元素中,而XML元素本身包装在GenericXmlSecurityElement
中
- 此令牌用作
ChannelFactory
的
CreateChannelWithIssuedToken
的参数
- The JWT token issued by the STS is wrapped in a
BinarySecurityToken
XML element, itself wrapped in aGenericXmlSecurityElement
- This token is used as a parameter of the
CreateChannelWithIssuedToken
of theChannelFactory
在SOAP标头中找到令牌,并将其传递给JwtSecurityTokenHandler
.
但是随后引发异常:
The token is found in the SOAP header and passed on to the JwtSecurityTokenHandler
.
But then an exception is thrown:
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 ---
JustDecompiling之后,进一步读取SOAP标头中的XML元素时似乎出现了错误.奇怪的是令牌是最后一个元素.这是整个消息的样子:
After JustDecompiling, it looks like there's an error when further reading the XML elements in the SOAP header. What's strange is that the token is the last element. Here's what the whole message looks like:
<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>
结束元素时必须引发异常.
Doesn't look like there's something malformed or anything. From the stack trace, the exception must be thrown when reading the </o:Security>
end element since the token was properly read and handled.
我分叉了示例存储库,以便您随意查看. 以下是相关的项目:
I forked the samples repo so you can have a look if you feel like it. Here are the relevant projets:
-
SelfHost (Minimal)
.这是STS - 在
Clients
解决方案中,WCF服务位于APIs
文件夹中 - 在
Clients
解决方案中,WCF客户端是Console Client Credentials With Wcf
项目
sources
文件夹中的SelfHost (Minimal)
in thesources
folder. This is the STS- In the
Clients
solution, the WCF service is in theAPIs
folder - In the
Clients
solution, the WCF client is theConsole Client Credentials With Wcf
project
启动它的最佳方法是先启动STS,然后在WCF服务上启动Right click -> Debug -> Start new instance
,然后在WCF客户端上启动.
Best way to fire it up is to start the STS first, then Right click -> Debug -> Start new instance
on the WCF service, then the same on the WCF client.
提前谢谢!
推荐答案
我没有解决此问题,但是IdentityServer的开发人员之一Dominick Baier找到了解决方法.
他认为该异常来自WCF中的错误或WCF与JwtSecurityTokenHandler
之间的不兼容.由于他认为WCF已经完成,因此他不希望有人对此进行检查.
I didn't get to solve this problem but Dominick Baier, one of the developers of IdentityServer, found a workaround.
He thinks the exception comes from a bug in WCF or an incompatibility between WCF and the JwtSecurityTokenHandler
. Since he considers WCF done, he doesn't expect someone to take a look at it.
他的解决方案是将JWT令牌包装在SAML令牌中.然后,通过对SamlSecurityTokenHandler
进行子类化,将其取回并针对JwtSecurityTokenHandler
的实例进行验证.
His solution is to wrap the JWT token in a SAML token. Then, by subclassing SamlSecurityTokenHandler
, get it back and validate it against an instance of JwtSecurityTokenHandler
.
以下是链接:
- Dominick's blog post
- Samples repo on GitHub where he put the code
- Specific commit on GitHub
每个人都玩得开心,现在:-)
Everybody have fun, now :-)
这篇关于如何在WCF和WIF中使用JWT令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!