Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

the most efficient way to secure WCF NetHttpBinding

I am going to implement a web service which is working under NetHttpBindingto support duplex connection. But the problem is I don't know how to secure it. I've tried to use CostumUserNamePasswordValidationMode, this is my web.config:

<behaviors>
      <serviceBehaviors>
        <behavior name="Behavior1">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate findValue="MyWebSite"
                  storeLocation="LocalMachine"
                  storeName="My"
                  x509FindType="FindBySubjectName" />
            <userNameAuthentication userNamePasswordValidationMode="Custom"
             customUserNamePasswordValidatorType="WcfWSChat.UserNamePassValidator, WcfWSChat" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netHttpBinding>
        <binding name="Binding1">
          <security mode="Message">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </netHttpBinding>
    </bindings>
    <protocolMapping>
      <add scheme="http" binding="netHttpBinding"/>
    </protocolMapping>
    <services>
      <service name="WcfWSChat.WSChatService" 
               behaviorConfiguration="Behavior1" >
        <endpoint address="" 
                  binding="netHttpBinding"
                  bindingConfiguration="Binding1"
                  contract="WcfWSChat.IWSChatService" />
        <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
      </service>
    </services>

I think the problem is <security mode="Message">, whenever I run the project, whether on IIS Express or IIS 8.0, I will get this error:

Could not find a base address that matches scheme https for the endpoint with binding NetHttpBinding. Registered base address schemes are [http].

If I change mode property to None, I won't see the error anymore but the validation is not working!

How can I solve this problem?

like image 323
Saman Gholami Avatar asked Aug 05 '15 18:08

Saman Gholami


1 Answers

I think you are almost near to the solution. I tried to replicate your problem and this is how I came up.

  1. Add and set httpsGetEnabled to true in your ServiceMetadata. MetaData exchange will happen in HTTPS :

<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />

  1. Change mexHttpBinding to mexHttpsBinding :

<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>

  1. In your binding add this :
<netHttpBinding>
   <binding name="netHttpBinding">
       <security mode="TransportWithMessageCredential">
           <message clientCredentialType="UserName"/>
       </security>
   </binding>
</netHttpBinding>
  1. Since netHttpBinding used http by default, we need some mapping.
<protocolMapping>
    <add scheme="https" binding="netHttpBinding"/>
</protocolMapping>
  1. For some reason even I change the protocolMapping to use HTTPS for netHttpBinding I still getting an error that says "Could not find a base address that matches scheme https for the endpoint with binding NetHttpBinding. Registered base address schemes are [http].".

So what I did is, I added based address under my service like this :

<host>
    <baseAddresses>
       <add baseAddress="https://localhost/Services/"/>
    </baseAddresses>
</host>

You may escape step five if you didn't see any error message highlighted above. I just put it here in case.

Note : I installed my certificate in certificate store under Personal and the CA in trusted Root Certificate. This example is only working under the same machine since my certificate name is just localhost. By the way I used .Net framework 4.5 here.

Below is my complete configuration :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="ServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="https://localhost/Services/"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netHttpBinding"  bindingConfiguration="netHttpBinding" contract="WcfServiceLibrary1.IService1" name="WcfServiceLibrary1.IService1"/>
        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" listenUriMode="Explicit" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors >
        <behavior name="ServiceBehavior">
          <serviceCredentials>
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            **<!-- Retain your custom username password validator here -->**
          </serviceCredentials>
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netHttpBinding>
        <binding name="netHttpBinding">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </netHttpBinding>
    </bindings>
    <protocolMapping>
      <add scheme="https" binding="netHttpBinding"/>
    </protocolMapping>
  </system.serviceModel>
</configuration>
like image 191
jtabuloc Avatar answered Oct 22 '22 03:10

jtabuloc