将JWT SecurityToken提供给WCF客户端

时间:2013-05-01 04:52:43

标签: wcf wif

我需要根据用户名/密码身份验证为客户端生成并发出令牌。我已经尝试了几种解决这个问题的方法,但所有这些方法都遇到了问题。

我的第一个计划是在我的WCF端点上实现WS-Trust Issue。我找到的例子使用了这个:

[OperationContract(Action = "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue",
                   ReplyAction = "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue")]
Message IssueToken(Message rstMessage);

但是,对4.5中的WIF进行更改以将其集成到.NET Framework中已经打破了其余的示例代码,以将Message转换为RequestSecurityToken。 WSTrustRequestSerializer似乎这样做,但它需要WSTrustSerializationContext,并且关于如何创建或配置此上下文对象的信息很少。

我尝试将我想要用于我的SecurityToken类型的JWT序列化为字符串并将其返回给客户端,但看起来将其反序列化为WCF可以使用的SecurityToken将需要我发送JWTSecurityToken和Handler在客户端,我想避免的事情。虽然WS-Trust绑定似乎以某种方式回避了这一点并产生了GenericXmlSecurityToken,但我似乎无法找到如何创建其中一个。

有关如何序列化/反序列化WS-Trust中的RequestSecurityToken和RequestSecurityTokenResponse对象,或者如何在WS-Trust框架之外序列化/反序列化令牌的任何想法?还是其他想法?

2 个答案:

答案 0 :(得分:4)

我做的是这样的: 我创建了自己的响应消息版本,其中包含创建GenericXmlSecurityToken所需的位。这通常是从WSTrustChannel返回的,所以它似乎是正确的做法。值得庆幸的是,包装JWT的GenericXmlSecurityToken的大多数参数都为null;我只需要在服务中的JWTSecurityTokenHandler上使用WriteToken序列化的序列化标记,以及validFrom和validTo值。

客户代码:

XmlElement element = document.CreateElement("wsse", "BinarySecurityToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
element.SetAttribute("ValueType", "urn:ietf:params:oauth:token-type:jwt");
element.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
UTF8Encoding encoding = new UTF8Encoding();
element.InnerText = Convert.ToBase64String(encoding.GetBytes(jwtToken));

GenericXmlSecurityToken token = new GenericXmlSecurityToken(
    element,
    null,
    validFrom,
    validTo,
    null,
    null,
    null);

var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.IssuedTokenType = "urn:ietf:params:oauth:token-type:jwt";

var factory2 = new ChannelFactory<IService1>(binding, new EndpointAddress("https://localhost:44300/Service1.svc"));
factory2.Credentials.SupportInteractive = false;
factory2.Credentials.UseIdentityConfiguration = true;

var proxy = factory2.CreateChannelWithIssuedToken(token);

var info = proxy.DoWork();

web.config的相关位:

绑定:

<ws2007FederationHttpBinding>
  <binding>
    <security mode="TransportWithMessageCredential">
      <message issuedKeyType="BearerKey" establishSecurityContext="false" issuedTokenType="urn:ietf:params:oauth:token-type:jwt"/>
    </security>
  </binding>
</ws2007FederationHttpBinding>

identityModel部分:

<system.identityModel>
  <identityConfiguration>
    <audienceUris>
      <add value="--audienceUri--"/>
    </audienceUris>
    <securityTokenHandlers>
      <add type="--namespace--.CustomJWTSecurityTokenHandler, --my dll--" />
      <securityTokenHandlerConfiguration>
        <certificateValidation certificateValidationMode="PeerTrust"/>
      </securityTokenHandlerConfiguration>
    </securityTokenHandlers>
    <issuerNameRegistry>
      <trustedIssuers>
        <add name="--issuer--"  thumbprint="--thumbprint--"/>
      </trustedIssuers>
    </issuerNameRegistry>
  </identityConfiguration>
</system.identityModel>

此问题中的CustomJWTSecurityTokenHandler(我的方案只需要validIssuer部分):How to configure MIcrosoft JWT with symmetric key?

我还没有看到其他地方使用的issuedTokenType属性,但我发现让代码工作至关重要。没有它,我收到了这个错误:“MessageSecurityException:找不到'Microsoft.IdentityModel.Tokens.JWT.JWTSecurityToken'令牌类型的令牌验证器。根据当前的安全设置,不能接受该类型的令牌。”

这可能是一种矫枉过正的解决方案,但我认为它最大限度地减少了自定义代码的数量,并将其集中在我感觉更舒服的地方。

感谢user2338856和leastprivilege让我在那里中途!

答案 1 :(得分:1)

AFAIK,你需要一个WSFederationBinding。开箱即用,这只支持Saml令牌。要让它支持Jwt令牌,您需要添加一个能够在WiF管道中处理它的securitytokenhandler。不幸的是,Microsoft的实验处理程序不是那种配置文件友好的,所以你需要将它子类化以允许你在config中指定属性。或者,您可以使用ThinkTecture Jwt处理程序,这在配置中也不是很容易设置。 设置所有这些将花费你一段时间,我不知道网上有任何这样的例子。