Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turn on Basic Authentication for a simple WCF service?

I have a very simple WCF webservice that a customer is hosting on their own IIS.

The customer has their own client that they've been testing against it, in their testing environment, and everything was working fine, until they disabled anonymous authentication and enabled basic. Once they did, they started getting errors:

The authentication schemes configured on the host ('Basic') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous'). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. 

So, what do I need to do to get basic authentication working?

My webservice's current web.config:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
            multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
</configuration>

I have my own test client, that I can run against my webservice. Its current app.config:

<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IMyServiceSvc" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost/MyServiceSvc.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyServiceSvc"
                contract="MyServiceSvc.IMyServiceSvc"
                name="BasicHttpBinding_IMyServiceSvc" />
        </client>
    </system.serviceModel>
</configuration>

When I install the service on my local IIS, and run the client against it, everything works, with anonymous authentication enabled.

What do I need to do to turn on basic authentication, in IIS, and to configure both client and server to use basic authentication?

My current test client code:

public class BlackHillsCompletionSvcTest
{
    static void Main(string[] args)
    {
        using (var client = new MyServiceSvcClient())
        {
            var data = new Data
            {
                id = "1",
                description = "test data"
            };

            try
            {
                var result = client.receiveData(data);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
            }
        }
    }
}

==Attempts:==

As per Pankaj Kapare's suggestion, I added this to the webservice's web.config:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="httpBinding">
                <security mode="TransportCredentialOnly">
                    <transport clientCredentialType="Basic" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    ...
</system.serviceModel>

With that, I got an error when creating the client:

The binding at system.serviceModel/bindings/basicHttpBinding does not have a configured binding named 'BasicHttpBinding_IMyServiceSvc'. This is an invalid value for bindingConfiguration. 

So I added this to the client's app.config:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IMyServiceSvc">
                <security mode="TransportCredentialOnly">
                    <transport clientCredentialType="Basic" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    ...
</system.serviceModel>

With that, I got another error:

The username is not provided. Specify username in ClientCredentials.

So I added username and password in my client:

using (var client = new MyServiceSvcClient())
{
    client.ClientCredentials.UserName.UserName = "myusername";
    client.ClientCredentials.UserName.Password = "mypassword";
    ...
}

And with that, I get yet another error:

The requested service, 'http://localhost/MyServiceSvc.svc' could not be activated.  Which got me wondering. So I loaded the .svc page in my browser, was asked to log in, and after I did, I saw this:

The authentication schemes configured on the host ('Basic') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous').  Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly.  Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the <serviceAuthenticationManager> element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.

Which is what the customer is seeing.

Ideas?

== Maybe a solution? ==

I think what may have been missing was a service definition, on the server, tying the binding to the endpoint:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="httpBinding">
                <security mode="TransportCredentialOnly">
                    <transport clientCredentialType="Basic" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <services>
        <service
                name="MyServiceSvcNs.MyServiceSvc"
                behaviorConfiguration="ServiceWithMetaData"
                >
            <endpoint name="Default"
                address=""
                binding="basicHttpBinding"
                bindingConfiguration="httpBinding"
                contract="MyServiceSvcNs.IMyServiceSvc"
                />
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="ServiceWithMetaData">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
        multipleSiteBindingsEnabled="true" />
</system.serviceModel>

With this, things seem to be working. At least at first glance.

like image 459
Jeff Dege Avatar asked Jan 22 '15 16:01

Jeff Dege


2 Answers

OK, I figured it out.

First, in IIS Manager., you need to turn off anonymous authentication, and turn on basic authentication. Which may require enabling basic authentication first, then restarting IIS Manager. That's basic IIS stuff, and not really part of my question.

Then, we need to make changes to the web service's web.config. If you remember, it had looked like this:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
            multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
</configuration>

We need to change this to:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="httpTransportCredentialOnlyBinding">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Basic" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service
                    name="MyServiceSvcNs.MyServiceSvc"
                    behaviorConfiguration="ServiceWithMetaData"
                    >
                <endpoint name="Default"
                    address=""
                    binding="basicHttpBinding"
                    bindingConfiguration="httpTransportCredentialOnlyBinding"
                    contract="MyServiceSvcNs.IMyServiceSvc"
                    />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceWithMetaData">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
            multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
</configuration>

What we're doing is defining a basicHttpBinding with TransportCredentialOnly security. Then we define a service, with an endpoint that uses that binding.

Then on the client, we had had:

<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IMyServiceSvc" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost/MyServiceSvc.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyServiceSvc"
                contract="MyServiceSvc.IMyServiceSvc"
                name="BasicHttpBinding_IMyServiceSvc" />
        </client>
    </system.serviceModel>
</configuration>

This needs to change to:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="httpTransportCredentialOnlyBinding">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Basic" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint
                address="http://localhost/MyServiceSvc.svc"
                binding="basicHttpBinding"
                bindingConfiguration="httpTransportCredentialOnlyBinding"
                contract="MyServiceSvc.IMyServiceSvc"
                name="BasicHttpBinding_IMyServiceSvc"
                />
        </client>
    </system.serviceModel>
</configuration>

Here, we're again creating an basicHttpBinding with TransportCredentialOnly security, the we're modifying the endpoint to use it.

like image 160
Jeff Dege Avatar answered Nov 15 '22 06:11

Jeff Dege


Configure you basicHttpBinding in service web.config as follows

<bindings>
  <basicHttpBinding>
    <binding name="httpBinding">
      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Basic" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
like image 41
Pankaj Kapare Avatar answered Nov 15 '22 06:11

Pankaj Kapare