basic authentication in IIS with basichttpBinding WCF issue - c#

I have just put my webservice onto IIS 7 and I need to use basic authentication, I have set this up in IIS 7 by enabling it, however I am getting the common error:
the http request is unauthorized with client authentication scheme
'basic' the authentcation header received from the server was 'basic
realm' = "server address"
In my client I am using
binding.Security.Mode = ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly
binding.Security.Transport.ClientCredentialType = ServiceModel.HttpClientCredentialType.Basic
With the same settings in the service
<basicHttpBinding>
<binding name="binding1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
/binding>
</basicHttpBinding>
I see that a lot of solutions to this is to use a different security mode like transport which uses HTTPS and a certificate instead of HTTP. I dont want this, so is there anyway of solving this without HTTPS?
Thanks

Related

Active Directory usage in WCF Windows authentication

We have a WCF service that uses Windows authentication (also with option AllowNtlm=true). The documentation says that Windows authentication uses Active Directory to authenticate the user but doesn't describe how, which I need to figure out. How does WCF uses Active Directory?
Here's the binding configuration we're using:
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Windows" establishSecurityContext="false" />
</security>
If anyone interested, this is what I've found.
If you set your client credentials type to Windows, WCF uses something called Windows SSPI for Windows authentication.
Windows SSPI makes either Kerberos or CLDAP requests to domain controller. Example:
Kerberos: AS-REQ request
CLDAP:
searchRequest(..) "<ROOT>"
(&(&(&(&(&(&(DnsDomain=...)(Host=...))(User=...))(AAC=...))(DomainGuid=...))(NtVer=...))(DnsHostName=...))
Both can be observed using Wireshark (look for Kerberos5 or CLDAP protocol requests)

WCF Streaming with authentication

I have a WCF service which must be secured with Windows and Certificate authentication.
I know that wsHttpBinding does no support Streaming but according to msdn it can be done using transport security with a customBinding but I am not able to do it...
<customBinding>
<binding name="AuthBinding">
<mtomMessageEncoding maxBufferSize="65535" />
<windowsStreamSecurity protectionLevel="Sign"/>
<httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
I am going from one exception to another :
The security capabilities of binding 'System.ServiceModel.Channels.CustomBinding' do not match those of the generated runtime object. Most likely this means the binding contains a StreamSecurityBindingElement, but lacks a TransportBindingElement that supports Stream Security
Or
The request message must be protected. This is required by an operation of the contract ('IEntity','WebService.Entity'). The protection must be provided by the binding ('CustomBinding','WebService.Entity')
Rather than being done in a single step, this is two step process.
Enable Transport Security with Certificate Authentication.
Enable Transport Security with Windows Authentication.
Also I am not sure both works together.
But MSDN Article found seems to direct in a correct direction:
How to: Secure a Service with Windows Credentials with wsHttpBinding
Please refer these links from MSDN for further learning (not much help if you are in hurry to deliver some milestone):
Transport Security with Windows Authentication
Transport Security with Certificate Authentication
Update
You have to use custom binding having Mixed (transport with message credentials) security mode.
Three binding elements relate to message level security, all of which derive from the SecurityBindingElement class.
The three are TransportSecurityBindingElement, SymmetricSecurityBindingElement, and AsymmetricSecurityBindingElement. The TransportSecurityBindingElement is used to provide Mixed mode security. The other two elements are used when the message layer provides security.
Additional classes are used when transport level security is provided:
HttpsTransportBindingElement
SslStreamSecurityBindingElement
WindowsStreamSecurityBindingElement
You can get help on:
How to: Create a Custom Binding Using the SecurityBindingElement
and
Security Capabilities with Custom Bindings
This works for me:
<basicHttpBinding>
<binding name="basic" transferMode="Streamed" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>

Kerberos Over HTTPS

I have a WCF service hosted by a Windows Application of my own. I want the service to authenticate the client at the transport level using the client's Certificate and when the client communicates with the service, it must pass its Kerberos Ticket of the client's user account. Looking around on the internet i found this configuration for the service:
<bindings>
<customBinding>
<binding name="Kerberos (MsgHeader) over Transport (Certificate)">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="KerberosOverTransport">
<secureConversationBootstrap />
</security>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
They say that this configuration worked with Microsoft's help. Now, i tried to duplicate this configuration through code, so i used the following snippet:
BindingElementCollection elementCollection = new BindingElementCollection();
elementCollection.Add(SecurityBindingElement.CreateKerberosOverTransportBindingElement());
elementCollection.Add(new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap11 });
elementCollection.Add(new HttpsTransportBindingElement() { RequireClientCertificate = true });
return new CustomBinding(elementCollection);
I configured the endpoint with this binding along with a valid certificate bound to the port. I then added a service reference at the client project in Visual Studio.
To this end, everthing is working great! I also configured the client to send its certificate when communicating with the service, this also worked fine. However, when I try to invoke any method of the service, I get the following error:
An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
And when I examined the inner exception, I found the following error:
An error occurred when processing the security tokens in the message.
Any help, please? Do i need to configure the client further to send its Kerberos token, or what?
P.S. The service and client machine clocks are synchronized. In addition, the service and the client are on two different machines joined to a domain.

Making WCF service run over HTTP with simple user config based authentication

I've looked up and down and I can't seem to find a way to have a simple WCF service (with either basicHttpBinding or wsHttpBinding) authenticate against this sort of config:
<authentication mode="Forms">
<forms cookieless="UseCookies">
<credentials passwordFormat="Clear">
<user name="test" password="pass"/>
</credentials>
</forms>
</authentication>
Basically, I want to hardcode a simple user/pass (don't ask why) and make sure my WCF service uses this.
On the client side I have this:
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "pass";
But the credentials do not seem to get passed on. The HttpContext.Current.User.Identity is never authenticated on the WCF side.
I've tried playing with the settings below trying to use everything from None, Transport, Message... but only None seems to let the service run (but no credentials are being sent/used). Other settings seem to require a X509 certificate (as I've found out in this great example).
<wsHttpBinding>
<binding name="userHttp">
<security mode="None">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
So, all in all... I want to create a very simple WCF service (that runs over HTTP - not HTTPS) with even simpler plain text username/password authentication. Should be possible but I am already lost. The best solution involves honoring <user /> entries but I'd be happy with any other simple implementation. It doesn't need to use cookies. As far as I am concerned it may as well send username/password on each service method call.
If you want to send user/pass in the message level without ssl then use ClearUsernameBinding. If you want the same in the transport level then use TransportCredentialOnly.
<binding name="BasicHttpEndpointBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>

Using WCF to consume service and receieving varying errors depending on binding configuration

I am attempting to consume an intranet web service with WCF. I added reference to the service via the Add Service Reference feature in VS2008. In doing so I was prompted for network credentials to access the service which I provided and the service reference was added.
I then wrote some code that I would expect to fail as it doesn't pass credentials along with the call of the service:
FooServiceClient proxy = new FooServiceClient();
bool isValid = proxy.ValidateBar(baz);
When I use this code I receieve the exception:The HTTP request is unauthorized with client authentication scheme 'Negotiate'.The authentication header received from the server was 'Basic realm="Kerberos"'.Which is the same error I receieve when using either of the two code examples below.
FooServiceClient proxy = new FooServiceClient();
proxy.ClientCredentials.UserName.UserName = "USERNAME";
proxy.ClientCredentials.UserName.Password = "PASSWORD";
bool isValid = proxy.ValidateBar(baz);
or
FooServiceClient proxy = new FooServiceClient();
NetworkCredential creds = new NetworkCredential("USERNAME", "PASSWORD");
proxy.ClientCredentials.Windows.AllowedImpersonationLevel =
TokenImpersonationLevel.Identification;
proxy.ClientCredentials.Windows.AllowNtlm = false;
proxy.ClientCredentials.Windows.ClientCredential = creds;
bool isValid = proxy.ValidateBar(baz);
My gut tells me that I have the security mode configured incorrectly. According to the server manager the end point that I am attempting to bind to is looking for a Basic Http Credential via SSL. Which after reading about WCF-BasicHttp Transport Properties lead me to believe that I should use this configuration:
<security mode="Transport">
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Unfortunately, I continued to receive the same error.
Again, I am sure my troubles have to do with a configuration issue on my part as I've previously consumed this service in other projects with the outdated Add Web Reference.
You have to really understand what the endpoint on the other end is configured under. If it is self hosted and running under SSL then it should be Transport, but if its running under IIS with SSL then it could possibly be TransportWithMessageCredentials and the Transport credentials might be "None".
It is very tricky to get this to bind correctly.
As far as the Exception you are getting
The provided URI scheme 'https' is
invalid; expected 'http'. Parameter
name:
When you use TransportCredentialOnly you have to use HTTP binding rather than HTTPS, and I am sure you didn't change your endpoint address to HTTP because that's not what the service reference is.
What binding are you using for your intranet scenario? The recommended best practice would be NetTCP with transport security and Windows credentials (assuming all your callers are intranet-clients with an account in your corporate Active Directory)
That would avoid any of the http/https mess.
However, to host netTcp, you either needs WAS (Windows Process Activation Server) which is part of IIS7 and that only runs on Windows Server 2008 (Vista Server) or 2008 R2 (Win7 Server). Or you need to host your service yourself in a e.g. NT Service.
Lots of information still missing! Please update your question accordingly. Thanks!
The below WCF binding configuration ended up being the solution.
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

Categories