如何在服务端指定声明类型要求,以便客户端请求遵守它们?

发布于 2024-09-16 07:34:19 字数 2208 浏览 9 评论 0原文

我有:

  • 一个被动的 STS“登录应用程序”,它也是一个身份提供者。
  • 可以接受和处理 ActAs 令牌的活动 STS WCF 服务
  • 网站依赖方
  • 由网站调用的 WCF 服务依赖方。

所有这些都是使用 Windows Identity Foundation 和自定义 STS 代码组合在一起的。不涉及 Active Directory (ADFS)。

我现在的工作是:

  1. 用户尝试访问网站 RP。
  2. 用户被重定向到被动 STS。
  3. 用户登录,获得颁发的令牌,重定向回网站 RP。
  4. 网站 RP 对 WCF RP 进行服务调用并传递 ActAs 令牌,以便发生委派。
  5. 主动 STS 看到 ActAs 令牌进入并正确设置输出身份,因此主要身份是 ActAs 令牌,并且调用者的身份被添加到 Actor 链中。
  6. WCF RP 获得正确的令牌,一切都就位,当前线程主体具有正确的身份和声明。

我希望 WCF RP 向活动 STS 请求其他声明。

也就是说,在发送到活动 STS 的 RST 中,我希望它包含服务所需的声明列表,以便这些附加声明如果声明尚不存在,则可以获取它们。

我已经想出了如何通过修改网站 RP 客户端上的绑定来做到这一点,但我希望在 WCF RP 服务端指定要求。

我感觉这与我正在使用的绑定。我在使用 ActAs 令牌使用 ws2007FederationHttpBinding 时遇到了麻烦,并且 WIF 身份培训套件中的所有示例都使用了 customBinding,所以我也这样做了,并且最终成功了。以下是 WCF RP 中的配置片段,显示了我的绑定配置:

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="CustomBinding_FederatedService">
        <security
          authenticationMode="IssuedTokenForCertificate"
          messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
          <issuedTokenParameters tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
            <issuer address="http://localhost:38901/ActiveSts.svc/IWSTrust13" />
            <issuerMetadata address="http://localhost:38901/ActiveSts.svc/mex" />
          </issuedTokenParameters>
        </security>
        <textMessageEncoding>
          <readerQuotas maxArrayLength="32767" />
        </textMessageEncoding>
        <httpTransport />
      </binding>
    </customBinding>
  </bindings>
</system.serviceModel>

如果我更改调用网站上的配置以在 IssuedTokenParameters 部分中指示 ClaimTypeRequirements,则活动 STS 实际上会在 RST 中看到所需声明的列表...但是这是在调用网站上,这对我来说是有问题的。

我该如何做到这一点,以便 WCF RP 可以指定它需要的其他声明,而不必在调用网站上复制该配置?

如果这确实是一个绑定问题,那么如果您可以的话,这将会有所帮助给我展示上面给出的等效配置。我可以通过适当的更改来更新网站和 WCF 服务,但同样,我需要服务(或服务上的行为,或服务上的配置)来控制它所需的声明列表。该服务不应接受缺少必需声明的请求。

I have:

  • A passive STS "login application" that is also an identity provider.
  • An active STS WCF service that can accept and handle ActAs tokens
  • A web site relying party
  • A WCF service relying party that is called by the web site.

All of this is put together using Windows Identity Foundation and custom STS code. Active Directory (ADFS) is not involved.

What I have working now is:

  1. User attempts to visit web site RP.
  2. User gets redirected to passive STS.
  3. User logs in, gets a token issued, gets redirected back to the web site RP.
  4. Web site RP makes a service call to the WCF RP and passes an ActAs token so delegation happens.
  5. Active STS sees the ActAs token come in and properly sets up the output identity so the primary identity is the ActAs token and the caller's identity is added to the Actor chain.
  6. WCF RP gets the proper token with everything in place, current thread principal has the right identity and claims as should be.

I want the WCF RP to request additional claims from the active STS.

That is, in the RST that goes to the active STS, I want it to include the list of claims that the service requires so those additional claims can be fetched if they're not already present.

I have figued out how to do this by modifying the binding on the web site RP client but I want the requirements to be specified on the WCF RP service end.

I have a feeling it has something to do with the binding I'm using. I had trouble getting ws2007FederationHttpBinding working with ActAs tokens and all of the examples in the WIF Identity Training Kit used customBinding, so I did that, too, and it finally worked. Here is the config snippet from the WCF RP showing my binding configuration:

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="CustomBinding_FederatedService">
        <security
          authenticationMode="IssuedTokenForCertificate"
          messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
          <issuedTokenParameters tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
            <issuer address="http://localhost:38901/ActiveSts.svc/IWSTrust13" />
            <issuerMetadata address="http://localhost:38901/ActiveSts.svc/mex" />
          </issuedTokenParameters>
        </security>
        <textMessageEncoding>
          <readerQuotas maxArrayLength="32767" />
        </textMessageEncoding>
        <httpTransport />
      </binding>
    </customBinding>
  </bindings>
</system.serviceModel>

If I change the config on the calling web site to indicate claimTypeRequirements in the issuedTokenParameters section, the Active STS actually does see the list of required claims in the RST... but that's on the calling web site, which is problematic for me.

How do I make it so the WCF RP can specify additional claims it requires without having to duplicate that configuration on the calling web site?

If it is, indeed, a binding issue, it would help if you can show me the equivalent configuration given what I've got above. I can update the web site and the WCF service with the appropriate changes, but again, I need the service (or a behavior on the service, or configuration on the service) to control the list of claims it needs. The service should not accept requests that are missing required claims.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

彩扇题诗 2024-09-23 07:34:20

事实证明,您必须执行此操作的方法是...

  1. 找出一种在客户端检索索赔要求的方法。这可以是某种中央配置服务、WS-Policy/Metadata Exchange,或者任何您喜欢的服务。
  2. 手动创建 STS 的令牌请求。不要使用 Microsoft.IdentityModel CreateChannelActingAs(token) 扩展方法,而是使用 WSTrustChannelFactory 手动请求 ActAs 令牌(或新令牌)。
  3. 将手动请求的令牌添加到传出通道参数中。

请注意,这并不能完全消除您的客户了解索赔要求列表的需要,但它确实使您能够以某种方式集中该配置,甚至使用服务本身来提供该索赔要求列表。不幸的是,Microsoft.IdentityModel 堆栈中没有任何东西可以为您完成这一切。客户端绝对需要知道声明要求列表,因为对安全令牌的请求是作为客户端通信的一部分发出的,而不是在服务操作请求进来时由服务发出的。

无论如何,您可以看到 的一些不错的解释MSDN 网络上的 WSTrustChannelFactoryWSTrustChannel 网站。我的解决方案就是基于此。

归结起来,没有所有错误处理等,代码基本上如下所示:

// You need the channel factory so you can get info about the endpoint.
var factory = new ChannelFactory<IService>();

// Get the issuedTokenParameters information from the binding.
// You see this in the XML config but it's painful to access.
var tokenParameters = factory.Endpoint.Binding
    .CreateBindingElements()
    .OfType<SecurityBindingElement>().First()
    .EndpointSupportingTokenParameters
    .Endorsing.OfType<IssuedSecurityTokenParameters>().First();

// Prepare the RST.
var trustChannelFactory = new WSTrustChannelFactory(tokenParameters.IssuerBinding, tokenParameters.IssuerAddress);
var trustChannel = (WSTrustChannel)trustChannelFactory.CreateChannel();
var rst = new RequestSecurityToken(RequestTypes.Issue);
rst.AppliesTo = factory.Endpoint.Address;

// If you're doing delegation, set the ActAs value.
var principal = Thread.CurrentPrincipal as IClaimsPrincipal;
var bootstrapToken = principal.Identities[0].BootstrapToken;
rst.ActAs = new SecurityTokenElement(bootstrapToken);

// Here's where you can look up claims requirements dynamically.
rst.Claims.Add(new RequestClaim("http://dynamically-added-claim"));

// Get the token and attach it to the channel before making a request.
RequestSecurityTokenResponse rstr = null;
var issuedToken = trustChannel.Issue(rst, out rstr);
var fccParameters = new FederatedClientCredentialsParameters();
fccParameters.IssuedSecurityToken = issuedToken;
var channel = factory.CreateChannel();
((IChannel)channel).GetProperty<ChannelParameterCollection>().Add(fccParameters);

// NOW you can make the request.
channel.DoWork();

如果您希望优化系统周围的一些通信,这还允许您缓存已发布的令牌。

当然,如果您不尝试动态插入声明要求,或者您乐于使用 XML 配置并在服务器和客户端上复制它,则没有必要这样做。 CreateChannelActingAs(token) 扩展方法和整个 Microsoft.IdentityModel 堆栈会为您处理此问题。

It turns out the way you have to do this is to...

  1. Figure out a way to retrieve the claim requirements on the client side. This could be some sort of central configuration service, WS-Policy/Metadata Exchange, or whatever you like.
  2. Manually create the token request for the STS. Rather than use the Microsoft.IdentityModel CreateChannelActingAs(token) extension method, manually request an ActAs token (or a new token) using WSTrustChannelFactory.
  3. Add the manually requested token to the outgoing channel parameters.

Note that this doesn't exactly remove the need for your client to know about the list of claims requirements, but it does give you the ability to centralize that configuration somehow or even use the service itself to provide that list of claims requirements. There is, unfortunately, nothing in the Microsoft.IdentityModel stack that does all this for you. The client absolutely needs to know the list of claims requirements because the request for security token is issued as part of the client communication, not issued by the service as service operation requests come in.

Anyway, you can see some decent explanations of WSTrustChannelFactory and WSTrustChannel on the MSDN web site. My solution is based on that.

Boiled down without all the error handling, etc., the code basically looks like this:

// You need the channel factory so you can get info about the endpoint.
var factory = new ChannelFactory<IService>();

// Get the issuedTokenParameters information from the binding.
// You see this in the XML config but it's painful to access.
var tokenParameters = factory.Endpoint.Binding
    .CreateBindingElements()
    .OfType<SecurityBindingElement>().First()
    .EndpointSupportingTokenParameters
    .Endorsing.OfType<IssuedSecurityTokenParameters>().First();

// Prepare the RST.
var trustChannelFactory = new WSTrustChannelFactory(tokenParameters.IssuerBinding, tokenParameters.IssuerAddress);
var trustChannel = (WSTrustChannel)trustChannelFactory.CreateChannel();
var rst = new RequestSecurityToken(RequestTypes.Issue);
rst.AppliesTo = factory.Endpoint.Address;

// If you're doing delegation, set the ActAs value.
var principal = Thread.CurrentPrincipal as IClaimsPrincipal;
var bootstrapToken = principal.Identities[0].BootstrapToken;
rst.ActAs = new SecurityTokenElement(bootstrapToken);

// Here's where you can look up claims requirements dynamically.
rst.Claims.Add(new RequestClaim("http://dynamically-added-claim"));

// Get the token and attach it to the channel before making a request.
RequestSecurityTokenResponse rstr = null;
var issuedToken = trustChannel.Issue(rst, out rstr);
var fccParameters = new FederatedClientCredentialsParameters();
fccParameters.IssuedSecurityToken = issuedToken;
var channel = factory.CreateChannel();
((IChannel)channel).GetProperty<ChannelParameterCollection>().Add(fccParameters);

// NOW you can make the request.
channel.DoWork();

This also allows you to cache that issued token if you so desire to optimize some of the communication flowing around the system.

Granted, if you're not trying to dynamically insert claim requirements or if you're otherwise happy using the XML config and duplicating it on the server and the client, this isn't necessary. The CreateChannelActingAs(token) extension method and the whole Microsoft.IdentityModel stack takes care of this for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文