2009-05-30 19 views
6

को अनदेखा कर रहा है। मैं अपनी परियोजना के लिए डब्ल्यूसीएफ सुरक्षा काम करने की कोशिश कर रहा हूं, और मुझे बहुत कम भाग्य मिला है। मैं एक ऐसी सेवा बनाने की कोशिश कर रहा हूं जो बाध्यकारी के रूप में net.tcp का उपयोग करता है, और संदेश और परिवहन दोनों सुरक्षा करता है। उपयोगकर्ता नाम और पासवर्ड का उपयोग करके संदेश सुरक्षा की जाती है और सर्टिफिकेट का उपयोग करके परिवहन सुरक्षा (माना जाता है!) किया जाता है।सर्टिफिकेट का उपयोग कर डब्ल्यूसीएफ ट्रांसपोर्ट सिक्योरिटी चेन ट्रस्ट

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

तब मैंने क्लाइंट ऐप को कॉन्फ़िगर किया जो अमान्य अविश्वसनीय प्रमाणपत्र का उपयोग अपने क्लाइंट प्रमाणपत्र के रूप में करने के लिए सेवा से कनेक्ट करता है। सेवा चेन ट्रस्ट का उपयोग कर क्लाइंट प्रमाणपत्रों की जांच करने के लिए (माना जाता है) सेट है। हालांकि, यह ग्राहक कनेक्ट करने और सेवा से सफलतापूर्वक बात करने में सक्षम है! इसे खारिज किया जाना चाहिए, क्योंकि इसका प्रमाणपत्र अविश्वसनीय है!

मुझे नहीं पता कि यह व्यवहार क्या कर रहा है, इसलिए मैं आपको यह देखने के लिए समस्या देता हूं कि आप इसे क्या बनाते हैं। यहाँ मेरी WCF विन्यास हैं:

सेवा conf:

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="DHTestBehaviour" name="DigitallyCreated.DHTest.Business.DHTestBusinessService"> 
      <endpoint address="" binding="netTcpBinding" contract="DigitallyCreated.DHTest.Business.IDHTestBusinessService" bindingConfiguration="DHTestNetTcpBinding" bindingNamespace="http://www.digitallycreated.net/DHTest/v1" /> 

      <host> 
       <baseAddresses> 
        <add baseAddress="net.tcp://localhost:8090/"/> 
        <add baseAddress="http://localhost:8091/"/> 
       </baseAddresses> 
      </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
      <behavior name="DHTestBehaviour"> 
       <serviceMetadata httpGetEnabled="true"/> 
       <serviceDebug includeExceptionDetailInFaults="true"/> 
       <serviceCredentials> 
        <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="DHTestMembershipProvider"/> 
        <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" findValue="CN=business.dhtestDHTest.com" /> 
        <clientCertificate> 
         <authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" revocationMode="NoCheck" /> 
        </clientCertificate> 
       </serviceCredentials> 
       <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="DHTestRoleProvider" /> 
      </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <netTcpBinding> 
      <binding name="DHTestNetTcpBinding"> 
       <security mode="TransportWithMessageCredential"> 
        <message clientCredentialType="UserName"/> 
        <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign"/> 
       </security> 
      </binding> 
     </netTcpBinding> 
    </bindings> 
</system.serviceModel> 

ग्राहक सम्मेलन:

<system.serviceModel> 
    <bindings> 
     <netTcpBinding> 
      <binding name="NetTcpBinding_IDHTestBusinessService" closeTimeout="00:01:00" 
      openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
      transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" 
      hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" 
      maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> 
       <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
       maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
       <reliableSession ordered="true" inactivityTimeout="00:10:00" 
       enabled="false" /> 
       <security mode="TransportWithMessageCredential"> 
        <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" /> 
        <message clientCredentialType="UserName" /> 
       </security> 
      </binding> 
     </netTcpBinding> 
    </bindings> 
    <behaviors> 
     <endpointBehaviors> 
      <behavior name="DHTestBusinessServiceEndpointConf"> 
       <clientCredentials> 
        <clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" findValue="CN=invalid"/> 
        <serviceCertificate> 
         <authentication revocationMode="NoCheck" trustedStoreLocation="LocalMachine"/> 
        </serviceCertificate> 
       </clientCredentials> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    <client> 
     <endpoint address="net.tcp://phoenix-iv:8090/" binding="netTcpBinding" 
     behaviorConfiguration="DHTestBusinessServiceEndpointConf" 
     bindingConfiguration="NetTcpBinding_IDHTestBusinessService" 
     contract="DHTest.NetTcp.Business.IDHTestBusinessService" 
     name="NetTcpBinding_IDHTestBusinessService"> 
      <identity> 
       <dns value="business.dhtest.com" /> 
      </identity> 
     </endpoint> 
    </client> 
</system.serviceModel> 

ग्राहक उपयोगकर्ता नाम/पासवर्ड प्राधिकरण कोड:

DHTestBusinessServiceClient client = new DHTestBusinessServiceClient(); 
client.ClientCredentials.UserName.UserName = "ratfink"; 
client.ClientCredentials.UserName.Password = "testpassword"; 

धन्यवाद y अग्रिम में आपकी मदद के लिए कहां।

संपादित करें (2009/06/01):

मेरे दोस्तों में से एक ने मुझे a blog कि ऐसा क्यों हो रहा है के रूप में सवाल का जवाब की ओर इशारा किया। जाहिर है, जब आप TransportWithMessageCredential निर्दिष्ट करते हैं तो इसका अर्थ है बिल्कुल कि: संदेश प्रमाण पत्र केवल के साथ परिवहन। यही कारण है कि मेरे प्रमाण पत्र परिवहन स्तर पर नजरअंदाज कर रहे हैं।

हालांकि, मैं इस मुद्दे को पूर्ण और बंद नहीं मानता, क्योंकि मैं अभी भी ऐसा करना चाहता हूं। :) मैं कस्टम प्रमाणपत्र सत्यापनकर्ताओं को देखने जा रहा हूं जो मुझे लगता है कि मैं प्लग इन कर सकता हूं और देख सकता हूं कि यह काम करता है या नहीं। मैं परिणामों के साथ आप सभी को वापस मिल जाएगा।

संपादित करें (2009/06/08):

नहीं, कस्टम प्रमाणपत्र प्रमाणकों या तो काम नहीं करते। डब्ल्यूसीएफ बस उन्हें फोन नहीं करता है।

उत्तर

4

मुझे मेरी समस्या का समाधान मिला, हालांकि, यह अपेक्षा की तुलना में बहुत नास्टियर बन गया।

असल में, परिवहन और संदेश दोनों प्रमाण पत्र जांचने के लिए आपको एक कस्टम बाध्यकारी परिभाषित करने की आवश्यकता है। (मुझे इस प्रभाव here पर जानकारी मिली)।

मुझे ऐसा करने का सबसे आसान तरीका एक्सएमएल में अपनी कॉन्फ़िगरेशन जारी रखना है, लेकिन रनटाइम प्रतिलिपि पर और एक्सएमएल कॉन्फ़िगरेशन से नेटटीसीपी बाइंडिंग को थोड़ा संशोधित करें। सचमुच एक स्विच है जिसे आपको सक्षम करने की आवश्यकता है। यहाँ सेवा पक्ष पर और क्लाइंट साइड पर कोड है:

सेवा साइड

ServiceHost businessHost = new ServiceHost(typeof(DHTestBusinessService)); 
ServiceEndpoint endpoint = businessHost.Description.Endpoints[0]; 
BindingElementCollection bindingElements = endpoint.Binding.CreateBindingElements(); 
SslStreamSecurityBindingElement sslElement = bindingElements.Find<SslStreamSecurityBindingElement>(); 
sslElement.RequireClientCertificate = true; //Turn on client certificate validation 
CustomBinding newBinding = new CustomBinding(bindingElements); 
NetTcpBinding oldBinding = (NetTcpBinding)endpoint.Binding; 
newBinding.Namespace = oldBinding.Namespace; 
endpoint.Binding = newBinding; 

क्लाइंट साइड

DHTestBusinessServiceClient client = new DHTestBusinessServiceClient(); 
ServiceEndpoint endpoint = client.Endpoint; 
BindingElementCollection bindingElements = endpoint.Binding.CreateBindingElements(); 
SslStreamSecurityBindingElement sslElement = bindingElements.Find<SslStreamSecurityBindingElement>(); 
sslElement.RequireClientCertificate = true; //Turn on client certificate validation 
CustomBinding newBinding = new CustomBinding(bindingElements); 
NetTcpBinding oldBinding = (NetTcpBinding)endpoint.Binding; 
newBinding.Namespace = oldBinding.Namespace; 
endpoint.Binding = newBinding; 

आपको लगता है कि यह है कि यह हो जाएगा चाहते हैं लेकिन तुम गलत हो! :) यह वह जगह है जहां यह अतिरिक्त लंगड़ा हो जाता है। मैं PrincipalPermission के साथ अपने ठोस सेवा तरीकों का श्रेय प्रदान किया गया था इस तरह सेवा उपयोगकर्ता की भूमिका के आधार पर उपयोग को सीमित करने के लिए:

[PrincipalPermission(SecurityAction.Demand, Role = "StandardUser")] 

यह जैसे ही मैं ऊपर परिवर्तन लागू नाकाम रहने शुरू कर दिया। इसका कारण यह था कि

OperationContext.Current.ServiceSecurityContext.PrimaryIdentity 

अज्ञात, उपयोगकर्ता नाम-रहित, अनधिकृत IIDentity होने का अंत हो रहा था। ऐसा इसलिए था क्योंकि वास्तव में दो उपयोगकर्ता का प्रतिनिधित्व करने वाली पहचानें हैं: X509 प्रमाण पत्र के लिए एक परिवहन पर प्रमाणीकरण के लिए उपयोग किया जाता है, और उपयोगकर्ता स्तर और पासवर्ड प्रमाण-पत्रों के लिए एक संदेश स्तर पर प्रमाणित करने के लिए उपयोग किया जाता है। जब मैंने डब्लूसीएफ बाइनरी को इंजीनियर किया, यह देखने के लिए कि यह मुझे मेरी प्राथमिकता क्यों नहीं दे रहा था, मैंने पाया कि इसमें कोड की एक स्पष्ट रेखा है जो इसे उस खाली IIDentity को वापस करने का कारण बनती है यदि उसे एक से अधिक IIdentity मिलती है। मुझे लगता है कि ऐसा इसलिए है क्योंकि यह पता लगाने का कोई तरीका नहीं है कि कौन सा प्राथमिक एक है।

इसका मतलब है प्रिंसिपलप्रमिशन विशेषता का उपयोग खिड़की से बाहर है। इसके बजाय, मैं एक विधि ने लिखा है कि कर सकते हैं कई IIdentities साथ सौदा अपनी कार्यक्षमता की नकल करने की:

private void AssertPermissions(IEnumerable<string> rolesDemanded) 
{ 
    IList<IIdentity> identities = OperationContext.Current.ServiceSecurityContext.AuthorizationContext.Properties["Identities"] as IList<IIdentity>; 
    if (identities == null) 
     throw new SecurityException("Unauthenticated access. No identities provided."); 

    foreach (IIdentity identity in identities) 
    { 
     if (identity.IsAuthenticated == false) 
      throw new SecurityException("Unauthenticated identity: " + identity.Name); 
    } 

    IIdentity usernameIdentity = identities.Where(id => id.GetType().Equals(typeof(GenericIdentity))).SingleOrDefault(); 
    string[] userRoles = Roles.GetRolesForUser(usernameIdentity.Name); 

    foreach (string demandedRole in rolesDemanded) 
    { 
     if (userRoles.Contains(demandedRole) == false) 
      throw new SecurityException("Access denied: authorisation failure."); 
    } 
} 

यह बहुत नहीं (विशेष रूप से जिस तरह से मैं उपयोगकर्ता नाम/पासवर्ड क्रेडेंशियल IIdentity का पता लगाने), लेकिन यह काम करता है है! अब, मेरी सेवा तरीकों के शीर्ष पर मैं इसे इस तरह कॉल करने की आवश्यकता:

AssertPermissions(new [] {"StandardUser"}); 
+1

+1 मैं जानता हूँ कि यह पुरानी लेकिन अच्छी तरह से किया है, यह मेरे समाधान की तुलना में बेहतर लग रहा है (या मैं इसे हैक बुलाना चाहिए) यहाँ: http://stackoverflow.com/questions/9111361/wcf-service-with-wshttpbinding-manipulating-http-request-headers –

0

Codeplex - Intranet Section देखें जो विभिन्न परिदृश्यों के लिए चेकलिस्ट प्रदान करता है। उल्लेख करने की दूसरी बात यह है कि आईआईटी 5.0 और आईआईएस 6.0 के भीतर नेट टीसीपी बाइंडिंग का उपयोग करने के लिए समर्थित नहीं है - 3rd paragraph here देखें, केवल आईआईएस 7.0 +।

संबंधित मुद्दे

 संबंधित मुद्दे