none
customUserNamePasswordValidator over basichttpbinding with security mode = transport RRS feed

  • Question

  • Hello, I'm trying to setup 2 WCF services, 1 which authenticates with basic authententication with active directory, and a second with a customusernameandpasswordvalidator. 

    Per this article, it says we can use Transport as the security mode over the basicHttpBinding with a CustomUserNamePasswordValidator, but it won't work with it set to Transport, only TransportWithMessageCredential. 

    The exception I'm getting when it's set to Transport is:

    "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="mysite.mydomain.local"'."

    Here is my server side web.config that works:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
        <sessionState cookieless="false" mode="InProc" timeout="10" />
        <httpRuntime maxRequestLength="10485760" enable="true" />
        <customErrors mode="Off"/>
      </system.web>
      <system.serviceModel>
        <bindings>
          <basicHttpBinding>
            <binding name="MyBinding" closeTimeout="00:01:00"
              openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:11:00"
              allowCookies="true" maxBufferPoolSize="524288" maxReceivedMessageSize="10485760">
              <readerQuotas maxStringContentLength="10485760" maxArrayLength="10485760"
                maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <security mode="Transport">
                <transport clientCredentialType="Basic" />
              </security>
            </binding>
            <binding name="MyCustomBinding" closeTimeout="00:01:00"
              openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:11:00"
              allowCookies="true" maxBufferPoolSize="524288" maxReceivedMessageSize="10485760">
              <readerQuotas maxStringContentLength="10485760" maxArrayLength="10485760"
                maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <security mode="TransportWithMessageCredential" >
                <transport clientCredentialType="Basic" />
                <message clientCredentialType="UserName" />
              </security>
            </binding>
          </basicHttpBinding>
        </bindings>
        <services>
          <service name="MyWebService.Service1" behaviorConfiguration="MyBehavior">
            <endpoint address="MyEndPoint" binding="basicHttpBinding"
              bindingConfiguration="MyBinding" contract="MyWebService.IService1" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          </service>
          <service name="MyWebService.Service2" behaviorConfiguration="MyCustomBehavior">
            <endpoint address="MyCustomEndPoint" binding="basicHttpBinding"
              bindingConfiguration="MyCustomBinding" contract="MyWebService.IService2" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="MyBehavior">
              <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="true" />
              <serviceCredentials />
              <serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500"
                maxConcurrentInstances="500" />
            </behavior>
            <behavior name="MyCustomBehavior">
              <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="true" />
              <serviceCredentials>
                <userNameAuthentication userNamePasswordValidationMode="Custom"
                  customUserNamePasswordValidatorType="MyWebService.MyCustomUserNameValidator, MyWebService" />
              </serviceCredentials>
              <serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500"
                maxConcurrentInstances="500" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    </configuration>
    

    Changing this binding to the following generates the exception:

     <binding name="MyCustomBinding" closeTimeout="00:01:00"
              openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:11:00"
              allowCookies="true" maxBufferPoolSize="524288" maxReceivedMessageSize="10485760">
              <readerQuotas maxStringContentLength="10485760" maxArrayLength="10485760"
                maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <security mode="Transport" >
                <transport clientCredentialType="Basic" />
                <message clientCredentialType="UserName" />
              </security>
            </binding>
    Everything works find on the Service1 with the domain user name and password, and actually if you put in those credentials on the Service2, then it works as well. So it's for some reason validating against Basic Authentication unless you change it to TransportWithMessageCredentials.

    Does anyone know if you can do this?

    Thanks

    Tuesday, February 26, 2013 12:06 AM

Answers

  • Hi Ryan_Ha,

    Hope that you are doing great today.

    You are right. If you want to use transport security then only the transport tag will be read i.e.

    <security mode="Transport" >
               
    <transport clientCredentialType="Basic" />
    and not <message clientCredentialType="UserName" />

    This is because IIS does not understand this as it works over the channel and not end to end. It will authenticate with AD and if the credentials are fine then no issues.

    If you want to use customusernameandpasswordvalidator, then you have to use message security i.e. TransportWithMessageCredentials so that the message tag will be read i.e.

    <message clientCredentialType="UserName" />

    and not the transport tag i.e. <transport clientCredentialType="Basic" />

    HTH!

    Regards,

    Melissa

    • Marked as answer by Ryan_Ha Tuesday, March 5, 2013 11:38 PM
    Tuesday, March 5, 2013 5:27 PM

All replies

  • Hi, try with, set algorithmSuite="Default" .

    <security mode="Transport">
                             <transport clientCredentialType="Basic" proxyCredentialType="None" realm=""/>
                            <message clientCredentialType="UserName" algorithmSuite="Default"/>
                        </security>

    The causing of this issue may be the IIS intercepts the https request and performs IIS-level authentication before the WCF framework and your custom validator has a chance to kick in.

    Tuesday, February 26, 2013 8:26 AM
  • Thanks MiniPeter, still same thing, just wondering, what do you have to set the algorithmSuite to on the client side?

    Also - do you know, is this even possible to do with Transport security on IIS with the customusernameandpasswordvalidator?  I read someone said that it can't be done with IIS but that was a while ago on the 3.0 .NET framework.  I'm using 4.0 on IIS 7..

    Thanks.

    Tuesday, February 26, 2013 3:05 PM
  • Hi Ryan_Ha,

    Hope that you are doing great today.

    You are right. If you want to use transport security then only the transport tag will be read i.e.

    <security mode="Transport" >
               
    <transport clientCredentialType="Basic" />
    and not <message clientCredentialType="UserName" />

    This is because IIS does not understand this as it works over the channel and not end to end. It will authenticate with AD and if the credentials are fine then no issues.

    If you want to use customusernameandpasswordvalidator, then you have to use message security i.e. TransportWithMessageCredentials so that the message tag will be read i.e.

    <message clientCredentialType="UserName" />

    and not the transport tag i.e. <transport clientCredentialType="Basic" />

    HTH!

    Regards,

    Melissa

    • Marked as answer by Ryan_Ha Tuesday, March 5, 2013 11:38 PM
    Tuesday, March 5, 2013 5:27 PM
  • Thanks so much Melissa, I think I can work around this - I would just create a "Login" method that would do the same thing as the customusernameandpasswordvalidator.  If I go that route, and lets say a user calls methodA before they call Login - is there a way to somehow block all other methods from being accessed before they call the Login?  If so then I can basically re-create the customusernameandpasswordvalidator and keep it with transport layer security. 

    I unfortunately can't use message because I'm using MonoTouch for an iPad app and it doesn't support TransportWithMessageCredentials.

    Thanks again for your help

    Tuesday, March 5, 2013 11:43 PM