一、netTCPBinding.1
3、安全模式 – Message.1
3.1.客戶端驗證 – None.2
3.1.1.獲得和安裝證書...2
3.1.2.服務端代碼...2
3.1.3.客戶端代碼...3
3.1.4.測試...3
3.2.客戶端驗證 – Windows.3
3.2.1.獲得和安裝證書...4
3.2.2.服務端代碼...4
3.2.3.客戶端代碼...4
3.2.4.測試...5
3.3.客戶端驗證 – UserName.5
3.3.1.獲得和安裝證書...5
3.3.2.服務端代碼...6
3.3.3.客戶端代碼...8
3.3.4.測試...9
3.3.5.身份模擬和訪問權限控制...9
3.4.客戶端驗證:Certificate.10
3.4.1.獲得和安裝證書...10
3.4.2.服務端代碼...11
3.4.3.客戶端代碼...11
3.4.4.測試...12
3.4.5.證書映射到windows用戶...12
一、netTCPBinding
此綁定使用TCP傳輸協議,不具交互性,只適用於 WCF 到 WCF 的通信。
此綁定的傳輸安全性的實現:
l 安全模式Message
這種模式WCF中都一樣,都是使用WS-*通過對SOAP消息本身進行加密、簽名等 等的處理來保證安全性。Message模式不依賴於傳輸協議。服務端需要指定服務 端證書,用來加密服務端和客戶端相互傳送的消息。
l Transport – 客戶端windows驗證
使用windows security保證消息的安全,使用windows credential進行身份 驗證。
這種方式不需要服務端證書。
至於windows security的實現安全的原理我還不明白,這部分尚待了解。
l Transport – 客戶端其他驗證方式
使用TLS over TCP實現傳輸安全性,需要服務端證書。
一般大家對SSL比較熟悉,對TLS可能要陌生些,其實可以說TLS協議可以看作 跟SSL協議後續版本。1994年,netscape為了在internet上進行安全的數據傳輸 ,開發了的SSL協議,後來標准化組織把SSL標准化了,稍作修改改名叫TLS,在 一般的使用意義上,這兩個協議差別不大,就是在保證消息完整性的散列算法上 使用了不同的算法。
TLS over TCP 直接建立在TCP協議上,通過傳輸層TCP協議實現安全性。
netTCPBinding綁定是直接使用TCP協議,不走HTTP,所以不能使用IIS宿主。 這部分的測試實例采用自宿主的服務端console應用,基於代碼的方式。
3、安全模式 – Message
這部分測試netTCPBinding綁定的Message安全模式的各種情況。
共用測試WCF服務類
所有測試都是用同樣的服務端contract和實現這個contract的service:
[ServiceContract(Namespace = "http://chnking.com")]
public interface IGetIdentity
{
[OperationContract]
string Get(string ClientIdentity);
}
public class GetIdentity : IGetIdentity
{
public string Get(string ClientIdentity)
{
return ("服務端Identity 是'" + ServiceSecurityContext.Current.PrimaryIdentity.Name +
"'\n\r客戶端Identity是 '" + ClientIdentity + "'");
}
}
代碼很簡單,一個contract提供了一個Get方法,接收一個string參數,返回 一個string參數。在後面的測試中,客戶端把客戶端安全上下文的Identity發送 到服務端,服務端返回服務端安全上下文的Identity給客戶端。
3.1.客戶端驗證 – None
這部分的測試代碼: NetTcpBinding_Message_None.rar
netTCPBinding綁定的Message安全模式,客戶端None驗證。此時將使用服務 端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制(但不 是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安全性。
這種方式的安全性:
完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 沒有
3.1.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
3.1.2.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
//設置服務端證書
myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
3.1.3.客戶端代碼
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//不驗證服務端證書的有效性
gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
3.1.4.測試
3.2.客戶端驗證 – Windows
這部分的測試代碼: NetTcpBinding_Message_Windows.rar
netTCPBinding綁定的Message安全模式,客戶端Windows驗證。此時將使用服 務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制(但 不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安全性 。
這種方式的安全性:
完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 Windows身份驗證
3.2.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
3.2.2.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
//設置服務端證書
myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
3.2.3.客戶端代碼
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//不驗證服務端證書的有效性
gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
3.2.4.測試
可以看出,客戶端windows身份被傳送到服務端。
3.3.客戶端驗證 – UserName
這部分的測試代碼: NetTcpBinding_Message_UserName.rar
netTCPBinding綁定的Message安全模式,客戶端使用UserName驗證。此時將 使用服務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機 制(但不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的 安全性。
這種方式的安全性:
完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 客戶端提供的用戶名和密碼
3.3.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
3.3.2.服務端代碼
Contract和Services部分的代碼:
[ServiceContract(Namespace = "http://chnking.com")]
public interface IGetIdentity
{
[OperationContract]
string Get(string ClientIdentity);
}
public class GetIdentity : IGetIdentity
{
[PrincipalPermission(SecurityAction.Demand, Role = "admin")]
public string Get(string ClientIdentity)
{
IPrincipal myWindowsPrincipal = (IPrincipal) Thread.CurrentPrincipal;
return ("Identity of server is'" + myWindowsPrincipal.Identity.Name +
"'\n\rIdentity of client is '" + ClientIdentity + "'");
}
}
這部分代碼跟前面的測試例子一樣,只是為了測試服務端模擬身份後的權限 控制在Get方法前增加了了如下的控制訪問的attribute:
[PrincipalPermission(SecurityAction.Demand, Role = "admin")]
表示只有運行方法的當前線程安全上下文的identity屬於admin角色時才有權 限訪問這個方法。
服務宿主部分的代碼:
internal class MyServiceHost
{
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
//設置服務端證書
myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
//默認服務端PrincipalPermissionMode為UseWindowsGroups,將 Thread.CurrentPrincipal設置為WindowsPrincipal
//一般是windows驗證時映射到windows用戶。
//本例需要自己設置Thread.CurrentPrincipal,故此處設置為None
myServiceHost.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.None;
//設置客戶端username在服務端驗證模式為Custom
myServiceHost.Credentials.UserNameAuthentication.UserNamePasswordValid ationMode =
System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
myServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswor dValidator = new customUserNamePasswordValidator();
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
}
public class customUserNamePasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
public override void Validate(string username, string password)
{
if (username == "chnking" && password == "jjz666")
{
string[] roles = { "admin", "operator" };
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("chnking", "Custom"), roles);
}
else
{
throw(new SecurityTokenException("用戶名或密碼無效! "));
}
}
}
這部分代碼有幾處需要說明:
客戶端使用UserName驗證方式,在服務端可以使用對客戶端發送來的 UserName的驗證方式有三種:
Windows:用windows的帳號和密碼驗證客戶端送來的UserName。
MembershipProvider:提供基於已配置的MembershipProvider的密碼驗證。
Custom:由自定義的從UserNamePasswordValidator繼承來的類驗證用戶名和 密碼。
本例中選用自定義驗證,並新建了一個從UserNamePasswordValidator繼承來 的類customUserNamePasswordValidator來驗證客戶端用戶名和口令。
驗證了用戶正確後,新建一個跟此用戶對應的GenericPrincipal,包括這個 用戶的Identity,這裡叫做”chnking”,和這個identity所屬的角 色,這裡這個用戶同時屬於"admin", "operator"。還把 這個用戶的GenericPrincipal賦給了Thread.CurrentPrincipal,使本線程往下 的運行上下文切換到這個定制的GenericPrincipal。
還有一點,服務端的PrincipalPermissionMode默認是UseWindowsGroups,這 表示將Thread.CurrentPrincipal設置為WindowsPrincipal,一般是windows驗證 時映射到windows用戶。本例需要自己設置Thread.CurrentPrincipal,故此處設 置為None,否則,到了執行服務端services代碼時,Thread.CurrentPrincipal 將為空。
3.3.3.客戶端代碼
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
EndpointAddress ea = new EndpointAddress ("net.tcp://jinjz2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//不驗證服務端證書的有效性
gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
//提供UserName客戶端用戶憑據
gc.ClientCredentials.UserName.UserName = "chnking";
gc.ClientCredentials.UserName.Password = "jjz666";
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("net.tcp://jinjz2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
客戶端沒有太多需要特別說明的。設置客戶端驗證方式為UserName後用以下 代碼提供用戶名和口令:
//提供UserName客戶端用戶憑據
gc.ClientCredentials.UserName.UserName = "chnking";
gc.ClientCredentials.UserName.Password = "jjz666";
3.3.4.測試
可以看出,客戶端的chnking身份被傳送到服務端。並且,有權限執行服務端 的Get方法。
3.3.5.身份模擬和訪問權限控制
如果在服務端的Get方法中設置一個斷點,如下圖:
可以看到當代碼運行到Get方法中時,當前線程的Principal就是在 customUserNamePasswordValidator定制類中賦給的chnking,並且這個chnking 屬於admin角色。
如果把Get的權限改一下,改成只有叫”manager”的角色可以方 法此方法:
[PrincipalPermission(SecurityAction.Demand, Role = " manager ")]
public string Get(string ClientIdentity)
再看運行結果:
Chning不屬於”manager”角色,也就沒有執行Get方法的權限。
3.4.客戶端驗證:Certificate
這部分的測試代碼: NetTcpBinding_Message_Certificate.rar
netTCPBinding綁定的Message安全模式,客戶端Certificate驗證,此時將使 用服務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制 (但不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安 全性。
這種方式的安全性:
完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 客戶端證書提供
3.4.1.獲得和安裝證書
同時客戶端驗證設置為Certificate,就需要提供客戶端證書以驗證客戶端身 份。
所有這裡需要在服務端和客戶端分別安裝證書。
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
makecert -sr currentuser -ss My -n CN=TestClient -sky exchange -pe -r
這是客戶端證書。
3.4.2.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
//設置服務端證書
myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
//設置不驗證客戶端證書的有效性
myServiceHost.Credentials.ClientCertificate.Authentication.Certificate ValidationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
3.4.3.客戶端代碼
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//設置客戶端證書
gc.ClientCredentials.ClientCertificate.SetCertificate ("CN=TestClient",
StoreLocation.CurrentUser, StoreName.My);
//設置不驗證服務端證書有效性
gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
3.4.4.測試
由於客戶端是Certificate身份驗證,到了服務端 ServiceSecurityContext.Current.PrimaryIdentity.Name獲得的是證書的 subject name和證書指紋。
3.4.5.證書映射到windows用戶
有時需要把客戶端證書映射為服務端的windows用戶,這樣可以使用windows 權限控制客戶端在服務端的權限。
在本例的情況,可以設置客戶端證書跟服務端windows用戶的映射,首先在服 務端的代碼或配置文件中設置允許客戶端證書到服務端windows用戶的映射。
代碼中將客戶端驗證MapClientCertificateToWindowsAccount設為True:
myServiceHost.Credentials.ClientCertificate.Authentication.Ma pClientCertificateToWindowsAccount = true;
配置文件中將服務端Behavior的客戶端證書驗證 MapClientCertificateToWindowsAccount設為True:
<serviceBehaviors>
<behavior>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" mapClientCertificateToWindowsAccount="True" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
然後在服務端設置映射,在操作系統上把客戶端的證書與windows用戶作映射 ,這必須是要在安裝了Active Directory的服務器上做。
具體步驟參考文章:Map certificates to user accounts: http://technet2.microsoft.com/WindowsServer/f/?en/library/0539dcf5- 82c5-48e6-be8a-57bca16c7e171033.mspx