持久性已颁发令牌提供程序

此示例演示如何实现一个自定义客户端已颁发令牌提供程序。Windows Communication Foundation (WCF) 中的令牌提供程序用于为安全性基础结构提供凭据。令牌提供程序一般检查目标并颁发相应的凭据,以使安全性基础结构能够确保消息的安全。WCF 附带了一个 CardSpace 令牌提供程序。自定义令牌提供程序在下列情况下有用:

  • 存在不能由内置令牌提供程序操作的凭据存储区。
  • 想要提供自己的自定义传输机制,以便从用户提供详细信息这一刻起到 WCF 客户端框架使用凭据时转换凭据。
  • 要生成一个自定义令牌。

此示例演示如何生成一个自定义令牌提供程序,该提供程序可以缓存由安全令牌服务 (STS) 颁发的令牌。

总之,此示例将演示如下内容:

  • 如何使用自定义令牌提供程序对客户端进行配置。
  • 如何缓存已颁发的令牌并将它们提供给 WCF 客户端框架。
  • 客户端如何使用服务器的 X.509 证书对服务器进行身份验证。

此示例由客户端控制台程序 (client.exe)、安全令牌服务控制台程序 (securitytokenservice.exe) 和服务控制台程序 (service.exe) 组成。该服务实现定义“请求-答复”通信模式的协定。该协定由 ICalculator 接口定义,此接口公开数学运算(加、减、乘和除)。客户端从安全令牌服务 (STS) 中获取安全令牌,向给定数学运算的服务发出同步请求,服务使用结果进行回复。客户端活动显示在控制台窗口中。

提示

本主题的末尾介绍了此示例的设置过程和生成说明。

此示例使用 wsFederationHttpBinding Element公开 ICalculator 协定。下面的代码演示了此绑定在客户端上的配置。

<bindings>
  <wsFederationHttpBinding>
    <binding name="ServiceFed" >
      <security mode ="Message">
        <message issuedKeyType ="SymmetricKey" issuedTokenType ="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" >
          <issuer address ="https://localhost:8000/sts/windows" binding ="wsHttpBinding" />
        </message>
      </security>
    </binding>
  </wsFederationHttpBinding>
</bindings>

security element of wsFederationHttpBinding上,mode 值配置应使用哪种安全模式。在此示例中使用了消息安全性,这也是在 security element of wsFederationHttpBinding内指定 message element of wsFederationHttpBinding的原因。wsFederationHttpBinding 的消息元素内的 wsFederationHttpBinding 的 issuer 元素指定向客户端颁发安全令牌的安全令牌服务的地址和绑定,以使客户端能够向“计算器”服务进行身份验证。

下面的代码演示了此绑定在服务上的配置。

<bindings>
  <wsFederationHttpBinding>
    <binding name="ServiceFed" >
      <security mode ="Message">
        <message issuedKeyType ="SymmetricKey" issuedTokenType ="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" >
          <issuerMetadata address ="https://localhost:8000/sts/mex" >
            <identity>
              <certificateReference storeLocation ="CurrentUser" 
                                    storeName="TrustedPeople" 
                                    x509FindType ="FindBySubjectDistinguishedName" 
                                    findValue ="CN=STS" />
            </identity>
          </issuerMetadata>
        </message>
      </security>
    </binding>
  </wsFederationHttpBinding>
</bindings>

security element of wsFederationHttpBinding上,mode 值配置应使用哪种安全模式。在此示例中使用了消息安全性,这也是在 security element of wsFederationHttpBinding内指定 message element of wsFederationHttpBinding的原因。wsFederationHttpBinding 的消息元素内的 wsFederationHttpBinding 的 issuerMetadata 元素指定可用于检索安全令牌服务元数据的终结点的地址和标识。

下面的代码演示了该服务的行为。

<behavior name ="ServiceBehaviour" >
  <serviceDebug includeExceptionDetailInFaults ="true"/>
  <serviceMetadata httpGetEnabled ="true"/>
  <serviceCredentials>
    <issuedTokenAuthentication>
      <knownCertificates>
        <add storeLocation ="LocalMachine"
             storeName="TrustedPeople"
             x509FindType="FindBySubjectDistinguishedName"
             findValue="CN=STS" />
      </knownCertificates>
    </issuedTokenAuthentication>
    <serviceCertificate storeLocation ="LocalMachine"
                        storeName ="My"
                        x509FindType ="FindBySubjectDistinguishedName"
                        findValue ="CN=localhost"/>
  </serviceCredentials>
</behavior>

serviceCredentials 元素内的 issuedTokenAuthentication 元素允许服务对它在身份验证过程中允许客户端提供的令牌指定约束。此配置指定该服务接受由主题名称为 CN=STS 的证书签名的令牌。

SecurityTokenService 使用标准 wsHttpBinding 公开一个终结点。安全令牌服务响应客户端对令牌的请求,使用 Windows 帐户提供客户端身份验证并颁发包含客户端用户名(作为颁发的令牌中的声明)的令牌。作为创建令牌的一部分,安全令牌服务使用与 CN=STS 证书关联的私钥对令牌进行签名。另外,它还创建对称密钥并使用与 CN=localhost 证书关联的公钥对该密钥进行加密。在向客户端返回令牌的过程中,安全令牌服务还返回对称密钥。客户端向计算器服务出示颁发的令牌,并通过使用该对称密钥对消息进行签名来证明客户端知道该密钥。

自定义客户端凭据和令牌提供程序

下列步骤演示如何开发自定义令牌提供程序(用来缓存已颁发的令牌)并将其与 WCF 安全框架集成在一起:

  1. 编写自定义令牌提供程序。
    此示例实现一个自定义令牌提供程序,它返回从缓存中检索的安全令牌。
    为了执行此任务,自定义令牌提供程序派生了 SecurityTokenProvider 类,并重写了 GetTokenCore 方法。此方法尝试从缓存中获取令牌,如果在缓存中找不到令牌,则从基础提供程序中检索令牌并缓存该令牌。在这两种情况下,该方法都返回 SecurityToken

    protected override SecurityToken GetTokenCore(TimeSpan timeout)
    {
      GenericXmlSecurityToken token;
      if (!this.cache.TryGetToken(target, issuer, out token))
      {
        token = (GenericXmlSecurityToken) this.innerTokenProvider.GetToken(timeout);
        this.cache.AddToken(token, target, issuer);
      }
      return token;
    }
    
  2. 编写自定义安全令牌管理器。
    使用 SecurityTokenManager,可以为在 CreateSecurityTokenProvider 方法中传入该管理器的特定 SecurityTokenRequirement 创建 SecurityTokenProvider。安全令牌管理器还用于创建令牌身份验证器和令牌序列化程序,但它们不包括在此示例中。在此示例中,自定义安全令牌管理器继承自 ClientCredentialsSecurityTokenManager 类并重写 CreateSecurityTokenProvider 方法,这样,当所传递令牌的要求指示需要一个已颁发的令牌时,将返回自定义令牌提供程序。

    class DurableIssuedTokenClientCredentialsTokenManager :
     ClientCredentialsSecurityTokenManager
    {
      IssuedTokenCache cache;
    
      public DurableIssuedTokenClientCredentialsTokenManager ( DurableIssuedTokenClientCredentials creds ): base(creds)
      {
        this.cache = creds.IssuedTokenCache;
      }
    
      public override SecurityTokenProvider CreateSecurityTokenProvider ( SecurityTokenRequirement tokenRequirement )
      {
        if (IsIssuedSecurityTokenRequirement(tokenRequirement))
        {
          return new DurableIssuedSecurityTokenProvider ((IssuedSecurityTokenProvider)base.CreateSecurityTokenProvider( tokenRequirement), this.cache);
        }
        Else
        {
          return base.CreateSecurityTokenProvider(tokenRequirement);
        }
      }
    }
    
  3. 编写自定义客户端凭据。
    客户端凭据类用于表示为客户端代理配置的凭据并创建一个安全令牌管理器,该管理器用于获取令牌身份验证器、令牌提供程序和令牌序列化程序。

    public class DurableIssuedTokenClientCredentials : ClientCredentials
    {
      IssuedTokenCache cache;
    
      public DurableIssuedTokenClientCredentials() : base()
      {
      }
    
      DurableIssuedTokenClientCredentials ( DurableIssuedTokenClientCredentials other) : base(other)
      {
        this.cache = other.cache;
      }
    
      public IssuedTokenCache IssuedTokenCache
      {
        Get
        {
          return this.cache;
        }
        Set
        {
          this.cache = value;
        }
      }
    
      protected override ClientCredentials CloneCore()
      {
        return new DurableIssuedTokenClientCredentials(this);
      }
    
      public override SecurityTokenManager CreateSecurityTokenManager()
      {
        return new DurableIssuedTokenClientCredentialsTokenManager ((DurableIssuedTokenClientCredentials)this.Clone());
      }
    }
    
  4. 实现令牌缓存。该示例实现使用一个抽象基类,给定令牌缓存的使用方通过该基类与缓存进行交互。

    public abstract class IssuedTokenCache
    {
      public abstract void AddToken ( GenericXmlSecurityToken token, EndpointAddress target, EndpointAddress issuer);
      public abstract bool TryGetToken(EndpointAddress target, EndpointAddress issuer, out GenericXmlSecurityToken cachedToken);
    }
    Configure the client to use the custom client credential.
    

    为了使客户端使用自定义客户端凭据,该示例删除了默认的客户端凭据类,并提供了新的客户端凭据类。

    clientFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
    DurableIssuedTokenClientCredentials durableCreds = new DurableIssuedTokenClientCredentials();
    durableCreds.IssuedTokenCache = cache;
    durableCreds.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
    clientFactory.Endpoint.Behaviors.Add(durableCreds);
    

运行示例

请参见下面的说明来运行该示例。运行示例时,对安全令牌的请求显示在安全令牌服务控制台窗口中。操作请求和响应显示在客户端和服务控制台窗口中。在任何一个控制台窗口中按 Enter 可以关闭应用程序。

设置批处理文件

通过运行此示例随附的 Setup.cmd 批处理文件,可以用相关的证书配置服务器和安全令牌服务以运行自承载的应用程序。批处理文件在 CurrentUser/TrustedPeople 证书存储区中创建两个证书。第一个证书的主题名称为 CN=STS,并由安全令牌服务用来对颁发给客户端的安全令牌进行签名。第二个证书的主题名称为 CN=localhost,并由安全令牌服务用来加密机密,以便服务能够解密该机密。下面提供了批处理文件不同节的简要概述,以便可以修改批处理文件从而在相应的配置中运行。

设置、生成和运行示例

  1. 运行 Setup.cmd 文件以创建所需的证书。

  2. 若要生成解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。确保生成解决方案中的所有项目(Shared、RSTRSTR、Service、SecurityTokenService 和 Client)。

  3. 确保 Service.exe 和 SecurityTokenService.exe 都在运行。

  4. 运行 client.exe。

运行示例后进行清除

  1. 运行完示例后运行示例文件夹中的 Cleanup.cmd。

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.