Bug 2415 - When calling a WCF service with windows authentication a client credentials exception is thrown
Summary: When calling a WCF service with windows authentication a client credentials e...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: WCF assemblies (show other bugs)
Version: unspecified
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2011-12-08 06:18 UTC by Dave
Modified: 2011-12-29 15:27 UTC (History)
1 user (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Modified copies of the BasicHttpBinding and HttpRequestChannel classes (8.41 KB, patch)
2011-12-27 16:22 UTC, Dave
Details | Diff
BasicHttpBinding and HttpRequestChannel patch (3.94 KB, patch)
2011-12-29 15:27 UTC, Dave
Details | Diff

Description Dave 2011-12-08 06:18:18 UTC
We have a basicHttpBinding WCF web service with windows authenctication configured. A dynamic proxy is generated from an Interface to call the web service's functions.

On a Windows machine using the following code, using .net framework 3.5, the following will succeed.

if (connection.UseAuthentication)
{
                //do some crazy authentication malarkey
    binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
 binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
}


String hostAddress = String.Format("{0}/Management.svc", connection.Server);
EndpointAddress newAddress = new EndpointAddress(hostAddress);

ChannelFactory<AccessMobileServices.IManagement>  ManagementChannel = new ChannelFactory<AccessMobileServices.IManagement>(binding);

if (connection.UseAuthentication)
{

                    ManagementChannel.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

ManagementChannel.Credentials.Windows.AllowNtlm = true;
ManagementChannel.Credentials.Windows.ClientCredential = new NetworkCredential("USERNAME", "PASSWORD", "DOMAIN");

}

ManagementProxy = ManagementChannel.CreateChannel(newAddress);

m_Database = connection.Database;

SecurityTicketRequest request = new SecurityTicketRequest();
request.Username = connection.Username;
request.Password = connection.Password;
request.Database = connection.Database;
request.APIKey = Access.Mobile.Datatypes.Keys.ApiKeys.WebServiceAPIKey;

SecurityTicketResponse result = ManagementProxy.CreateSecurityTicket(request);

However, when the same code is run via mono on a mac(either as a compiled dll or as source files) an exception is thrown.

The exception message is 
Use ClientCredentials to specify a user name for required HTTP negotiate authentication.

Setting the client credentials

ManagementChannel.Credentials.UserName.UserName = @"DOMAIN\USERNAME";
ManagementChannel.Credentials.UserName.Password = "PASSWORD";

removes the error but always returns failed authentication, regardless of the combination of username and password.


Details:
Mac OSX Lion using monodevelop 2.8.2

Mono JIT compiler version 2.10.6 (tarball Fri Sep 16 00:13:06 EDT 2011)
Copyright (C) 2002-2011 Novell, Inc, Xamarin, Inc and Contributors. www.mono-project.com
	TLS:           normal
	SIGSEGV:       normal
	Notification:  kqueue
	Architecture:  x86
	Disabled:      none
	Misc:          debugger softdebug 
	LLVM:          yes(2.9svn-mono)
	GC:            Included Boehm (with typed GC)

Service Config
<basicHttpBinding>
        <binding name="Basic" maxBufferSize="655360000" maxReceivedMessageSize="655360000" maxBufferPoolSize="655360000">
          <readerQuotas maxStringContentLength="655360000" maxArrayLength="655360000" maxBytesPerRead="655360000" maxNameTableCharCount="655360000" maxDepth="100"/>
          <!-- Enable the section below to support Windows authentication on the http connection-->

          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"/>
          </security>
         
        </binding>
      </basicHttpBinding>

IIS 7.5(windows 7)
Anonymous disabled
Windows Authentication disabled
Comment 1 Zoltan Varga 2011-12-08 08:10:20 UTC
-> wcf.
Comment 2 Dave 2011-12-27 16:22:52 UTC
Created attachment 1101 [details]
Modified copies of the BasicHttpBinding and HttpRequestChannel classes

I have done some work on this bug using the source code from the main branch.

By setting the authenticationscheme of the binding(BasicHttpBinding) to IntegratedWindows when client credential type is set to Windows you can set the HttpRequestChannel to pass the NetworkCredentials from the windows property of the ClientCredntials.  This allows the user to specify domain as well as username and password.

The changes are below.

BasicHttpBinding.cs

Original

switch (Security.Transport.ClientCredentialType) {
case HttpClientCredentialType.Basic:
h.AuthenticationScheme = AuthenticationSchemes.Basic;
break;
case HttpClientCredentialType.Ntlm:
h.AuthenticationScheme = AuthenticationSchemes.Ntlm;
break;
case HttpClientCredentialType.Windows:
h.AuthenticationScheme = AuthenticationSchemes.Negotiate;
break;

New

switch (Security.Transport.ClientCredentialType) 
{
	case HttpClientCredentialType.Basic:
		h.AuthenticationScheme = AuthenticationSchemes.Basic;
				break;
	case HttpClientCredentialType.Ntlm:
		h.AuthenticationScheme = AuthenticationSchemes.Ntlm;
				break;
	case HttpClientCredentialType.Windows:
               h.AuthenticationScheme  = AuthenticationSchemes.IntegratedWindowsAuthentication;

HttpRequestChannel

Original

var httpbe = (HttpTransportBindingElement) source.Transport;
string authType = null;
switch (httpbe.AuthenticationScheme) {
// AuthenticationSchemes.Anonymous is the default, ignored.
case AuthenticationSchemes.Basic:
authType = "Basic";
break;
case AuthenticationSchemes.Digest:
authType = "Digest";
break;
case AuthenticationSchemes.Ntlm:
authType = "Ntlm";
break;
case AuthenticationSchemes.Negotiate:
authType = "Negotiate";
break;
}
if (authType != null) {
var cred = source.ClientCredentials;
string user = cred != null ? cred.UserName.UserName : null;
string pwd = cred != null ? cred.UserName.Password : null;
if (String.IsNullOrEmpty (user))
throw new InvalidOperationException (String.Format ("Use ClientCredentials to specify a user name for required HTTP {0} authentication.", authType));
var nc = new NetworkCredential (user, pwd);
web_request.Credentials = nc;
// FIXME: it is said required in SL4, but it blocks full WCF.
//web_request.UseDefaultCredentials = false;
}

New

var httpbe = (HttpTransportBindingElement) source.Transport;
			string authType = null;
			switch (httpbe.AuthenticationScheme) {
			// AuthenticationSchemes.Anonymous is the default, ignored.
			case AuthenticationSchemes.Basic:
				authType = "Basic";
				break;
			case AuthenticationSchemes.Digest:
				authType = "Digest";
				break;
			case AuthenticationSchemes.Ntlm:
				authType = "Ntlm";
				break;
			case AuthenticationSchemes.Negotiate:
				authType = "Negotiate";
				break;
			case AuthenticationSchemes.IntegratedWindowsAuthentication:
				authType = "Negotiate";
				break;
			}

			if (authType != null)
            		{
              			NetworkCredential netCred = null;
 
		                if (httpbe.AuthenticationScheme == AuthenticationSchemes.IntegratedWindowsAuthentication)
                		{
                    			netCred = source.ClientCredentials.Windows.ClientCredential;
                    
		                }
                		else
                		{
		                    var cred = source.ClientCredentials;
                		    string user = cred != null ? cred.UserName.UserName : null;
                    		    string pwd = cred != null ? cred.UserName.Password : null;
                    		    if (String.IsNullOrEmpty(user))
                        		throw new InvalidOperationException(String.Format("Use ClientCredentials to specify a user name for required HTTP {0} authentication.", authType));
                    		    netCred = new NetworkCredential(user, pwd);
                		}
                		web_request.Credentials = netCred;
                		// FIXME: it is said required in SL4, but it blocks full WCF.
                		//web_request.UseDefaultCredentials = false;
            		}
Comment 3 Dave 2011-12-29 15:27:25 UTC
Created attachment 1111 [details]
BasicHttpBinding and HttpRequestChannel patch

Patch file to enable windows authentication to work when using BasicHttpBinding with a WCF Service

Note You need to log in before you can comment on or make changes to this bug.