2010-03-09 23 views
12

मेरी टीम तीसरे पक्ष के मोटी क्लाइंट एप्लिकेशन के लिए कई WPF प्लग-इन विकसित कर रही है। डब्ल्यूपीएफ प्लग-इन कई टीआईबीसीओ सेवाओं द्वारा प्रकाशित वेब सेवाओं का उपभोग करने के लिए डब्ल्यूसीएफ का उपयोग करते हैं। मोटी क्लाइंट एप्लिकेशन एक अलग केंद्रीय डेटा स्टोर रखता है और डेटा स्टोर तक पहुंचने के लिए एक मालिकाना एपीआई का उपयोग करता है। मोटी क्लाइंट और डब्ल्यूपीएफ प्लग-इन 10,000 वर्कस्टेशन पर तैनात किए जाने के कारण हैं। हमारा ग्राहक केंद्रीय डेटा स्टोर में मोटी क्लाइंट द्वारा उपयोग किए जाने वाले प्रमाण पत्र को रखना चाहता है ताकि उन्हें प्रमाणपत्र जारी करने के बारे में चिंता करने की आवश्यकता न हो (वर्तमान पुन: जारी चक्र में लगभग 3 महीने लगते हैं) और उन्हें अधिकृत करने का अवसर भी है प्रमाण पत्र का उपयोग। प्रस्तावित वास्तुकला केंद्रीय डेटा स्टोर और टीआईबीसीओ सेवाओं के बीच साझा गुप्त/प्रमाणीकरण का एक रूप प्रदान करता है।सर्टिफिकेट स्टोर के बिना डब्ल्यूसीएफ सर्टिफिकेट

जबकि मैं प्रस्तावित आर्किटेक्चर के साथ जरूरी नहीं हूं, हमारी टीम इसे बदलने में सक्षम नहीं है और प्रदान की गई चीज़ों के साथ काम करना चाहिए।

असल में हमारा ग्राहक चाहता है कि हम अपने डब्ल्यूपीएफ प्लग-इन को एक तंत्र में बनाना चाहते हैं जो केंद्रीय डेटा स्टोर (जिसे उस डेटा स्टोर में भूमिकाओं के आधार पर अनुमति दी जाएगी या अस्वीकार कर दिया जाएगा) से प्रमाण पत्र पुनर्प्राप्त करेगा, फिर प्रमाणपत्र के लिए प्रमाणपत्र का उपयोग करें टीआईबीसीओ सेवाओं के लिए एसएसएल कनेक्शन बनाना। स्थानीय मशीन के प्रमाणपत्र स्टोर का कोई उपयोग करने की अनुमति नहीं है और स्मृति सत्र में प्रत्येक सत्र के अंत में त्याग दिया जाना है।

तो सवाल यह है कि क्या किसी को पता है कि एसएसएल ट्रांसपोर्ट स्तर एन्क्रिप्शन के लिए डब्ल्यूसीएफ (.NET 3.5) सेवा में इन-मेमोरी प्रमाणपत्र पास करना संभव है?

नोट: मैंने एक समान प्रश्न (here) से पूछा था, लेकिन तब से इसे हटा दिया है और इसे अधिक जानकारी के साथ फिर से पूछा है।

उत्तर

13

यह संभव है। हम म्यूचुअल सर्टिफिकेट ऑथ के साथ कुछ करते हैं - सर्विस सर्टिफिकेट और कुछ मामलों में क्लाइंट सर्टिफिकेट को ऑटो-डिस्कवरी/सिंगल-साइन-ऑन मैकेनिज्म के हिस्से के रूप में केंद्रीय प्राधिकरण से उठाया जाता है।

यह पूरी तरह से स्पष्ट नहीं है कि प्रमाण पत्र का उपयोग किस संदर्भ में किया जाएगा, लेकिन सभी मामलों में आपको जो करना है वह System.ServiceModel.Description नामस्थान में विशेष व्यवहार/तत्व से प्राप्त अपने व्यवहार और व्यवहार तत्व को परिभाषित करता है जो प्रमाण पत्र लेता है। मैं उस समय के लिए मानता हूं कि यह एक ग्राहक प्रमाण पत्र है।

public class MyCredentialsExtensionElement : ClientCredentialsElement 
{ 
    protected override object CreateBehavior() 
    { 
     return new MyCredentials(); 
    } 

    public override Type BehaviorType 
    { 
     get { return typeof(MyCredentials); } 
    } 

    // Snip other overrides like Properties 
} 

इस के बाद आप नीति जोड़ सकते हैं:

public class MyCredentials : ClientCredentials 
{ 
    public override void ApplyClientBehavior(ServiceEndpoint endpoint, 
     ClientRuntime behavior) 
    { 
     // Assuming GetCertificateFromNetwork retrieves from CDS 
     ClientCertificate.Certificate = GetCertificateFromNetwork(); 
    } 

    protected override ClientCredentials CloneCore() 
    { 
     // ... 
    } 
} 

अब आप एक तत्व है कि XML विन्यास में जा सकते हैं बनाने की जरूरत: सबसे पहले आप व्यवहार में लिखने के लिए है, जो कुछ इस तरह चला जाता है है

<behaviors> 
    <endpointBehaviors> 
     <behavior name="MyEndpointBehavior"> 
      <myCredentials/> 
     </behavior> 
    </endpointBehaviors> 
</behaviors> 

संपादित करें:: अपने WCF config को

: लगभग उल्लेख करना भूल गया, तो आप विस्तार रजिस्टर करने की आवश्यकता
<system.serviceModel> 
    <extensions> 
     <behaviorExtensions> 
      <add name="myCredentials" 
       type="MyAssembly.MyCredentialsExtensionElement, MyAssembly, 
         Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
     </behaviorExtensions> 
    </extensions> 
</system.serviceModel> 

उम्मीद है कि मदद करता है। यदि आपको इन सभी कक्षाओं की व्यवस्था और दृश्यों के पीछे क्या चल रहा है, तो Extending WCF with Custom Behaviors पढ़ने का प्रयास करें।

+0

आप अपने सुझाव के लिए बहुत बहुत शुक्रिया ऊपर कोड मैं अपने क्लाइंट कॉन्फ़िगर करने में सक्षम था का उपयोग कर। मैं आपको बता दूंगा कि मैं कैसे चल रहा हूं। – Kane

+0

बहुत देर से पूछने के लिए खेद है। 'SetCertificate()' को कॉल करने के विरोध में सीधे क्लाइंट प्रमाणपत्र क्यों असाइन करें? क्या कोई अंतर है? – ashes999

+0

@ ashes999: उस विधि में अधिभार नहीं है जो वास्तविक 'X509 प्रमाण पत्र' लेता है। यह केवल तभी उपयोगी होता है जब आपका प्रमाणपत्र पहले से ही स्थानीय स्टोरों में से एक में है, जो स्पष्ट रूप से यहां मामला नहीं है। – Aaronaught

4

मैं वह व्यक्ति हूं जिसने केन (हमारे SO कमी!) को मूल प्रश्न पूछने के लिए मिला है। मैंने सोचा कि आखिर में हारूनॉट द्वारा पोस्ट किए गए उत्तर के संबंध में मैं एक खाता बनाउंगा और हमारे निष्कर्ष/परिणाम/अनुभव पोस्ट करूंगा (इसलिए उसे ऊपर कोई क्रेडिट)।

हमने ऊपर सुझाए गए अनुसार एक कस्टम व्यवहार जोड़ने की कोशिश की और व्यवहार का उपयोग करने के लिए एंडपॉइंट कॉन्फ़िगरेशन तत्व पर कॉन्फ़िगरेशन कॉन्फ़िगरेशन सेट किया। हम एक प्रोग्रामेटिक दृष्टिकोण के साथ चलने वाले कोड को इतनी देर तक नहीं पहुंचा सके।

चूंकि हमारे पास क्लाइंटबेस ऑब्जेक्ट बनाने के लिए एक रैपर वर्ग स्थापित किया गया था, हमने क्लाइंटबेस के अन्य सभी हिस्सों के निर्माण के बाद व्यवहार को जोड़ने के लिए हमारे मौजूदा निर्माण कार्यों का उपयोग किया था।

हम कुछ ऐसा करने में भी कुछ मुद्दों में भाग गए, अर्थात् क्लाइंटबेस के व्यवहार को हमारे प्रमाणपत्र + उपयोगकर्ता नाम और पासवर्ड के बजाय उपयोगकर्ता नाम और पासवर्ड के साथ प्रमाणित करने के लिए पहले से ही परिभाषित किया जा रहा था। इसलिए हमने परीक्षण के लिए एक अस्थायी उपाय के रूप में हमारे नए प्रमाण पत्र आधारित व्यवहार (उपयोगकर्ता नाम और पासवर्ड इंजेक्शन के साथ) जोड़ने से पहले मौजूदा व्यवहार को प्रोग्रामेटिक रूप से हटा दिया। अभी भी कोई पासा नहीं है, हमारे व्यवहार का निर्माण किया जा रहा था और लागू क्लाइंटबैवियर को निकाल दिया जा रहा था, लेकिन जब सेवा को बुलाया गया था तब भी सेवा खत्म हो रही थी (हमें उन अवधारणाओं का उपयोग करने के गुच्छा के कारण असली अपवाद नहीं मिला जो कि रिफैक्टर करना मुश्किल था)।

हमने फिर मौजूदा क्लाइंट क्रेडेंशियल व्यवहार को हटाने के बजाय निर्णय लिया कि हम पूरी प्रक्रिया को सामान्य रूप से सामान्य करने से पहले हमारे प्रमाणपत्र को इंजेक्ट करेंगे। तीसरा बार एक आकर्षण और यह सब खत्म हो गया है और अब काम कर रहा है।

मैं हारूनॉट को धन्यवाद देना चाहता हूं (और अगर मैं कर सकता हूं तो मैं वोट दूंगा!) हमें सही रास्ते पर डालने और एक अच्छा विचार और उपयोगी उत्तर प्रदान करने के लिए।

इसका एक छोटा कोड स्निपेट है और चल रहा है (एक परीक्षण सीआरटी फ़ाइल का उपयोग कर)।

 protected override ClientBase<TChannel> CreateClientBase(string endpointConfigurationName) 
    { 
     ClientBase<TChannel> clientBase = new ClientBase<TChannel>(endpointConfigurationName); // Construct yours however you want here 

     // ... 

     ClientCredentials credentials = clientBase.Endpoint.Behaviors.Find<ClientCredentials>(); 

     X509Certificate2 certificate = new X509Certificate2(); 
     byte[] rawCertificateData = File.ReadAllBytes(@"C:\Path\To\YourCert.crt"); 
     certificate.Import(rawCertificateData); 

     credentials.ClientCertificate.Certificate = certificate; 

     return clientBase; 
    } 

एक अन्य पक्ष नोट के रूप में, परीक्षण हम स्थानीय मशीन की दुकान से हमारे सभी प्रमाणपत्र हटाया के भाग के रूप, यह वास्तव में एक समस्या फ़िडलर का उपयोग कर का कारण बना। फिडलर ने हमारे क्लाइंट सर्टिफिकेट का पता नहीं लगाया क्योंकि यह पूरी तरह स्मृति में था और भरोसेमंद स्टोर में नहीं था। अगर हमने इसे विश्वसनीय स्टोर में वापस जोड़ा तो फिडलर ने फिर से अच्छा खेलना शुरू कर दिया।

फिर से धन्यवाद।

+0

उत्तर jules के लिए धन्यवाद :) – Kane

+0

हम्म, बहुत परेशान है कि आप चलाने के लिए व्यवहार नहीं मिल सका। क्या आप व्यवहार के साथ एंडपॉइंट को कॉन्फ़िगर करना भूल गए थे? वैसे भी, ऐसा लगता है कि आप लोगों को एक कामकाज मिला, तो सब ठीक है जो अच्छी तरह समाप्त होता है! – Aaronaught

+0

हाँ, हमने व्यवहार का उपयोग करने के लिए एंडपॉइंट कॉन्फ़िगर किया है लेकिन इसे प्रोग्रामेटिक रूप से जोड़ते समय इसे ट्रिगर करने के लिए ही प्राप्त किया जा सकता है। यह थोड़ा विचित्र था लेकिन हमने आगे नहीं बढ़े क्योंकि हमने दिशा में थोड़ा बदलाव किया था। –

0

हारून के पास सही विचार था, लेकिन मुझे इसे काम करने के लिए कुछ संशोधन करना पड़ा। मेरे द्वारा उपयोग किए जाने वाले कार्यान्वयन का पालन करता है। मैंने एम्बेडेड संसाधन से प्रमाण पत्र प्राप्त करने की क्षमता के साथ थोड़ा और जोड़ा।

using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Security.Cryptography.X509Certificates; 
using System.ServiceModel.Configuration; 
using System.Configuration; 
using System.ServiceModel.Description; 

namespace System.ServiceModel.Description 
{ 
    /// <summary> 
    /// Uses a X509 certificate from disk as credentials for the client. 
    /// </summary> 
    public class ClientCertificateCredentialsFromFile : ClientCredentials 
    { 
     public ClientCertificateCredentialsFromFile(CertificateSource certificateSource, string certificateLocation) 
     { 
      if (!Enum.IsDefined(typeof(CertificateSource), certificateSource)) { throw new ArgumentOutOfRangeException(nameof(certificateSource), $"{nameof(certificateSource)} contained an unexpected value."); } 
      if (string.IsNullOrWhiteSpace(certificateLocation)) { throw new ArgumentNullException(nameof(certificateLocation)); } 

      _certificateSource = certificateSource; 
      _certificateLocation = certificateLocation; 

      ClientCertificate.Certificate = certificateSource == CertificateSource.EmbeddedResource ? 
       GetCertificateFromEmbeddedResource(certificateLocation) 
       : GetCertificateFromDisk(certificateLocation); 
     } 

     /// <summary> 
     /// Retrieves a certificate from an embedded resource. 
     /// </summary> 
     /// <param name="certificateLocation">The certificate location and assembly information. Example: The.Namespace.certificate.cer, Assembly.Name</param> 
     /// <returns>A new instance of the embedded certificate.</returns> 
     private static X509Certificate2 GetCertificateFromEmbeddedResource(string certificateLocation) 
     { 
      X509Certificate2 result = null; 

      string[] parts = certificateLocation.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 
      if (parts.Length < 2) { throw new ArgumentException($"{certificateLocation} was expected to have a format of namespace.resource.extension, assemblyName"); } 
      string assemblyName = string.Join(",", parts.Skip(1)); 

      var assembly = Assembly.Load(assemblyName); 
      using (var stream = assembly.GetManifestResourceStream(parts[0])) 
      { 
       var bytes = new byte[stream.Length]; 
       stream.Read(bytes, 0, bytes.Length); 
       result = new X509Certificate2(bytes); 
      } 

      return result; 
     } 

     /// <summary> 
     /// Retrieves a certificate from disk. 
     /// </summary> 
     /// <param name="certificateLocation">The file path to the certificate.</param> 
     /// <returns>A new instance of the certificate from disk</returns> 
     private static X509Certificate2 GetCertificateFromDisk(string certificateLocation) 
     { 
      if (!File.Exists(certificateLocation)) { throw new ArgumentException($"File {certificateLocation} not found."); } 
      return new X509Certificate2(certificateLocation); 
     } 


     /// <summary> 
     /// Used to keep track of the source of the certificate. This is needed when this object is cloned. 
     /// </summary> 
     private readonly CertificateSource _certificateSource; 

     /// <summary> 
     /// Used to keep track of the location of the certificate. This is needed when this object is cloned. 
     /// </summary> 
     private readonly string _certificateLocation; 

     /// <summary> 
     /// Creates a duplicate instance of this object. 
     /// </summary> 
     /// <remarks> 
     /// A new instance of the certificate is created.</remarks> 
     /// <returns>A new instance of <see cref="ClientCertificateCredentialsFromFile"/></returns> 
     protected override ClientCredentials CloneCore() 
     { 
      return new ClientCertificateCredentialsFromFile(_certificateSource, _certificateLocation); 
     } 
    } 
} 


namespace System.ServiceModel.Configuration 
{ 
    /// <summary> 
    /// Configuration element for <see cref="ClientCertificateCredentialsFromFile"/> 
    /// </summary> 
    /// <remarks> 
    /// When configuring the behavior an extension has to be registered first. 
    /// <code> 
    /// <![CDATA[ 
    /// <extensions> 
    ///  <behaviorExtensions> 
    ///   <add name = "clientCertificateCredentialsFromFile" 
    ///    type="System.ServiceModel.Configuration.ClientCertificateCredentialsFromFileElement, Assembly.Name" /> 
    ///  </behaviorExtensions> 
    /// </extensions> 
    /// ]]> 
    /// </code> 
    /// Once the behavior is registered it can be used as follows. 
    /// <code> 
    /// <![CDATA[ 
    /// <behaviors> 
    ///  <endpointBehaviors> 
    ///   <behavior name = "BehaviorConfigurationName" > 
    ///    <clientCertificateCredentialsFromFile fileLocation="C:\certificates\paypal_cert.cer" /> 
    ///   </behavior> 
    ///  </endpointBehaviors> 
    /// </behaviors> 
    /// <client> 
    ///  <endpoint address="https://endpoint.domain.com/path/" behaviorConfiguration="BehaviorConfigurationName" ... /> 
    /// </client> 
    /// ]]> 
    /// </code> 
    /// </remarks> 
    public class ClientCertificateCredentialsFromFileElement : BehaviorExtensionElement 
    { 
     /// <summary> 
     /// Creates a new <see cref="ClientCertificateCredentialsFromFile"/> from this configuration element. 
     /// </summary> 
     /// <returns>The newly configured <see cref="ClientCertificateCredentialsFromFile"/></returns> 
     protected override object CreateBehavior() 
     { 
      return new ClientCertificateCredentialsFromFile(Source, Location); 
     } 

     /// <summary> 
     /// Returns <code>typeof(<see cref="ClientCertificateCredentialsFromFile"/>);</code> 
     /// </summary> 
     public override Type BehaviorType 
     { 
      get 
      { 
       return typeof(ClientCertificateCredentialsFromFile); 
      } 
     } 

     /// <summary> 
     /// An attribute used to configure the file location of the certificate to use for the client's credentials. 
     /// </summary> 
     [ConfigurationProperty("location", IsRequired = true)] 
     public string Location 
     { 
      get 
      { 
       return this["location"] as string; 
      } 
      set 
      { 
       this["location"] = value; 
      } 
     } 

     /// <summary> 
     /// An attribute used to configure where the certificate should should be loaded from. 
     /// </summary> 
     [ConfigurationProperty("source", IsRequired = true)] 
     public CertificateSource Source 
     { 
      get 
      { 
       return (CertificateSource)this["source"]; 
      } 
      set 
      { 
       this["source"] = value; 
      } 
     } 
    } 

    /// <summary> 
    /// Used to declare the source of a certificate. 
    /// </summary> 
    public enum CertificateSource 
    { 
     FileOnDisk, 
     EmbeddedResource 
    } 
} 

के रूप में इस प्रकार है

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <system.serviceModel> 
     <extensions> 
      <behaviorExtensions> 
       <add name="clientCertificateCredentialsFromFile" 
        type="System.ServiceModel.Configuration.ClientCertificateCredentialsFromFileElement, My.Project.PayPal" /> 
      </behaviorExtensions> 
     </extensions> 

     <bindings> 
      <basicHttpBinding> 
       <binding name="PayPalAPISoapBinding"> 
        <security mode="Transport"> 
         <transport clientCredentialType="Certificate" /> 
        </security> 
       </binding> 
       <binding name="PayPalAPIAASoapBinding"> 
        <security mode="Transport"> 
         <transport clientCredentialType="Certificate" /> 
        </security> 
       </binding> 
      </basicHttpBinding> 
     </bindings> 
     <behaviors> 
      <endpointBehaviors> 
       <behavior name="PayPalAPICredentialBehavior"> 
        <clientCertificateCredentialsFromFile source="EmbeddedResource" location="My.Project.PayPal.Test.Integration.paypal_cert.cer, My.Project.PayPal.Test.Integration" /> 
       </behavior> 
       <behavior name="PayPalAPIAACredentialBehavior"> 
        <clientCertificateCredentialsFromFile source="EmbeddedResource" location="My.Project.PayPal.Test.Integration.paypal_cert.cer, My.Project.PayPal.Test.Integration" /> 
       </behavior> 
      </endpointBehaviors> 
     </behaviors> 
     <client> 
      <endpoint 
       address="https://api.sandbox.paypal.com/2.0/" 
       behaviorConfiguration="PayPalAPICredentialBehavior" 
       binding="basicHttpBinding" 
       bindingConfiguration="PayPalAPISoapBinding" 
       contract="My.Project.PayPal.Proxy.PayPalAPIInterface" 
       name="PayPalAPI" /> 
      <endpoint 
       address="https://api-aa.sandbox.paypal.com/2.0/" 
       behaviorConfiguration="PayPalAPIAACredentialBehavior" 
       binding="basicHttpBinding" 
       bindingConfiguration="PayPalAPIAASoapBinding" 
       contract="My.Project.PayPal.Proxy.PayPalAPIAAInterface" 
       name="PayPalAPIAA" /> 
     </client> 
    </system.serviceModel> 
</configuration> 
संबंधित मुद्दे