is wcf ClientCredential username and password secure? - wcf-security

I have a wcf and upload it on my host on a web farms and use this secure mode:
<basicHttpBinding>
<binding name="BasicHttpBinding_IHelinusSMSService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType= "Ntlm" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
in my client if I want to use this wcf service I must to add a my domain user name and pass.
my client codes are;
using (var myService = new MyServiceClient())
{
myService.ClientCredentials.Windows.ClientCredential.UserName = "abcd";
myService.ClientCredentials.Windows.ClientCredential.Password = "123";
.
.
.
}
if I do not use my domain user name and password I will get this error:
"The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The
authentication header received from the server was 'Negotiate,NTLM'."
I want to know is it secure to use my username and pass word like this and
it is hackable and is secure or not ?
"because if some one can hack it it can access to all my domain host and files and ....
and I will f...up"

Yes. When you providing username and password, you must use transport security. Data is protected by the transport layer (https/ssl).

Related

Pass message headers on WCF via netTcpBinding

After banging my head for a day I'm asking for help. I have a Web Forms application with WCF service hosting at the same machine. The WCF service has methods with some sort of custom permissions (for instance, only "admin" can set passwords for users).
Web forms app uses Forms Authentication so I have HttpContext.Current.User with all the roles this uses has. So I used an AuthCookie to pass the object via HttpRequestMessageProperty and read it like this:
HttpRequestMessageProperty property =
OperationContext.Current.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
With basicHttpBinding that worked fine. But then I needed to implement net.tcp protocol so the HttpRequestMessageProperty doesn't work anymore. I've tried to add it by MessageHeader but that doesn't work either.
OperationContext.Current.IncomingMessagePropertieshas got none of my headers...
So how can I pass the user roles list to my WCF? I am using Windows security like this but I need to pass roles from HttpContext.Current.User:
<netTcpBinding>
<binding transactionFlow="True">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
OK so I found the working way for transferring the role info. Although this is still unclear why standard ways didn't work for me here is the right one (thanks to Guy Burstein):
Client:
MessageHeader<string> header = new MessageHeader<string>(roleData);
MessageHeader untypedHeader = header.GetUntypedHeader(ProjectParam.Role, "justASampleNamespace");
OperationContext.Current.OutgoingMessageHeaders.Add(untypedHeader);
WCF:
string roles = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(ProjectParam.Role, "justASampleNamespace");
if(roles.Contains(ProjectParam.AdminLoginID))
{
//Now business logic comes
}
ProjectParam.Role is just an internal constant utilized for key and the second parameter is a sample string (MSDN says the "namespace")

Could not find a base address that matches scheme https for the endpoint

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="DataSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport" />
</binding>
</basicHttpBinding>
<customBinding>
<binding name="CustomBinding_GetData">
<binaryMessageEncoding />
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://localhost/MyApp.Web/Webservice/Data.asmx"
binding="basicHttpBinding" bindingConfiguration="DataSoap"
contract="ServiceReference1.DataSoap" name="DataSoap" />
<endpoint address="https://localhost/MyApp.Web/Webservice/GetData.svc"
binding="customBinding" bindingConfiguration="CustomBinding_GetData"
contract="GetData.GetData" name="CustomBinding_GetData" />
</client>
</system.serviceModel>
Hello every one, above is my silverlight applications ServiceReferences.ClientConfig file. The site is configured to be accessed over https. From the above file, i would imagine i have everything configured correctly. I can browser to my service from local development environment successfully but after deploying the application in my QA environment, browing to the service gives me the error below.
Could not find a base address that matches scheme https for the endpoint with binding CustomBinding. Registered base address schemes are [http].
Any i dea why http is still being picked as the registered base address schemes only QA but not in my local development environment?.
EDIT:
#Brian, thanks for the reply, let me give you more information just in case it gives a much clear picture.
The site is configured for SSL, but the SSL certificate is installed on a load balancer which i have no access to.
Now from the error message, it would seem like i have to configure Host Headers and Secure Site Bindings in IIS, but can i really do this from IIS when the SSL certificate is installed and managed from the load balancer?
IT looks like the https binding are what is missing because i can reproduce the exact same error message from my development machine if i temporarily remove the https binding i created following this link.
http://weblogs.asp.net/scottgu/tip-trick-enabling-ssl-on-iis7-using-self-signed-certificates.
So would i be right to think that i need that https binding on the load balancer rather than in IIS because the site has no SSL certificate of its own in IIS?
I ran into this problem. Basically, the URL identity associated with the certificate doesn't match the URL of the website from which it comes ... at least that was my problem.
I was able to work around this client-side security check by specifically setting (in code) the System.ServiceModel.EndPointIdentity to the URL I was connecting to.
There's a CreateDNSIdentity() function to which you give the URL of the website you're hitting.
Here's a link to the MS documentation: http://msdn.microsoft.com/en-us/library/system.servicemodel.endpointidentity.creatednsidentity(v=vs.110).aspx
I'm not sure how you'd configure this without using code.
String sFullURL = "http://MyDNSServer:8001/SomeService"
String sDNS = "MyDNSServer";
System.ServiceModel.EndpointAddress Endpoint;
System.ServiceModel.EndpointIdentity Identity = default (System.ServiceModel.EndpointIdentity);
Identity = System.ServiceModel.EndpointIdentity.CreateDnsIdentity(sDNS);
EndPoint = new System.ServiceModel.EndpointAddress(new Uri(sFullURL), Identity);
UPDATE
OK, so imagine you had a web service and the public address for this web service was IP https:// 10.134.116.161:8001/MyService. The certificate below would pass the client-side cert verification check and you would not get an error. But if this certificate shown in the picture below is deployed on public URL https:// XZYCorp:8001/MyService, you'll get that error. So you either need to override the client side cert verification check or change the cert on the LB.

401 Client 'Negotiate', Server 'Negotiate,NTLM' When Calling WCF Server to Server

Ok, I've read every thread & question I can find with this error and surprisingly have not found a solution. I'm trying to require Windows authentication on my IIS hosted WCF service (.NET 4.0) which, until now, has been optional. I have had a Windows authentication enabled endpoint available on the server for a while with several remote applications successfully using it. I'm now trying to switch our web applications and other server apps that use the WCF service over to this secured endpoint by giving them the exact same client configuration as the working remote clients, but the server apps are receiving a 401 with the message:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.]
I have Anonymous and Windows authentication enabled for the WCF hosting site. The web application I've started with is hosted on a different server than the WCF service and is running on ASP.NET 2.0 and Windows Server 2008 R2 Enterprise. I have both created a client behavior with allowNtlm and set the NetworkSecurity: LAN Manager authentication level to Send LM & NTLM... on the client end. On the hosting end, it is set to Send NTLMv2 Response Only...I don't know if that affects how the server/service handles authentication. I've also tried setting allowedImpersonationLevel to Impersonation on the client which, thankfully, didn't work (because impersonation shouldn't be necessary). We seem to get the same result for a Windows service and console app running on the same server as the web app.
Here is my server config:
<binding name="WindowsSecuredBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
...
<service behaviorConfiguration="OMWebServices.QueueServiceBehavior"
name="OMWebServices.QueueService">
<endpoint address="" binding="basicHttpBinding" name="QueueEndpoint"
bindingName="" contract="OMWebServices.IQueueService" />
<endpoint binding="basicHttpBinding" bindingConfiguration="WindowsSecuredBinding"
name="QueueSecuredEndpoint" contract="OMWebServices.IQueueService" />
<endpoint address="mex" binding="mexHttpBinding" name="QueueMetadataEndpoint"
contract="IMetadataExchange" />
</service>
...
<behavior name="OMWebServices.QueueServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
And here is the client config:
<endpoint address="https://.../QueueService.svc" binding="basicHttpBinding" bindingConfiguration="QueueSecuredEndpoint" behaviorConfiguration="OMServiceBehavior" contract="OMQueueService.IQueueService" name="QueueSecuredEndpoint" />
<binding name="QueueSecuredEndpoint" 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="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
....
<!-- The behavior I tried that didn't make a difference -->
<behavior name="OMServiceBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation" allowNtlm="True"/>
</clientCredentials>
</behavior>
My first question is, what is this error message really telling me? It says the client scheme is Negotiate and the server's responding with Negotiate,NTLM. If the server offers Negotiate and and client is using Negotiate, what's the problem?
Second question is, obviously, what's wrong and how do I make it work?
EDIT
Well this is stupid. The problem seems to be there are no credentials being passed. Way back when the web site was in development, I started writing code to explicitly set the credentials in code, but in the process, found that it was already working without explicitly setting them. So that code has remained commented out. This was running on IIS 6. Now running on IIS 7, it seems to only work if I explicitly set the credentials in my code. Can I get it automatically using the w3wp process' account?
To answer the first question, the error message is telling me exactly what it says; I'm not authorized. The line telling me the client authentication scheme and server header is just extra info, not an indication of a conflict. It's actually confirmation that the configuration is correct.
In the staging environment, the problem is being masked because the WCF service and the web application are hosted on the same server. The problem is the web app's site is configured to use IUSR (or IUSR_Server), a local account, for anonymous users by default. This is the user that is being passed (which I believe is equal to CredentialCache.DefaultNetworkCredentials). When they're on different servers, WCF on server 2 obviously can't authenticate a server 1 user. The solution is in IIS, right click Anonymous Authentication > Edit...> check Application pool identity (which is a domain account in my case) or enter a domain account for Specific user.
It just means your client and server are using different authentication scheme.
In your client config, you've set up a
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
and a message security
<message clientCredentialType="UserName" algorithmSuite="Default" />
So you might be getting errors because of this. These links might help you.
Ch. 7 Message and Transport Security
security of basicHttpBinding
Also, in your client config
<endpoint address="https://.../QueueService.svc" binding="basicHttpBinding" bindingConfiguration="QueueSecuredEndpoint" behaviorConfiguration="OMSServiceBehavior" contract="OMQueueService.IQueueService" name="QueueSecuredEndpoint" />
Change the behaviorConfiguration from behaviorConfiguration="OMSServiceBehavior"
to behaviorConfiguration="OMWebServices.QueueServiceBehavior"
Also did you try to use TransportCredentialOnly? If not, it might be good to try this http://msdn.microsoft.com/en-us/library/ff648505.aspx
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
My problem with this error was not config related but specific to
a WCF Service calling another on the same machine.
Because this affected a fleet of new servers that were partly provisioned through a C# console app, I solved it by executing code like this through the affected servers:
const string userRoot = "HKEY_LOCAL_MACHINE";
const string subkey = #"SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0";
const string keyName = userRoot + #"\" + subkey;
Registry.SetValue(keyName, "BackConnectionHostNames", hostnamesOnServer.ToArray(), RegistryValueKind.MultiString);
Reboot wasn't required on Windows Server 2012.
This can also apparently be an issue with your credentials not being passed correctly. I needed:
Client.ClientCredentials.Windows.ClientCredential.UserName = User;
Client.ClientCredentials.Windows.ClientCredential.Password = Password;
Instead of:
Client.ClientCredentials.UserName.UserName = User;
Client.ClientCredentials.UserName.Password = Password;
(Oddly, the second way worked once in a while for me, but not always.)
I was having exactly the same issue reported here. The AD account being used for credentials had had the password changed. Once I used the new password it started working.
This error is very misleading for an incorrect password situation.

Consume SOAP based web service with https

I'm integrating af ASP.NET application, which must consume a 3rd party SOAP web service, which can only be accessed by HTTPS. I add a service reference i VS2012 with the HTTPS URL and VS find the service just fine. But when I use the proxy that VS create to use the web service, it uses regular HTTP.
I suspect that I should alter the binding in the web.config, but I can't seem to figure out what to do. How do I set up the web service to use HTTPS?
You need to make sure that the binding the client uses has security mode="Transport" set up (and that the client binding matches the server binding), something like this for example:
<binding name="yourClientSecureBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
and that the client indeed accesses the httpS:// address of the web service:
<client>
<endpoint bindingConfiguration="yourClientSecureBinding"
address="https://..."
... />
</client>
You are not providing any code, so for starters have a look at these posts: here (Microsoft developer network - Transport Security with an Anonymous Client) and here (Https with BasicHTTPBinding).

Share ASP.NET Session Id between WCF and a Silverlight Http client

I have a WCF service configured to use ASP.NET session state. I have tested this WCF service with a WPF client and the session state is maintained across the different web requests.
Now I am trying to use this same WCF service from a Silverlight app which uses the new Http stack independent from the browser. I need to use this stack in order to be able to understand our WCF service faults. My problem is that in this case we are not able to read from the responses the Set-Cookie header with the ASP.NET_SessionId cookie or set the Cookie header in the requests.
This is the binding from the Silverligth application:
<customBinding>
<binding name="customHttpBinding_IBasoaWebService" sendTimeout="01:00:00">
<binaryMessageEncoding />
<httpCookieContainer />
<httpTransport maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
And this is the binding of the WCF service:
<basicHttpBinding>
<binding name="basicHTTP" closeTimeout="01:00:00" openTimeout="01:00:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
receiveTimeout="01:00:00" sendTimeout="01:00:00" allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</basicHttpBinding>
In the Silverlight application we are using this code to read the Set-Cookie header in the response:
IHttpCookieContainerManager cookieManager = channel.GetProperty<IHttpCookieContainerManager>();
if (cookieManager.CookieContainer == null)
cookieManager.CookieContainer = new CookieContainer();
Uri applicationUri = new Uri(Application.Current.Host.Source, "../");
string cookieString = cookieManager.CookieContainer.GetCookieHeader(applicationUri);
ParseCookieString(cookieString);
And this is the code to set the ASP.NET Session ID cookie in the request:
IHttpCookieContainerManager cookieManager = channel.GetProperty<IHttpCookieContainerManager>();
if (cookieManager.CookieContainer == null)
cookieManager.CookieContainer = new CookieContainer();
Uri applicationUri = new Uri(Application.Current.Host.Source, "../");
Cookie cookie = new Cookie("ASP.NET_SessionId", aspNetSessionId);
cookieManager.CookieContainer.Add(applicationUri, cookie);
Checking through Fiddler the messages which are exchanged I see that the WCF service sends correctly the Set-Cookie header in the first response, but the Silverlight is not able to read it. I have also tried to set the Cookie header in the request through the CookieContainer class, but with no luck. I cannot see it in Fiddler.
Coould someone give me an advice about what I must be doing wrong?
Many thanks in advance.
Jose Antonio Arroba
In a web application, I use URI to set the SessionID. (I think it's possible with a WCF service)
In the web.config of your service, define :
<system.web>
<sessionState cookieless="true"></sessionState>
</system.web>
or
<sessionState cookieless="UseUri"></sessionState>
The sessionId appaears like this :
http://localhost:51358/(S(1wnqb23d2qe4blfxzukligdo))/default.aspx
You can get and set the SessionID in the URI.
Finally I have been able to find a workaround to solve this problem.
The reason why the Cookie header was not sent with the requests was that I was setting a bad Uri in the Cookie object. If I am trying to connect to http://localhost:8080/Service, it seems taht the correct Uri value to provide is http://localhost:8080 and not http://localhost:8080/Service.
However I am still wondering how to read the Set-Cookie sent by the server. My workaround consist on sending the ASP.NET Session ID also in a custom SOAP header and read it in the client, which is IMHO rather redundant. But it works.

Resources