2013-02-06 14 views
11

Tóm tắt: Tôi đang làm việc trên một WCF client .NET 4.0 để tiêu thụ một dịch vụ web (DataPower, dịch vụ Java ở đầu kia) sử dụng SOAP 1.1 và WS-Security 1.0. Các khách hàng WCF phải thực hiện một chứng chỉ khách hàng để xác thực lẫn nhau ở tầng vận chuyển. Nội dung thư phải được ký bằng chứng chỉ dịch vụ/ký riêng. Tiêu đề SOAP cũng cần chứa một Mã thông báo Tên người dùng với Mật khẩu Thông báo và bao gồm các thẻ Nonce và Created.WCF SOAP 1.1 và WS-Security 1.0, giao thông vận tải chứng chỉ khách hàng auth, dịch vụ cert để ký kết nội dung thư, UsernameToken, Mật khẩu Digest, nonce

Tôi có thể sử dụng dịch vụ web này bằng WSE 3.0 với BasicHTTPBinding. Nhưng tôi đã không thành công cho đến nay trong việc thực hiện cùng với WCF bằng cách sử dụng hoặc WSHttpBinding hoặc CustomBinding. Tôi đã thử tất cả các yếu tố ràng buộc an ninh và không có may mắn cho đến nay.

Tôi cũng đang sử dụng thư viện tên người dùng từ đây (http://blogs.msdn.com/b/aszego/archive/2010/06/24/usernametoken-profile-vs-wcf.aspx) để tôi có thể thêm mật khẩu thông báo/nonce/được tạo trong tiêu đề UsernameToken trong SOAP.

Tôi hiện đang sử dụng SecurityBindingElement.CreateMutualCertificateBindingElement Tôi cũng đã thử một số người khác như AsymmetricSecurityBindingElement, TransportSecurityBindingElement vv (chú thích trong mã dưới đây)

Certs: Tôi có cả giấy chứng nhận của khách hàng và dịch vụ chứng nhận nạp vào kho lưu trữ chứng chỉ bằng MMC (Tôi đang sử dụng Windows 7 btw.) Cả chứng chỉ ứng dụng khách và cert dịch vụ đều có khóa riêng. Tôi đã tải cả hai tệp PFX vào LocalMachine/Personal, LocalMachine/Root và LocalMachine/TrustedPeople. Tôi cũng chạy FindPrivateKey/ICACLS để cấp quyền cho tài khoản “IIS App Pool/DefaultAppPool”. Mặc dù không có vấn đề gì trong số này đáng kể vì tôi có thể chạy mã WSE 3.0 từ máy của mình và nó hoạt động mà không có bất kỳ vấn đề nào về cert.

Lệnh chạy:

FindPrivateKey.exe My LocalMachine -t "thumbprint of client cert" 
FindPrivateKey.exe My LocalMachine -t "thumbprint of service cert" 
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfClientCert} /grant "IIS AppPool\DefaultAppPool":R  <<Successfully processed 1 files; Failed processing 0 files>> 
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfServiceCert} /grant "IIS AppPool\DefaultAppPool":R  <<Successfully processed 1 files; Failed processing 0 files>> 

WCF CẤP: Tôi hiện nhận được một “Không thể thiết lập kênh an toàn cho SSL/TLS có thẩm quyền 'x.x.com” nhắn lại từ cổng DataPower. Tôi hình này có thể là do gateway đang lấy chứng chỉ dịch vụ và sử dụng nó để xác thực ứng dụng khách thay vì sử dụng chứng chỉ ứng dụng khách mà tôi đang gửi. Tôi đang nói điều này bởi vì khi tôi không chỉ định DNS Identity cho điểm cuối, tôi lấy lại một thông báo nói rằng gateway đang mong nhận dạng DNS là “{tên chủ đề của dịch vụ/chứng chỉ ký tên}”.

Đây là yêu cầu SOAP do WCF tạo ra, đưa ra lỗi trên. Yêu cầu SOF WCF trông rất giống với yêu cầu WSE SOAP. Lỗi trên hầu hết có thể xảy ra do sự cố chứng chỉ ở lớp SSL/Giao thông vận tải.

WCF yêu cầu SOAP:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
<s:Header> 
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> 
     <u:Timestamp u:Id="uuid-8533d9a5-865e-4a4b-a750-fadb7c1ce36c-1"> 
      <u:Created>2013-02-06T20:53:04.679Z</u:Created> 
      <u:Expires>2013-02-06T20:58:04.679Z</u:Expires> 
     </u:Timestamp> 
     <o:BinarySecurityToken u:Id="uuid-0bab08ce-3e3b-4360-a44b-694b06a3dd67-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">Removed Service Cert Encoded Value</o:BinarySecurityToken> 
     <wsse:UsernameToken wsu:Id="7843ab92-f69a-4d00-a5ba-117e32a74f49" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
          xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
      <wsse:Username>USER_Removed</wsse:Username> 
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">XXX=</wsse:Password> 
      <wsse:Nonce>XXX==</wsse:Nonce> 
      <wsu:Created>2013-02-06T20:53:04Z</wsu:Created> 
     </wsse:UsernameToken> 
     <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
      <SignedInfo> 
       <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod> 
       <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
       <Reference URI="#_1"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#uuid-8533d9a5-865e-4a4b-a750-fadb7c1ce36c-1"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#7843ab92-f69a-4d00-a5ba-117e32a74f49"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
      </SignedInfo> 
      <SignatureValue>XXXLongXXX=</SignatureValue> 
      <KeyInfo> 
       <o:SecurityTokenReference> 
        <o:Reference URI="#uuid-0bab08ce-3e3b-4360-a44b-694b06a3dd67-2"></o:Reference> 
       </o:SecurityTokenReference> 
      </KeyInfo> 
     </Signature> 
    </o:Security> 
</s:Header> 
<s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <ping xmlns="https://x.x.com/xxx/v1"> 
     <pingRequest xmlns="">hello</pingRequest> 
    </ping> 
</s:Body> 

WSE 3.yêu cầu 0 SOAP (chỉ hoạt động này):

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
      xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
<soap:Header> 
    <wsa:Action wsu:Id="Id-4271fb72-464a-467d-ab1f-4d32542e20f0"/> 
    <wsa:MessageID wsu:Id="Id-11657f64-d856-47d8-b600-d5379fb91a0d">urn:uuid:ff8becb7-74c2-4844-ab46-8ae23f1355a7</wsa:MessageID> 
    <wsa:ReplyTo wsu:Id="Id-40b2e6e8-e67b-4a6c-a545-071ce0f0107a"> 
     <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address> 
    </wsa:ReplyTo> 
    <wsa:To wsu:Id="Id-d5e0b488-6f8a-479c-940d-2b85833dbc66">https://x.x.com/xxx/v1</wsa:To> 
    <wsse:Security soap:mustUnderstand="1"> 
     <wsu:Timestamp wsu:Id="Timestamp-68476551-5c58-4a47-967b-54ec18257b1b"> 
      <wsu:Created>2013-02-06T19:38:39Z</wsu:Created> 
      <wsu:Expires>2013-02-06T19:43:39Z</wsu:Expires> 
     </wsu:Timestamp> 
     <wsse:UsernameToken wsu:Id="SecurityToken-e5f65166-a825-48cb-a939-8e515a637e01"> 
      <wsse:Username>USER_Removed</wsse:Username> 
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">XXX=</wsse:Password> 
      <wsse:Nonce>XXX==</wsse:Nonce> 
      <wsu:Created>2013-02-06T19:38:39Z</wsu:Created> 
     </wsse:UsernameToken> 
     <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
      <SignedInfo> 
       <ds:CanonicalizationMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
       <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
       <Reference URI="#Id-4271fb72-464a-467d-ab1f-4d32542e20f0"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#Id-11657f64-d856-47d8-b600-d5379fb91a0d"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#Id-40b2e6e8-e67b-4a6c-a545-071ce0f0107a"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#Id-d5e0b488-6f8a-479c-940d-2b85833dbc66"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#Timestamp-68476551-5c58-4a47-967b-54ec18257b1b"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
       <Reference URI="#Id-6f76e50e-932c-4878-bbc0-3ef4c8a36990"> 
        <Transforms> 
         <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> 
        </Transforms> 
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
        <DigestValue>XXX=</DigestValue> 
       </Reference> 
      </SignedInfo> 
      <SignatureValue>XXXLongXXX=</SignatureValue> 
      <KeyInfo> 
       <wsse:SecurityTokenReference> 
        <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" 
             EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">XXX=</wsse:KeyIdentifier> 
       </wsse:SecurityTokenReference> 
      </KeyInfo> 
     </Signature> 
    </wsse:Security> 
</soap:Header> 
<soap:Body wsu:Id="Id-6f76e50e-932c-4878-bbc0-3ef4c8a36990"> 
    <ping xmlns="https://x.x.com/xxx/v1"> 
     <pingRequest xmlns="">hello</pingRequest> 
    </ping> 
</soap:Body> 

Dưới đây là tất cả các cấu hình, xin vui lòng cho tôi biết những gì tôi đang làm sai!

WCF web.config: Tôi đã xóa mọi thứ khỏi web.config vì tôi đang thực hiện tất cả cấu hình trong mã.

WCF config trong mã:

var proxy = GetProxy(); 
pingResponseMessage resp = proxy.ping("hello"); 
lblStatus.Text = resp.status.ToString(); 

private XXXClient GetProxy() 
{ 

    System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; }; 

    XXXClient proxy = new XXXClient(GetCustomBinding(), new EndpointAddress(new Uri("https://xxx"), EndpointIdentity.CreateDnsIdentity("I am forced to put the signing cert subject here, nothing else works"), new AddressHeaderCollection())); 

    proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials)); 
    proxy.Endpoint.Behaviors.Add(new UsernameClientCredentials(new UsernameInfo(@"USER_Removed", "X"))); 

    proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED"); 
    proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED"); 
    proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None; 

    return proxy; 
} 

private Binding GetCustomBinding() 
{ 
    //TransportSecurityBindingElement secBE = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10); 
    //AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); 
    //secBE.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier }; 
    //secBE.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToInitiator, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier }; 
    //secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt; 
    //secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters() { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false }); 
    //secBE.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.Never) { InclusionMode = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier }); 
    //secBE.ProtectionTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient }; 
    //secBE.DefaultAlgorithmSuite = new CustomSecurityAlgorithm(); 

    SecurityBindingElement secBE = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); 
    secBE.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; 
    secBE.EndpointSupportingTokenParameters.Signed.Add(new UsernameTokenParameters() { InclusionMode= SecurityTokenInclusionMode.AlwaysToRecipient, ReferenceStyle = SecurityTokenReferenceStyle.External, RequireDerivedKeys = false }); 
    secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict; 
    //secBE.AllowInsecureTransport = false; 
    //secBE.AllowSerializedSigningTokenOnReply = false; 
    secBE.EnableUnsecuredResponse = true; 
    secBE.IncludeTimestamp = true; 
    secBE.SetKeyDerivation(false); 

    TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8); 

    HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement(); 
    httpsBE.RequireClientCertificate = true; 
    //httpsBindingElement.AllowCookies = false; 
    //httpsBindingElement.AuthenticationScheme = System.Net.AuthenticationSchemes.Basic; 
    httpsBE.BypassProxyOnLocal = false; 
    httpsBE.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard; 
    //httpsBindingElement.KeepAliveEnabled = false; 
    httpsBE.TransferMode = TransferMode.Buffered; 
    httpsBE.UseDefaultWebProxy = true; 

    CustomBinding myBinding = new CustomBinding(); 
    myBinding.Elements.Add(secBE); 
    myBinding.Elements.Add(textEncBE); 
    myBinding.Elements.Add(httpsBE); 

    return myBinding; 
} 

Tôi đã thêm ProtectionLevel.Sign trên ServiceContract và OperationContracts kể từ khi tôi chỉ cần phải đăng nội dung thư. Tôi đã không nhận được điều này đến nay để xác minh nó.

[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ConfigurationName = "x.x", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)] 
public interface XXXService { 
    [System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)] 
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)] 
    [return: System.ServiceModel.MessageParameterAttribute(Name="return")] 
    XXX.pingResponse ping(XXX.ping request); 

[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)] 
public partial class XXXClient : System.ServiceModel.ClientBase<XXXService> { 
    [System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)] 
    public XXX.pingResponseMessage ping(string pingRequest) { 

Tôi đã thêm sau dưới đây để web.config để cho phép khai thác gỗ của toàn bộ xà phòng bao gồm dữ liệu pii

(for pii, also added <machineSettings enableLoggingKnownPii="true" /> under <system.serviceModel> to C:\Windows\Microsoft.NET\Framework\vX\CONFIG\machine.config) 

<system.serviceModel> 
<diagnostics> 
    <messageLogging logKnownPii="true" logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="3000"/> 
</diagnostics> 
</system.serviceModel> 
<system.diagnostics> 
<sources> 
    <source name="System.ServiceModel.MessageLogging" logKnownPii="true"> 
    <listeners> 
     <add initializeData="C:\trace.log" type="System.Diagnostics.XmlWriterTraceListener" name="messages"/> 
    </listeners> 
    </source> 
</sources> 
</system.diagnostics> 

============== =

WSE 3.0 (cấu hình và mã làm việc): web.config:

<system.serviceModel> 
<bindings> 
    <basicHttpBinding> 
    <binding name="myBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> 
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> 
     <security mode="Transport"> 
     <transport clientCredentialType="None" proxyCredentialType="None" realm=""/> 
     <message clientCredentialType="UserName" algorithmSuite="Default"/> 
     </security> 
    </binding> 
    </basicHttpBinding> 
</bindings> 
<client> 
    <endpoint address="https://x.x.com/xxx/v1" binding="basicHttpBinding" bindingConfiguration="myBinding" contract="XXXService" name="XXX"/> 
</client> 
</system.serviceModel> 
<appSettings> 
<add key="XXXImplService" value="https://x.x.com/xxx/v1"/> 
</appSettings> 

... và WSE3 mã:

var proxy = new XXXImplServiceWse(); 

UsernameToken usernameToken = new UsernameToken(@"USER_Removed", "X"); 
proxy.RequestSoapContext.Security.Tokens.Add(usernameToken); 

X509Certificate2 mutualCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Client Cert Subject Name"); 
proxy.ClientCertificates.Add(mutualCert); 

X509Certificate2 signCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Service Cert Subject Name"); 

X509SecurityToken signatureToken = new X509SecurityToken(signCert); 

MessageSignature signature = new MessageSignature(signatureToken); // <!-- IS THIS SAME AS THIS STEP IN WCF: secBE.EndpointSupportingTokenParameters.Signed.Add(new UsernameTokenParameters()) --> 

proxy.RequestSoapContext.Security.Elements.Add(signature); 

==========

Vì vậy, làm thế nào để chuyển đổi các mã trên WSE 3,0 đến WCF?

+0

Tại sao bạn muốn chuyển đổi ngay từ đầu khi bạn có giải pháp làm việc trong WSE 3.0? Đối với câu hỏi của bạn trong mã WSE: Không có mã thông báo hỗ trợ điểm cuối nào là tính năng hoàn toàn khác. Btw. bạn cũng cần WS-Addressing (nó được sử dụng trong WSE client). –

+1

Chúng tôi có một khách hàng khẳng định rằng chúng tôi cung cấp cho họ phiên bản WCF vì họ nói WSE 3.0 là "công nghệ cũ" ... Tôi không nghĩ là giải quyết vấn đề, nhưng chắc chắn chỉ cho phù hợp, chúng tôi sẽ giữ nó Soap11WSAddressing10 – Jawad

+0

Tôi sẽ xem xét vấn đề này vào cuối tuần - Tôi quan tâm đến bản thân nhưng được chuẩn bị rằng có thể không có giải pháp cho WCF (ngoại trừ viết bảo mật theo cách thủ công) - WCF không bao gồm tất cả các tùy chọn trước đó có sẵn trong WSE 3.0. Hết sức tò mò: bạn có WS-SecurityPolicy (thường là một phần của triển khai dịch vụ WSDL hoặc Java) hay yêu cầu mẫu và phản hồi cho dịch vụ (không phải do những dịch vụ được tạo ra bởi WSE nhưng máy khách Java)? –

Trả lời

6

Tôi có thể giải quyết vấn đề của mình và kết nối với Cổng Dịch vụ Web DataPower (IBM Xi50) bằng WCF CustomB sau inding (CertificateOverTransport) và CustomCredentials (UsernameToken với Password Digest, chứng thực của khách hàng để xác thực vận chuyển và cert dịch vụ cho chữ ký của thân thư.) Tôi không chắc chính xác vấn đề đã được khắc phục, nhưng đây là mã WCF đang hoạt động của tôi! Tôi hy vọng điều này sẽ giúp những người khác đang ở trong một tình huống tương tự như tôi.

Vui lòng xác minh rằng cổng DataPower Xi50 cũng được định cấu hình cho WCF. Từ IBM: "Khi sử dụng BasicHttpBinding với SSL: Bạn có thể sử dụng tham số check-ssl-cipher-check để vô hiệu hóa các kiểm tra mật mã cho bất kỳ xác nhận TransportBinding nào. Trình cơ bản Auth Header không được hỗ trợ mặc định trong proxy dịch vụ Web. quy tắc on-error để chèn tiêu đề WWW-Authenticate được yêu cầu để liên kết với WCF. " Để biết chi tiết, hãy truy cập tại đây: https://publib.boulder.ibm.com/infocenter/ieduasst/v1r1m0/index.jsp?topic=/com.ibm.iea.wdatapower/wdatapower/1.0/xa35/380DataPowerWCFIntegration/player.html.

Hãy chắc chắn rằng bạn đã cài ProtectionLevel.Sign trên hợp đồng dịch vụ của bạn nếu bạn muốn nội dung thư của bạn chỉ có chữ ký (và không được mã hóa.)

Đối với DNS Identity, mà tôi có vấn đề với trước đó, bây giờ tôi đã có thể đặt tên chủ đề chứng chỉ ứng dụng khách của tôi - trước đó điều này sẽ không hoạt động.

Tôi không có bất kỳ cấu hình nào trong web.config của mình.

Dưới đây là Proxy sử dụng CustomBinding:

private ClientProxy GetProxy() 
{ 
    XXXServiceClient proxy = new XXXServiceClient(GetCustomBinding(), new EndpointAddress(new Uri("<<GatewayURLHere>>"), EndpointIdentity.CreateDnsIdentity("<<DNS or Client Cert Subject Name>>"), new AddressHeaderCollection())); 
    proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials)); 
    proxy.Endpoint.Behaviors.Add(new CustomCredentials(<clientCertHere>, <signingCertHere>)); 
    proxy.ClientCredentials.UserName.UserName = @"XXX"; 
    proxy.ClientCredentials.UserName.Password = "yyy"; 
    return proxy; 
} 

private Binding GetCustomBinding() 
{ 
    TransportSecurityBindingElement secBE = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); 
    secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false }); 
    secBE.EnableUnsecuredResponse = true; 
    secBE.IncludeTimestamp = true; 
    TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, System.Text.Encoding.UTF8); 
    HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement(); 
    httpsBE.RequireClientCertificate = true; 

    CustomBinding myBinding = new CustomBinding(); 
    myBinding.Elements.Add(secBE); 
    myBinding.Elements.Add(textEncBE); 
    myBinding.Elements.Add(httpsBE); 

    return myBinding; 
} 

Đây là lớp CustomCredentials của tôi mà tôi đặt lại với nhau từ nhiều nguồn khác nhau bao gồm các thư viện UsernameToken nêu trên - bộ giấy chứng nhận của khách hàng để xác thực (lẫn nhau?) Tại lớp truyền tải , dịch vụ/ký giấy chứng nhận để ký nội dung thư và UsernameToken với Password Digest trong tiêu đề SOAP:

using System; 
using System.IdentityModel.Selectors; 
using System.IdentityModel.Tokens; 
using System.Security.Cryptography; 
using System.Security.Cryptography.X509Certificates; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Security; 
using System.Text; 

namespace XXX_WCF 
{ 
    public class CustomCredentials : ClientCredentials 
    { 
     private X509Certificate2 clientAuthCert; 
     private X509Certificate2 clientSigningCert; 

     public CustomCredentials() : base() { } 

     public CustomCredentials(CustomCredentials other) 
      : base(other) 
     { 
      clientSigningCert = other.clientSigningCert; 
      clientAuthCert = other.clientAuthCert; 
     } 

     protected override ClientCredentials CloneCore() 
     { 
      CustomCredentials scc = new CustomCredentials(this); 
      return scc; 
     } 

     public CustomCredentials(X509Certificate2 ClientAuthCert, X509Certificate2 ClientSigningCert) 
      : base() 
     { 
      clientAuthCert = ClientAuthCert; 
      clientSigningCert = ClientSigningCert; 
     } 

     public X509Certificate2 ClientAuthCert 
     { 
      get { return clientAuthCert; } 
      set { clientAuthCert = value; } 
     } 

     public X509Certificate2 ClientSigningCert 
     { 
      get { return clientSigningCert; } 
      set { clientSigningCert = value; } 
     } 

     public override SecurityTokenManager CreateSecurityTokenManager() 
     { 
      return new CustomTokenManager(this); 
     } 
    } 

    public class CustomTokenManager : ClientCredentialsSecurityTokenManager 
    { 
     private CustomCredentials custCreds; 

     public CustomTokenManager(CustomCredentials CustCreds) 
      : base(CustCreds) 
     { 
      custCreds = CustCreds; 
     } 

     public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
     { 
      if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate) 
      { 
       x509CustomSecurityTokenProvider prov; 
       object temp = null; 
       TransportSecurityBindingElement secBE = null; 

       if (tokenRequirement.Properties.TryGetValue("http://schemas.microsoft.com/ws/2006/05/servicemodel/securitytokenrequirement/SecurityBindingElement", out temp)) 
       { 
        secBE = (TransportSecurityBindingElement)temp; 
       } 

       if (secBE == null) 
        prov = new x509CustomSecurityTokenProvider(custCreds.ClientAuthCert); 
       else 
        prov = new x509CustomSecurityTokenProvider(custCreds.ClientSigningCert); 
       return prov; 
      } 

      return base.CreateSecurityTokenProvider(tokenRequirement); 
     } 

     public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version) 
     { 
      return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity10); 
     } 
    } 

    class x509CustomSecurityTokenProvider : SecurityTokenProvider 
    { 
     private X509Certificate2 clientCert; 

     public x509CustomSecurityTokenProvider(X509Certificate2 cert) 
      : base() 
     { 
      clientCert = cert; 
     } 

     protected override SecurityToken GetTokenCore(TimeSpan timeout) 
     { 
      return new X509SecurityToken(clientCert); 
     } 
    } 

    public class CustomTokenSerializer : WSSecurityTokenSerializer 
    { 
     public CustomTokenSerializer(SecurityVersion sv) : base(sv) { } 

     protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token) 
     { 
      if (writer == null) 
      { 
       throw new ArgumentNullException("writer"); 
      } 
      if (token == null) 
      { 
       throw new ArgumentNullException("token"); 
      } 

      if (token.GetType() == new UserNameSecurityToken("x", "y").GetType()) 
      { 
       UserNameSecurityToken userToken = token as UserNameSecurityToken; 

       if (userToken == null) 
       { 
        throw new ArgumentNullException("userToken: " + token.ToString()); 
       } 

       string tokennamespace = "o"; 

       DateTime created = DateTime.Now; 
       string createdStr = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ"); 
       string phrase = Guid.NewGuid().ToString(); 
       string nonce = GetSHA1String(phrase); 
       string password = GetSHA1String(nonce + createdStr + userToken.Password); 
       //string password = userToken.Password; 

       writer.WriteStartElement(tokennamespace, "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
       writer.WriteAttributeString("u", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", token.Id); 
       writer.WriteElementString(tokennamespace, "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", userToken.UserName); 
       writer.WriteStartElement(tokennamespace, "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
       writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"); 
       writer.WriteValue(password); 
       writer.WriteEndElement(); 
       writer.WriteStartElement(tokennamespace, "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
       writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"); 
       writer.WriteValue(nonce); 
       writer.WriteEndElement(); 
       writer.WriteElementString(tokennamespace, "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", createdStr); 
       writer.WriteEndElement(); 
       writer.Flush(); 
      } 
      else 
      { 
       base.WriteTokenCore(writer, token); 
      } 
     } 

     protected string GetSHA1String(string phrase) 
     { 
      SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider(); 
      byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase)); 
      return Convert.ToBase64String(hashedDataBytes); 
     } 
    }//CustomTokenSerializer 
} 

Chúc may mắn!

2

Tôi đã xem xét mã của bạn và có vẻ chính xác. Có sự khác biệt nhỏ trong thông điệp xà phòng WSE và WCF nhưng sự khác biệt chỉ là cách chứng chỉ được sử dụng để ký thông điệp được tham chiếu.

Tôi nghĩ rằng vấn đề cốt lõi ở đây là sử dụng sai chứng chỉ. Bạn đang sử dụng cả giao thông và bảo mật lẫn nhau tin nhắn. Về lý thuyết, điều này đòi hỏi bốn chứng chỉ. Bạn cần

  • Chứng chỉ dịch vụ cho bảo mật giao thông - chứng chỉ này được máy chủ sử dụng để tạo kết nối SSL. Để xây dựng thành công máy khách kết nối phải tin tưởng chứng chỉ (bạn cần phải tin cậy thẩm quyền đã cấp chứng chỉ hoặc chứng chỉ máy chủ phải được đặt trong kho lưu trữ người đáng tin cậy của bạn).
  • Chứng chỉ khách hàng về bảo mật giao thông - chứng chỉ này được sử dụng để xác thực ứng dụng khách trên máy chủ ở cấp độ vận chuyển - bạn phải có chứng chỉ và khóa cá nhân của mình trong cửa hàng cá nhân của bạn
  • Chứng chỉ dịch vụ bảo mật thư - chứng chỉ này được sử dụng để mã hóa yêu cầu và ký trả lời (khi sử dụng WS-Security 1.0) được sử dụng. Bạn cần có chứng chỉ này ở đâu đó trên máy của bạn (tùy thuộc vào bạn sẽ sử dụng vị trí nào để tải chứng chỉ).
  • Chứng chỉ ứng dụng khách cho bảo mật thư - chứng chỉ này được sử dụng để mã hóa phản hồi và yêu cầu ký (khi sử dụng WS-Security 1.0). Bạn cần có chứng chỉ này và khóa riêng của nó ở đâu đó trên máy của bạn (tùy thuộc vào bạn sẽ sử dụng vị trí nào để tải chứng chỉ).

Có vẻ như bạn chỉ có hai chứng chỉ - một máy khách và một máy chủ. Trong trường hợp này, có lẽ chúng nên được sử dụng cho cả bảo mật và truyền tải. Nhưng ở đây có vấn đề thú vị - chứng chỉ "ký tên" của bạn ở phía máy khách trong ví dụ WSE thực sự là chứng chỉ dịch vụ. Nếu nó thực sự là trường hợp, nó có nghĩa là khách hàng phải có quyền truy cập vào khóa riêng của máy chủ - điều đó sẽ không bao giờ xảy ra. Đó là sự vi phạm tồi tệ nhất của cơ sở hạ tầng PKI. Cơ sở hạ tầng PKI dựa trên sự tin tưởng vào các cơ quan cấp chứng chỉ và về việc bảo mật các khóa cá nhân mà mỗi người tham gia có khóa riêng của nó không thể truy cập được bởi bất kỳ ai khác. Chia sẻ các khóa riêng sẽ giảm tính bảo mật. Trong trường hợp xấu nhất, nó có thể là không có an ninh ở tất cả bởi vì bất cứ ai có quyền truy cập vào khóa riêng có thể chặn các thông tin liên lạc hoặc chữ ký giả trên tin nhắn.

Nếu tôi đúng, bạn nên sử dụng WSE 3.0 và hài lòng với điều đó. Chỉ cần buộc WCF sử dụng chứng chỉ ứng dụng khách khác nhau cho HTTPS và bảo mật thư có thể khá khó khăn. Bạn có một thuộc tính ClientCertificate duy nhất nhưng bạn cần tải chứng chỉ khác nhau cho HTTPS và bảo mật thư. Nó đòi hỏi phải tạo ra tùy chỉnh ClientCredentials với hai thuộc tính và tùy chỉnh SecurityTokenManager để trả lại nhà cung cấp chứng chỉ chính xác (bằng cách thực hiện cho mỗi cách sử dụng (đó là một lý thuyết - tôi chưa bao giờ thử dùng nó). rằng dịch vụ của bạn được hiển thị trên một số DNS và nếu chủ đề trong chứng chỉ dịch vụ (trong trường hợp của bạn cũng ký chứng chỉ) khác nhau, bạn phải tạo một bản sắc DNS mới cho điểm cuối của bạn. được cấp cùng với tên đối tượng DNS được sử dụng để truy cập vào máy chủ

+0

Cảm ơn bạn đã phản hồi và hỗ trợ với Ladislav này. Vấn đề của tôi đã được giải quyết. Tôi không chắc những gì đã giải quyết nó. Tôi tìm thấy bên dưới trên trang web của IBM và đưa nó lên với nhóm cơ sở hạ tầng cổng CNTT của chúng tôi. Họ nói không có thay đổi nào được thực hiện cho DataPower, nhưng nó bắt đầu làm việc sáng nay !!! Tôi sẽ trả lời câu hỏi với mã làm việc cùng với lớp CustomCredential mà tôi đặt lại với nhau. Cảm ơn! – Jawad

+0

IBM: https://publib.boulder.ibm.com/infocenter/ieduasst/v1r1m0/index.jsp?topic=/com.ibm.iea.wdatapower/wdatapower/1.0/xa35/380DataPowerWCFIntegration/player.html Khi nào sử dụng BasicHttpBinding với SSL: Bạn có thể sử dụng tham số check-ssl-cipher-check để vô hiệu hoá kiểm tra mật mã cho bất kỳ xác nhận TransportBinding nào. Tiêu đề xác thực cơ bản không được hỗ trợ theo mặc định trong proxy dịch vụ web. Một cấu hình tùy chỉnh của một quy tắc trên-lỗi để chèn tiêu đề WWW-Authenticate là cần thiết để liên kết với WCF. – Jawad

Các vấn đề liên quan