[WCF安全系列]谈谈WCF的客户端认证[X.509证书认证]
前面介绍Windows认证和用户名/密码认证这两种典型的客户端认证模式,我们最后来介绍最后一种客户端认证方式,即客户端凭证类型为X.509证书时服务端采用的认证,简称为证书认证。我们照例先看看看客户端证书凭证如何设置设置。
一、客户端证书凭证的设置
在服务认证一文中,我们知道了基于X.509证书证书的服务凭证通过X509CertificateRecipientServiceCredential类型表示。与之对应地,客户端凭证对应的类型是X509CertificateInitiatorClientCredential。如下面的定义所示,在终结点行为 ClientCredentials中,具有一个只读的ClientCertificate属性,其类型就是X509CertificateInitiatorClientCredential。该类型实际上是对一个X509Certificate2类型对象的封装,我们可以通过两个SetCertificate方法重载以证书引用的方式指定某个具体的X.509证书作为客户端的凭证。
1: public class ClientCredentials : SecurityCredentialsManager, IEndpointBehavior
2: {
3: //其他成员
4: public X509CertificateInitiatorClientCredential ClientCertificate { get; }
5: }
6: public sealed class X509CertificateInitiatorClientCredential
7: {
8: //其他成员
9: public void SetCertificate(string subjectName, StoreLocation storeLocation, StoreName storeName);
10: public void SetCertificate(StoreLocation storeLocation, StoreName storeName, X509FindType findType, object findValue);
11: public X509Certificate2 Certificate { get; set; }
12: }
在下面给出服务调用代码中,我们通过编程的方式为ChannelFactory<TChannel>设置了一个基于X.509证书的客户端凭证。
1: using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorService"))
2: {
3: channelFactory.Credentials.ClientCertificate.SetCertificate(
4: StoreLocation.LocalMachine,
5: StoreName.TrustedPeople,
6: X509FindType.FindBySubjectName,
7: "Foo");
8: ICalculator calculator = channelFactory.CreateChannel();
9: double result = calculator.Add(1, 2);
10: //...
11: }
终结点行为ClientCredentials同样为客户端(默认)证书的设置定义相应的配置。在下面给出的XML片断中,我们通过配置的方式为终结点凭证指定了一个X.509证书。这个证书将作为服务代理对象(通过ChannelFactory<TChannel>创建的代理,或者是直接实例化通过元数据导入生成的服务代理类型)的默认客户凭证,而该凭证可以通过编程进行动态更改。
1: <system.serviceModel>
2: ...
3: <behaviors>
4: <endpointBehaviors>
5: <behavior name="defaultClientCert">
6: <clientCredentials>
7: <clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="Foo"/>
8: </clientCredentials>
9: </behavior>
10: </endpointBehaviors>
11: </behaviors>
12: </system.serviceModel>
二、客户端证书认证模式
关于基于证书的客户端认证,你可以与基于证书的服务认证进行类比。对于服务认证,服务在寄宿的时候指定某个X.509证书作为服务的凭证。客户端在默认的情况下会以ChainTrust模式对服务证书进行认证,也可以通过ClientCredentials这个终结点行为指定不同的认证模式。对于客户端认证,认证方变成了服务本身,服务端对客户证书的认证也采用相同的策略:默认认证模式为ChainTrust,但借助ServiceCredentials这个服务行为来指定不同的认证模式。
下面给出了服务端进行客户端证书认证模式设置对应的相关类型的定义。服务行为ServiceCredentials中具有一个只读的ClientCertificate属性,类型为X509CertificateInitiatorServiceCredential(对应于服务认证中的X509CertificateRecipientClientCredential)。X509CertificateInitiatorServiceCredential定义了只读属性Authentication,其类型为X509ClientCertificateAuthentication(对应于服务认证中的X509ServiceCertificateAuthentication)。和X509ServiceCertificateAuthentication定义类似,你可以通过X509ClientCertificateAuthentication设置不同的认证模式(None、PeerTrust、ChainTrust、PeerOrChainTrust、Custom)。当你选择Custom模式的时候,你需要通过CustomCertificateValidator属性设置一个自定义的X509CertificateValidator。
1: public class ServiceCredentials : SecurityCredentialsManager, IServiceBehavior
2: {
3: //其他成员
4: public X509CertificateInitiatorServiceCredential ClientCertificate { get; }
5: }
6: public sealed class X509CertificateInitiatorServiceCredential
7: {
8: //其他成员
9: public X509ClientCertificateAuthentication Authentication { get; }
10: public X509Certificate2 Certificate { get; set; }
11: }
12: public class X509ClientCertificateAuthentication
13: {
14: //其他成员
15: public X509CertificateValidationMode CertificateValidationMode { get; set; }
16: public X509CertificateValidator CustomCertificateValidator { get; set; }
17: }
下面的代码演示了在对服务进行自我寄宿的情况下,如何设置对客户端证书进行认证的模式,在这里将认证模式设置成了PeerOrChainTrust。
1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
2: {
3: ServiceCredentials serviceCredentials = host.Description.Behaviors.Find<ServiceCredentials>();
4: if (null == serviceCredentials)
5: {
6: serviceCredentials = new ServiceCredentials();
7: host.Description.Behaviors.Add(serviceCredentials);
8: }
9: serviceCredentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
10: host.Open();
11: //...
12: }
我们推荐的依旧是采用配置的方式,上面这段代码中设置的服务行为可以通过下面一端配置来表示。
1: <system.serviceModel>
2: ...
3: <behaviors>
4: <serviceBehaviors>
5: <behavior name="setCertAuthentication">
6: <serviceCredentials>
7: <clientCertificate>
8: <authentication certificateValidationMode="PeerOrChainTrust"/>
9: </clientCertificate>
10: </serviceCredentials>
11: </behavior>
12: </serviceBehaviors>
13: </behaviors>
14: </system.serviceModel>
- Python函数参数总结(位置参数、默认参数、可变参数、关键字参数和命名关键字参数)
- linux学习第二十七篇:使用w查看系统负载,vmstat,top,sar,nload命令
- Python 函数
- Python set(集合) 这一定是最全的介绍集合的博文
- Spark你一定学得会(二)No.8
- Python dict(字典)
- Python 条件判断
- linux学习第二十五篇:cut,sort,wc,uniq,tee,tr,split命令,shell特殊符号
- Python list(列表)
- linux学习第三十篇:iptables filter表小案例,iptables nat表应用
- Python tuple(元组)
- 手把脚教你实现第一个在线预测系统No.21
- Python基本数据类型
- C++对象的赋值和复制
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python3 爬虫第三步 本文包你学会正则 不会就来锤我
- php基础教程 第三步 学习字符串及相关函数
- php基础教程 第四步 学习运算符
- php基础教程 第五步 逻辑控制
- php基础教程 第六步 学习数组以及条件判断switch补充
- php基础教程 第七步数组补充及循环基础
- php基础教程 第八步循环补充
- php基础教程 第九步 自定义函数
- php基础教程 第十步 阶段性知识补充
- php基础教程 第十一步 面向对象
- php基础教程 第十一步 面向对象补充
- Serverless|Framework——图文玩转 AWS Lambda
- C++入门指南及实战 第一步 概述及经典HelloWorld
- C++入门指南及实战 第二步 HelloWorld及扩展详解
- 依托于GitLab持续集成基础配置和使用