Search code examples
c#.netwcfauthenticationautofac

Add authentication to WCF + Autofac extensionless service


I'm looking for a way to set up simple username + password authentication for my WCF services. They are set up using Autofac extensionless services. This means my Global.asax looks like this:

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)        
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyWcfService>().InstancePerLifetimeScope();
        var container = builder.Build();

        AutofacHostFactory.Container = container;
        AutofacHostFactory.HostConfigurationAction =
            host =>
            {
                host.Description.Behaviors.Add(container.Resolve<MyCustomBehavior>());
            };
        
        RouteTable.Routes.Add(new ServiceRoute("my/custom/route", new AutofacServiceHostFactory(), typeof(MyWcfService)));
    }
}

and my Web.config looks like this:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
  <behaviors>
    <serviceBehaviors>
    <behavior>
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
    </serviceBehaviors>
  </behaviors>
  <bindings>
    <basicHttpBinding>
    <binding maxReceivedMessageSize="10485760">
      <readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
    </binding>
    </basicHttpBinding>
  </bindings>
  <protocolMapping>
    <add binding="basicHttpsBinding" scheme="https" />
  </protocolMapping>
</system.serviceModel>

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true" />
  <directoryBrowse enabled="true" />
</system.webServer>

As you can see I don't have any *.svc files, nor do I have a <services> section in my Web.config to configure my services. Right now I need to add basic username + password authentication to this service. I have followed the steps in this Microsoft tutorial, but the CustomUserNameValidator never gets called.

Changes I made following the tutorial are:

  • Add the CustomUserNamePasswordValidator
  • Add serviceCredentials section to the behaviors in Web.config
<serviceCredentials>
  <userNameAuthentication 
    userNamePasswordValidationMode="Custom" 
    customUserNamePasswordValidatorType="My.ServiceHost.CustomUserNamePasswordValidator, My.ServiceHost"/>
</serviceCredentials>
  • Update my binding in Web.config to:
<wsHttpBinding>
  <binding name="authQuotaBinding" maxReceivedMessageSize="10485760">
    <security mode="Message">
      <message clientCredentialType="UserName" />
    </security>
    <readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
  </binding>
</wsHttpBinding>

Locally I am hosting the service using IIS Express. Which piece of the puzzle am I missing to get this to work?


Solution

  • There are several pieces of information missing that might be the missing pieces of the puzzle.

    1. You define a custom behavior on all your hosts via Autofac, but it is not clear what this custom behavior is doing and/or if this is related to your problem?

    2. You have defined your custom validator to be used when a username is used for authentication and needs to be validated (in the serviceCredentials section), however this will only be triggered when you use the wsHttpBinding for calling your service. However, I don't see any link between your service and this binding? Are you sure that the service is using that binding? Or is it still using your basicHttpBinding? Normally this would be configured in the configuration for each service, but since you are using AutoFac, I'm assuming that Autofac is linking the configuration of the binding to your service. Might be that is where it is going wrong?

    My guess is that either you need to specify this in Autofac, or it might be that you also need to update this part of the configuration:

    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    

    into

    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http" />
    </protocolMapping>
    

    or if you want to be more specific

    <protocolMapping>
      <add binding="wsHttpBinding" bindingConfiguration="authQuotaBinding" scheme="http" />
    </protocolMapping>
    

    But that depends on what the definition of the binding with name basicHttpsBinding is. (It also does not seem to be included in the provided information?)

    For more information about the protocolMapping, see: https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/protocolmapping

    Adding to that, it might also be that your requirements are to use this configuration instead:

    <wsHttpBinding>
      ...
        <security mode="TransportWithMessageCredential">
          <message clientCredentialType="UserName" />
        </security>
      ...
    </wsHttpBinding>
    

    This is off course depending on whether you want to use SOAP message encryption/signing for integrity of your message or are happy with the integrity provided by HTTPS.

    According to the article linked in your question, you could even use basicHttpBinding instead of wsHttpBinding and using security with mode set to Transport and clientCredentialType attribute of the transport section set to Basic e.g.,

    <basicHttpBinding>
      ...
        <security mode="Transport">
          <transport clientCredentialType="Basic" />
        </security>
      ...
    </basicHttpBinding>
    

    For more information about the different security modes, see: https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/security-of-wshttpbinding

    Lastly, I also would not recommend to leave the serviceDebug setting which allows you to include the exception details be set to on for production environments. (Off course this is again depending on your requirements)