WCF - How to configure netTcpBinding for NTLM authentication? - wcf

I know how to configure basicHttpBinding for NTLM authentication, but can't figure out a way to do the same for netTcpBinding.
Does netTcpBinding support NTLM? If so, how to force WCF service to use NTLM?
BTW a well known method using identity element for some reason didn't work at all. I am looking for something like this - clientCredentialType ="Ntlm" but for tcp.
Here is basicHttp setting:
<basicHttpBinding>
<binding name="BasicHttpBinding">
<security mode ="TransportCredentialOnly">
<transport clientCredentialType ="Ntlm"/>
</security>
</binding>
</basicHttpBinding>

Here is the comprehensive answer that I finally found, tested, and confirmed.
A. My WCF client used to build an EndPoint.Address dynamically as follow
EndPointAddress myEdpintAddress = new EndPointAddress(stringURL);
But in the case of a secure transport (net.tcp) it has to be initialized as follow
EndPointAddress myEdpintAddress = new EndPointAddress(new UrRL(string), myEndPointIdentity)
Without the EndPointIdentity parameters the Identity property in the EndPointAddress object is null, and generates the “...target principal name is incorrect... " error on the server side.
B. Our domain controller supports both Kerberos and Ntlm authentication. After above is done, generally there are four configuration scenarios on the client side for the net.tcp binding if security is other than “None”, and the WCF service runs as a domain account:
No <identity> elements in the client endpoint specified - WCF call fails
<identity> element provided, but with an empty value for dns, userPrioncipalName or servicePrincipalName elements - WCF call successful, but uses the Ntlm authentication
<identity> element provided with the a value for dsn or SPN – WCF call successfull; service uses Ntlm to authenticate.
<identity> element provided with the correct value for upn – WCF call successfull; service uses Kerberos for authenticate. Incorrect or missing value for upn trigger Ntlm authentication
Thanks.

The Net TCP Binding does not support "NTLM" as a client credentials type - you have a choice of None, Windows or Certificate only (see the MSDN docs on TcpClientCredentialType).
So in your case, try this:
<netTcpBinding>
<binding name="tcpWindows">
<security mode ="TransportCredentialOnly">
<transport clientCredentialType ="Windows"/>
</security>
</binding>
</netTcpBinding>
Any reason why this doesn't work??

Related

How to expose WCF service with Basic and Windows authentication options, so Negotiation works

Some clients need to be able to connect to our WCF SOAP services using Basic authentication, while others need to use Windows authentication. We normally host our services in IIS, although we do provide a less-developed Windows Service hosting option.
It's my understanding that it is not possible to configure one endpoint to support both Basic and Windows authentication. So we have two endpoints per service.
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
<endpoint address="win" binding="basicHttpBinding" bindingConfiguration="WindowsBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
...
<bindings>
<basicHttpBinding>
<binding name="BasicBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
<binding name="WindowsBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
These are in the same Web Application in IIS. That Web Application has both Basic and Windows authentication enabled (else one of the above bindings wouldn't work).
When a client uses the Windows-authenticated endpoint (with "win" on the end of URL), this typically works fine. When the initial request doesn't contain any authentication information, a negotiation takes place between the client and IIS, they settle on Windows authentication and all goes well.
When a client uses the Basic-authenticated endpoint (without "win" on the end of URL), this works if they include the Authorization HTTP header with the correct encoded credentials in it. However, if they do not include any authentication information in the initial request, the negotiation ends up choosing Windows authentication. This gets the request past IIS security, but WCF then refuses the request, because it's going to a Basic-authenticated endpoint.
I am rather hazy on exactly what's happening in the negotiation. But it seems to me that IIS offers all authentication methods enabled for the Web Application (i.e. Basic and Windows), even though the particular WCF endpoint URL for the request only supports Basic.
I would like to know if there is anything we can do in IIS to make the negotiation come up with the right answer: that is, if the request is to a Basic-authenticated endpoint, tell the client to use Basic. Of course, we still want the negotiation to end up choosing Windows, when the request went to the Windows-authenticated endpoint.
If there isn't, then do you think we would be better off concentrating on our Windows Service-hosted version of the services? Or would that have similar problems somehow?
Final note: we do use Basic with HTTP for some internal uses, but we do know that this is an insecure combination. So we typically turn on HTTPS for production use; I've left that out here, for simplicity.
Yes, clientCredentialType="InheritedFromHost" solves the problem for me. This, new in .Net 4.5, means that one can now use the same endpoint URL for more than one authentication type. IIS settings control what authentication is allowed, meaning no longer possible to get IIS and WCF settings in conflict.

How to use Message security and UserName clientCredentialType without Certificate in WCF Service?

i have a WCF service with wsHttpBinding which my clients are my windows application and my website. both those clients are consumer of the my service. in the my service, i used a Message security and UserName clientCredentialType for clients authentication. i do not want use any certificate for this authentication. how do i? or you suggest to me other solution for this sake?
WsHttpBinding message security with UserName client creadentials demands server certificate. The only option is to use Windows client credentials but in such case your client and service must be in the same AD domain (or trusted domains). If you want to secure message (encrypt and sign) you need such infrastructure.
Edit:
Based on your comment you don't need message security, you only want to use UserNameToken profile to transport client credentials over insecured channel. This is possible in WCF 4 (and in older versions with special KB). Try this custom binding:
<customBinding>
<binding name="UsernamePasswordOverHttp">
<textMessageEncoding messageVersion="Soap11" />
<security
authenticationMode="UserNameOverTransport"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
allowInsecureTransport="true" />
<httpTransport />
</binding>
</customBinding>
Be aware that there can be some problem with autogenerating WSDL for such service.
Edit 2:
Another possibility is to use ClearUserNameBidning.
thanks for your example. i used your example but i received this error:
The Scheme cannot be computed for this binding because this CustomBinding lacks a TransportBindingElement. Every binding must have at least one binding element that derives from TransportBindingElement.
and other my question: for this solution i use from which project type in VS2010? a WCF Service Library in project or a WCF Service website. which one?
thank you for your answers.

Which authentication mode of basichhtpbinding can be used to secure a WCF Service using Streaming?

Details about my service:
A file upload service
Transfermode is set to stream
Service is hosted in IIS 7.
I need to provide secuirty to my service. I have tried with ntlm and windows secuirty.I was getting the following error when i am trying to secure my service
"HTTP request streaming cannot be used in conjunction with HTTP authentication. Either disable request streaming or specify anonymous HTTP authentication."
I have found a description stating that:
Description:
You can't do transport auth. with streaming. If you have to use HTTP request streaming, you'll have to run without security.
So i wish to know how can i secure my service? Which secuirty mode can i use with basichttpbinding?Can anyone pls help me on this?
You can try using TransportWithMessageCredential:
<bindings>
<basicHttpBinding>
<binding name="securedStream" transferMode="streamed">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
This will pass credentials in SOAP header. Now you must either pass user's name and password - default validation is against Windows accounts but you can also use Membership provider or custom password validator.
If you really want NTLM or Windows then it means you are running both client and server in the same network / domain. In such case use Net.tcp instead.

WCF + User credentials

I am working on a Silverlight v3 web app and I would like to secure access to the WCF service I am using to fetch my data. I currently have the WCF working just fine, but it doesn't require any user credentials.
I'm not very experienced with this aspect of WCF, so my first idea was to add username and password parameters to each of my service's operations. The problem I have with this is that this would require a lot of redundant code, and the fact that the username and password would be transferred over the wire in plain text.
What I would like is a way to specify the credentials upfront on the client side right after I create my service proxy (I am using the proxy autogenerated from "Add Service Reference").
Upon googling for a solution to this, I could only find solutions that similar to my first idea (using username/password parameters). Could someone please point me in the right direction?
Thanks!
Where are these usernames and passwords coming from? If your web site already implements Forms authentication then you can bypass setting credentials yourself and use the forms authentication cookie. If your users are logged in then the cookie will travel with the web service call. In order to read it on the other side you need to make a couple of changes.
First you need to enable ASP.NET compatibility mode for WCF in the system.ServiceModel section:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Once that is done then for each service method you want to understand the ASP.NET cookie add the [AspNetCompatibilityRequirements] attribute to your service class
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService
{
}
Now within each method you can access the HttpContext.Current.User.Identity object to discover the user's identity.
If you only want certain methods to be called by authenticated users then you can use a PrincipalPermission thus
[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Authenticated=true)]
public string Echo()
As a bonus if you're using ASP.NET's role provider then those will also be populated and you can then use a PrincipalPermission on methods to limit them to members of a particular role:
[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role="Administators")]
public string NukeTheSiteFromOrbit()
And this works in Silverlight2 as well obviously.
Don't roll your own and add explicit parameters - that is indeed way too much work!
Check out the WCF security features - plenty of them available! You can e.g. secure the message and include credentials inside the message - all out of the box, no extra coding on your side required!
Check out this excellent article on WCF security by Michele Leroux Bustamante: http://www.devx.com/codemag/Article/33342
In your case, I'd suggest message security with user name credentials - you need to configure this on both ends:
Server-side:
<bindings>
<basicHttpBinding>
<binding name="SecuredBasicHttp" >
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="YourService">
<endpoint address="http://localhost:8000/MyService"
binding="basicHttpBinding"
bindingConfiguration="SecuredBasicHttp"
contract="IYourService" />
</service>
</services>
And you need to apply the same settings on the client side:
<bindings>
<basicHttpBinding>
<binding name="SecuredBasicHttp" >
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8000/MyService"
binding="basicHttpBinding"
bindingConfiguration="SecuredBasicHttp"
contract="IYourService" />
</client>
Now your server and client agree on the security - on the client, you'd then specify the user name and password to use like this:
YourServiceClient client = new YourServiceClient();
client.ClientCredentials.UserName.UserName = "your user name";
client.ClientCredentials.UserName.Password = "top$secret";
On the server side, you'll need to set up how these user credentials are being validated - typically either against a Windows domain (Active Directory), or against the ASP.NET membership provider model. In any case, if the user credentials cannot be verified against that store you define, the call will be rejected.
Hope this helps a bit - security is a big topic in WCF and has lots and lots of options - it can be a bit daunting, but in the end, usually it does make sense! :-)
Marc
you can pass in some sort of authentication object and encrypt it at the message level with WCF. C# aspects (http://www.postsharp.org/) can then be used to avoid redundant logic. Its a very clean way of handling it.

Enable SSL for my WCF service

I have a WCF service that uses basicHttpbinding in development.
Now in product we want to use SSL, what changes do I have to make to force SSL connections only?
This page on MSDN explains WCF Binding Security.
http://msdn.microsoft.com/en-us/library/ms729700.aspx
The BasicHttpBinding class is
primarily used to interoperate with
existing Web services, and many of
those services are hosted by Internet
Information Services (IIS).
Consequently, the transport security
for this binding is designed for
seamless interoperation with IIS
sites. This is done by setting the
security mode to Transport and then
setting the client credential type.
The credential type values correspond
to IIS directory security mechanisms.
The following code shows the mode
being set and the credential type set
to Windows. You can use this
configuration when both client and
server are on the same Windows domain.
C#
BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = BasicHttpSecurityMode.Transport ;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Or, in configuration:
<bindings>
<basicHttpBinding>
<binding name="SecurityByTransport">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
To enable ssl, without a login, set clientCredentialType to "None".
Options for security mode are:
None, Transport, Message, TransportWithMessageCredential and TransportCredentialOnly
You can find more details at: http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode.aspx
I just faced the same problem and found this MSDN article:
How to: Configure an IIS-hosted WCF service with SSL
At the end of the article you will find the xml configuration of the WebConfig file.
The solution worked just fine for me. One more thing to say, keep in mind that you need a REAL certificate for your release!
I think that if under your bindings where you have the <Security mode="Transport">, if you would change it to be <security mode="None">, you would be ok.
This is a copy of a code base that I'm working on and I tried that in-code, and it appears to be working.
I get the WSDL at least when I call the service, if that helps at all.
BasicHttpBinding basicBinding = new BasicHttpBinding();
if (RegistryConnectionStringFactory.UseSslForCommunications)
{
basicBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}
else
{
basicBinding.Security.Mode = BasicHttpSecurityMode.None;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}