tags:

views:

686

answers:

3

Server:

<system.serviceModel>
    <services>
        <service name="Service" behaviorConfiguration="md">
            <!-- Service Endpoints -->
            <endpoint address="SslService" binding="basicHttpBinding" bindingConfiguration="security" contract="IService"/>
            <host>
                <baseAddresses>
                    <add baseAddress="https://pc:8080/Service.svc"/&gt;
                </baseAddresses>
            </host>
        </service>
    </services>
    <bindings>
        <basicHttpBinding>
            <binding name="security">
                <security mode="Transport">
                    <transport clientCredentialType="Basic"/>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="md">
      <serviceCredentials>
        <userNameAuthentication
          userNamePasswordValidationMode="Custom"
          customUserNamePasswordValidatorType="ClassLibrary1.CustomUserNameValidator, ClassLibrary1" />
      </serviceCredentials>
                <serviceMetadata httpsGetEnabled="true"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

ClassLibrary1.CustomUserNameValidato:

public class CustomUserNameValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName != "111" || password != "111")
            {

                throw new System.ServiceModel.FaultException("Unknown username or incorrect password");
            }
        }
    }


Client:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="">
                        <extendedProtectionPolicy policyEnforcement="Never" />
                    </transport>
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://pc:8080/Service.svc/SslService" binding="basicHttpBinding"
            bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
            name="BasicHttpBinding_IService" />
    </client>
</system.serviceModel>


ServiceReference1.ServiceClient s = new WindowsFormsApplication1.ServiceReference1.ServiceClient();

s.ClientCredentials.UserName.UserName = "111";
s.ClientCredentials.UserName.UserName = "111";
MessageBox.Show(s.GetData(3)); // <---- ERROR

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

A: 

Looks like you set the user name twice instead of the user name and password.

When you have basic authentication and you do not send the username and password with the request you get a challenge response back.

Shiraz Bhaiji
A: 

Try to send username and password not in http with basic authentication (this can embarrass IIS), but only in soap-message headers with following scheme:

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

http://msdn.microsoft.com/en-us/library/ms789011.aspx

Maybe you also need to additionally specify <transport clientCredentialType="None">

Anon 806
+1  A: 

I'm assuming you are hosting your servicehost on the IIS. Then the problem is that 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.

In your example, the IIS will actually look for a local user '111' with password '111' on the server running the IIS. Try creating this user on the server, and you will probably get a different result.

One solution is to host your WCF servicehost somewhere else, for example in a Windows Service. Another solution is to change your security scheme to TransportWithMessageCredential. Finally, you could check this OSS http module out: Custom Basic Authentication for IIS - seems to do the trick we need.

peter_raven