WCF: wsHttpBinding with Windows Authentication.

How to configure wsHttpBinding with Windows Authentication:

 

Here is a simple service configured on IIS with windows authentication. When using wsHttpBinding, the security mode must be “Transport” for Windows Authentication on IIS to be used. Also the website needs to have a server certificate configured.

 

If you use any other security mode you will receive the following error message.

Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.

 

If you are receiving the following error message, make sure the website bindings are configured for https.

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

 

Filename: Service.svc

<%@ ServiceHost Language="VB" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.vb" %>

Filename: IService.vb

' NOTE: If you change the interface name "IService" here, you must also update the reference to "IService" in Web.config.

<ServiceContract()> _

Public Interface IService

    <OperationContract()> _

    Function GetData(ByVal value As Integer) As String

    <OperationContract()> _

    Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType

    ' TODO: Add your service operations here

End Interface

' Use a data contract as illustrated in the sample below to add composite types to service operations.

<DataContract()> _

Public Class CompositeType

    Private boolValueField As Boolean

    Private stringValueField As String

    <DataMember()> _

    Public Property BoolValue() As Boolean

        Get

            Return Me.boolValueField

        End Get

        Set(ByVal value As Boolean)

            Me.boolValueField = value

        End Set

    End Property

    <DataMember()> _

    Public Property StringValue() As String

        Get

            Return Me.stringValueField

        End Get

        Set(ByVal value As String)

            Me.stringValueField = value

        End Set

    End Property

End Class

 

Filename: Service.vb

' NOTE: If you change the class name "Service" here, you must also update the reference to "Service" in Web.config and in the associated .svc file.

Public Class Service

    Implements IService

    Public Sub New()

    End Sub

    Public Function GetData(ByVal value As Integer) As String Implements IService.GetData

        Return String.Format("You entered: {0}", value)

    End Function

    Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IService.GetDataUsingDataContract

        If composite.BoolValue Then

            composite.StringValue = (composite.StringValue & "Suffix")

        End If

        Return composite

    End Function

End Class

Filename: web.config

<!—The system.serviceModel section can be replaced with the following -->

<system.serviceModel>

  <bindings>

    <wsHttpBinding>

      <binding name="NewBinding0">

<!-- When using wsHttpBinding, the security mode must be “Transport” for Windows Authentication on IIS to be used. Also the website needs to have a server certificate configured. -->

        <security mode="Transport">

         <transport clientCredentialType="Windows"/>

        </security>

      </binding>

    </wsHttpBinding>

  </bindings>

  <services>

    <service behaviorConfiguration="ServiceBehavior" name="Service">

      <endpoint binding="wsHttpBinding" bindingConfiguration="NewBinding0"

        contract="IService" />

    </service>

  </services>

  <behaviors>

    <serviceBehaviors>

      <behavior name="ServiceBehavior">

        <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->

        <serviceMetadata httpGetEnabled="true"/>

        <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->

        <serviceDebug includeExceptionDetailInFaults="false"/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

</system.serviceModel>

 

Filename: Client.vb

‘You might receive errors relating to the server certificate when the name on the server certificate does not match the name used in the application endpoint address.

Could not establish trust relationship for the SSL/TLS secure channel with authority 'myIISServer.myDomain.com'.

Make sure you are adding the RemoteCertValidate method and declare the ServerCertificateValidationCallback delegate. C# version of the client is added below for reference.

Imports System.Security.Cryptography.X509Certificates

Module Module1

    Sub Main()

        System.Net.ServicePointManager.ServerCertificateValidationCallback = DirectCast([Delegate].Combine(System.Net.ServicePointManager.ServerCertificateValidationCallback, New System.Net.Security.RemoteCertificateValidationCallback(AddressOf RemoteCertValidate)), System.Net.Security.RemoteCertificateValidationCallback)

        Dim client As New ServiceReference1.ServiceClient()

        Console.WriteLine(client.GetData(10))

        client.Close()

        Console.ReadLine()

    End Sub

    Function RemoteCertValidate(ByVal sender As Object, ByVal cert As X509Certificate, ByVal chain As X509Chain, ByVal error1 As System.Net.Security.SslPolicyErrors) As Boolean

        Return True

    End Function

End Module

Filename: Client.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Security.Cryptography.X509Certificates;

namespace WCFClientCS

{

    class Program

    {

        static void Main(string[] args)

        {

            callWsHttp();

            Console.ReadLine();

        }

        static void callWsHttp()

        {

           System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate);

            ServiceReference1.ServiceClient svc1 = new ServiceReference1.ServiceClient("wsHttpBinding");

            Console.WriteLine(svc1.GetData(10));

            svc1.Close();

        }

        static bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)

        {

            return true;

        }

    }

}

 

Filename: app.config

<!—The following system.serviceModel Section can be replaced in the client’s app.config file -->

<system.serviceModel>

    <bindings>

        <wsHttpBinding>

            <binding name="WSHttpBinding_IService" closeTimeout="00:01:00"

                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

                bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"

                maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"

                allowCookies="false">

                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />

                <reliableSession ordered="true" inactivityTimeout="00:10:00"

                    enabled="false" />

                <security mode="Transport">

                    <transport clientCredentialType="Windows" proxyCredentialType="None"

                        realm="" />

                    <message clientCredentialType="Windows" negotiateServiceCredential="true"

                        establishSecurityContext="true" />

                </security>

            </binding>

        </wsHttpBinding>

    </bindings>

    <client>

        <endpoint address=https://myIISServer.myDomain.com/NTLMWCFService/Service.svc

            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService"

            contract="ServiceReference1.IService" name="WSHttpBinding_IService">

            <identity>

                <servicePrincipalName value="host/myClient.myDomain.com" />

            </identity>

        </endpoint>

    </client>

</system.serviceModel>