implementing Ws-security within WCF proxy - asp.net

I have imported an axis based wsdl into a VS 2008 project as a service reference.
I need to be able to pass security details such as username/password and nonce values to call the axis based service.
I have looked into doing it for wse, which i understand the world hates (no issues there)
I have very little experience of WCF, but have worked how to physically call the endpoint now, thanks to SO, but have no idea how to set up the SoapHeaders as the schema below shows:
<S:Envelope
xmlns:S="http://www.w3.org/2001/12/soap-envelope"
xmlns:ws="http://schemas.xmlsoap.org/ws/2002/04/secext">
<S:Header>
<ws:Security>
<ws:UsernameToken>
<ws:Username>aarons</ws:Username>
<ws:Password>snoraa</ws:Password>
</ws:UsernameToken>
</wsse:Security>
•••
</S:Header>
•••
</S:Envelope>
Any help much appreciated
Thanks, Mark

In order to call these kind of services, you will typically use either basicHttpBinding (that's SOAP 1.1 without WS-* implementations) or then wsHttpBinding (SOAP 1.2, with WS-* implementations).
The main issue will be getting all the security parameters right. I have a similar web service (Java-based) that I need to call - here's my settings and code:
app./web.config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="SoapWithAuth" useDefaultWebProxy="false">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="SoapWithAuth"
address="http://yourserver:port/YourService"
binding="basicHttpBinding"
bindingConfiguration="SoapWithAuth"
contract="IYourService" />
</client>
</system.serviceModel>
and then in your client's code when calling the service, you need this snippet of code:
IYourServiceClient client = new IYourServiceClient();
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "top-secret";
Does that help at all?

The WCF client proxy doesn't support the password digest option. The only way to do this is to build the UsernameToken yourself and then inject it into the SOAP headers before the message is sent.
I had a similar problem which is described here, which should be enough to help you solve your same issue.
I ended up using the old WSE3.0 library for the UsernameToken, rather than coding the hashing algorithm myself and then using a custom behavior to alter the SOAP headers.

Related

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).

WCF endpoint only on localhost? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Restricting WCF Service access to only localhost
I have a WCF method set up for a .NET project.
I can enable the endpoint to work over https and / or http.
However, I only want the HTTP version (bindingConfiguration="webBinding") to work on localhost. Is there a way to restrict this in the web.config?
I had very limited success setting <endpoint address="localhost/"myproj/mysvc.svc" /> but ultimately didnt work.
Source: Configure WCF for LOCALHOST-only listening
Try to set the BasicHttpBinding.HostNameComparisonMode Property to HostNameComparisonMode.Exact.
or in config file..
<bindings>
<basicHttpBinding>
<binding name="Binding1"
hostNameComparisonMode ="Exact">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
But better is to use the named pipe binding, which should support whatever message exchange pattern you are using (it supports request-response, as well as the same concurrency and session state modes that WS supports).
From the section of MSDN titled "Choosing a Transport"
Hope this help..

Forming an HTTP request for a SOAP web service

I trying to acces this SOAP Web Service (http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc) and I also have its WSDL files available
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?wsdl
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?wsdl=wsdl0
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?xsd=xsd0
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?xsd=xsd1
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?xsd=xsd2
http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc?xsd=xsd3
But I'm never worked with soap and I'm not finding the WSDL files clear enough.
What I'm trying to do is query the service for the different operations available, for example the ListaMinistros operation that takes a parameter actualizacion that is a date in the format yyyymmdd.
I have tried every possible combination to contact the service but it responds with a Endpoint not found response.
If you could provide me with an example of the SOAP XML it would be great as almost all of the other available operations are the same so I cold see how to do it myself.
Thanks in advance
========
EDIT
I have set up the WSDL reference in a C# project with visual studio to se what kind of request it makes
the config file it comes up with its the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="Rest">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint
binding="customBinding" bindingConfiguration="Rest" contract="SCJN.Tematica"
name="Rest" />
</client>
</system.serviceModel>
But it doesent includes the address for the endpoint, so I modified the endpoint to look like this:
<endpoint address="http://iberius.scjn.gob.mx:8080/Mobile/Tematica.svc"
binding="customBinding" bindingConfiguration="Rest" contract="SCJN.Tematica"
name="Rest" />
But the service responds with a endpoint not found.
So is there a way to find out wich address to call.
Also the WSDL does not list SOAPAction attributes but rather wsaw:Action in the operations supported, wich is translated in my .NET code to the following
[System.ServiceModel.OperationContractAttribute(Action="urn:Tematica/ListaMinistros", ReplyAction="urn:Tematica/ListaMinistrosResponse")]
ConsoleApplication2.SCJN.Ministro[] ListaMinistros(string actualizacion);
Try soapUI.org, it's a feature rich opensource/commercial web service explorer. You can feed in the WSDL and it will automatically create SOAP request stubs, which can be send to the endpoints named in the WSDL. Even the HTTP headers can be made visible.
You can download webservice studio.
Its free program and it will show you a soap message. Search in the google.
These articles [1][2] describes wsdl and soap.
The better options is to use the wsdl2java tool available with the platform. If there is no such thing available then you can use some other framework like Axis2 and examine the request and response messages for each and every operation.
[1] http://wso2.org/library/2873
[2] http://wso2.org/library/2935

WCF Service support file jsdebug fails to load

I have a WCF service that gets called from client side JavaScript. The call fails with a Service is null JavaScript error. WebDevelopment helper trace shows that the calls to load the jsdebug support file results in a 404 (file not found) error.
Restarting IIS or clearing out the Temp ASP.Net files or setting batch="false" on the compilation tag in web.config does not resolve the problem
From the browser
https://Myserver/MyApp/Services/MyService.svc displays the service metadata
however
https://Myserver/MyApp/Services/MyService.svc/jsdebug results in a 404.
The issue seems to be with the https protocol. With http /jsdebug downloads the supporting JS file.
Any ideas?
TIA
Figured it out!
Here is the services configuration section from web.config
Look at the bindingConfiguration attribute on the endpoint. The value "webBinding" points to the binding name="webBinding" tag in the bindings and that is what tells the service to use Transport level security it HTTPS. In my case the attribute value was empty causing the webservice request to the /js or /jsdebug file over HTTPS to fail and throw a 404 error.
<services>
<service name="MyService">
<endpoint address="" behaviorConfiguration="MyServiceAspNetAjaxBehavior" binding="webHttpBinding" bindingConfiguration="webBinding" contract="Services.MyService" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="webBinding">
<security mode="Transport">
</security>
</binding>
</webHttpBinding>
</bindings>
Note that the bindingConfiguration attribute should be empty ("") if the service is accessed via http instead of https (when testing on local machine with no certs)
Hope this helps someone.
If you still get the same error after all your possible work done. Just add a "AJAX Enabled WCF-Service".
For me the issue was the following; we added MVC to a solution with routing. Our WCF services were not being ignored. I resolved this by adding the following rule (where "WCF" is the folder we keep our services in).
routes.IgnoreRoute("WCF/{*pathInfo}");
Hope that saves somebody a few hours.

Resources