Saman Gholami
Saman Gholami

Reputation: 3502

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?

Upvotes: 12

Views: 2002

Answers (2)

jtabuloc
jtabuloc

Reputation: 2535

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>

Upvotes: 6

Brad
Brad

Reputation: 84

Seems like it might have something to do with the certificate you have registered as a service credential.

I'd try removing the serviceCertificate from the serviceBehaviours.

If you want to enforce SSL via that certificate then I would update your security mode in the binding section to TransportWithMessageCredential and change your protocol mapping scheme to https.

Upvotes: 0

Related Questions