I am developing a software that, apart from having its own BackEnd, has a module that must be integrated with an external web service. The external web service is as follows: https://e-seida.sunat.gob.pe/ol-ad-itseida-ws/ReceptorService.htm?wsdl
In the project (.NET C#), it can be easily referenced and I can see all the contract and methods that the external web service has exposed. I can do the same thing from the SOAP UI when I test successfully hitting the web service.
As you can see in the image, when you hit the web service, you have communication and a response from the SOAP UI. Now this does not happen in my project because although it is true the web service could be referenced, but until now I am still looking for the way or way to send the security data (UsernameToken) to the web service, honestly it is somewhat frustrating because I've been having this same problem for several days now and I can't give you a solution and researching I have found some possible solutions and none of them have really helped me.
I understand that the Header of this web service contains WS-Security type security, which is basically an open standard approved by OASIS to provide transport layer security (through SSL/TLS from HTTP).
I have also investigated some forums where they indicate that creating the following interfaces/classes (MessageHeader, IClientMessageInspector, IEndpointBehavior) but implementing that does not solve it either.
What can I try to resolve this?
Using wsdl.exe /l:CS /serverInterface, I generated a C# interface from a WDSL document. I've implemented that interface on a WCF class. The resulting service runs locally:
http://localhost:51454/TapasSim.svc
This shows the default site. The problem appears when I append ?wsdl to the URL:
http://localhost:51454/TapasSim.svc?wsdl
Unlike what I expected, this link does not return a WDSL document! Instead, it points back to the exact web page you get without the ?wsdl. As a result, I cannot reference the web service. If I run svcutil.exe it gives this error:
If you were trying to generate a client, this could be because the
metadata documents did not contain any valid contracts or services or
because all contracts/services were discovered to exist in /reference
assemblies. Verify that you passed all the metadata documents to the
tool.
But I would expect that error to have the same cause as the lack of reply to ?wsdl.
What could cause a WCF .svc service not to generate WSDL?
As it turns out, the problem was mixing two technologies. wdsl.exe belongs to the older "Web References" that predate WCF. The newer tool svcutil.exe is meant for generating WCF "Service Reference" interfaces.
So what happened was that WCF looked for [ServiceContract] and [OperationContract] attributes. When it couldn't find any, it silently did nothing.
The silent suppression of this condition is annoying, to say the least. An error like No service with [ServiceContract] attribute found would really have helped.
Note that you can manually add [ServiceContract], but that will leave you with half "Service Reference" half "Web Reference". The result probably will not work.
I had a problem with getting the WSDL via the IE window provided by starting the debugging session. I had to use a separate window, ensuring I put the HTTPS in the URL.
We are hosting our services on 443 (SSL). When you start up the debugger, even though the IE windows shows http: (80), it was listening for traffic on 443. FYI, this is controlled via the project level setting SSL Enabled
With a reference to my previous question, I would like to know how would I extract information of a WCF service from a client application to know what methods/types are exposed if the service exposes only one endpoint that uses webHttpBinding?
Just to summarize, in my previous question, I came to know that an endpoint using webHttpBinding does not get exposed in the generated WSDL because it would be a JSON endpoint and is just not compatible.
WebHttpBinding is a REST-based binding - REST does not expose metadata like WSDL/XSD contrary to SOAP.
There's no way to extract the metadata from a REST endpoint at this time. There are some efforts under way to establish a similar construct for REST called WADL (Web Application Description Language) - but that's nowhere near standardized yet.
For now, with REST endpoints, you have to either figure it out yourself, or you need to have some documentation provided by the service provider on e.g. a static HTML page or something.
.NET 4 does provide some level of an automatically generated help page - see this blog post or the MSDN docs for more info. But it's still nowhere near as formalized and machine-interpretable as WSDL/XSD.
I wonder why the REST samples tell you to expose a MEX endpoint at all. It is not needed and here is how to cleanly remove it:
Remove MEX endpoint from the service section of the config file.
Remove service metadata enabled line in the service behaviour section of the config file.
Edit the Visual Studio project (assuming it's a WCF service library) and remove the line:
<StartArguments>/client:"WcfTestClient.exe"</StartArguments>
If you have other non-rest services you will want to leave the last 2 parts present. You must remove the WCF Client when disabling MEX otherwise it will complain during debugging if it cannot enumerate any services in the project (regardless whether they have any useful metadata or not).
What do I need to call a web service over https in C#?
Do I need to get the certificate form the site? How do I use this to call the web service?
There's nothing special or different for calling a web service over https than over http. You generate a client proxy from the WSDL using either svcutil.exe (or Add Service Reference in VS) or wsdl.exe and invoke the method. The lower level classes HttpWebRequest and HttpWebResponse will eventually take care of the actual call and certificates but it should be transparent for your code. Of course the server hosting the web service needs to provide a valid certificate.
I take that you are using Visual Studio to create your projects, if you are it is pretty easy to do. I take that you have the url for the web service that you would like to connect to and it starts with HTTPS.
In your project in the solution explorer (assuming you using Visual Studio), you should see a node saying "References" and another one saying "Web References". Right click on the "Web Reference" and then basically follow the wizard. It is pretty straight forward. You can spec your own Namespace. I usually use the format SomethingAPI. Then use the API as you would like any other object in your project. You will get the intellisense and all.
There might occur known problems with some certificates though. See http://support.microsoft.com/kb/823177/en-us
Do you have a client certificate that has been supplied by the provider of the web service?
If so, there are various different ways of doing this depending upon which version of .NET you are using. What version are you using, and are you limited in how you can generate your client proxy classes?
Disclaimer: I've tried Googling for something that will do what I want, but no luck there. I'm hoping someone here might be able to lend a hand.
Background
I have a .NET class library that accesses a secure web service with the WSE 2.0 library. The web service provides a front-end to a central database (it's actually part of a data-sharing network spanning multiple customers) and the class library provides a simple wrapper around the web service calls to make it accessible from a legacy VB6 application. The legacy application uses the class library to retrieve and publish information to the web service. Currently, the application and class library DLL are both installed client-side on multiple workstations.
The Problem
The catch is that the web service we are accessing uses HTTPS and a valid X509 client certificate needs to be presented to the web service in order to access it. Since all of our components live on the client machine, this has led to deployment problems. For example, we have to download and install per-user certificates on each client machine, one for each user who might need to access the web service through our application. What's more, the web server itself must be accessed through a VPN (OpenVPN in particular), which means a VPN client has to be installed and configured on every client machine. It is a major pain (some of our customers have dozens of workstations).
The Proposed Solution
The proposed solution is to move all of this logic to a central server on the customer site. In this scenario, our legacy application would communicate with a local server, which will then go off and forward requests to the real web service. In addition, all of the X509 certificates would be installed on the server, instead of on each individual client computer, as part of the effort to simplify and centralize deployment.
So far, we've come up with three options:
Find a ready-made SOAP proxy server which can take incoming HTTP-based SOAP requests, modify the Host header and routing-related parts of the SOAP message (so they are pointing to the real web server), open an SSL connection to the real web server, present the correct client certificate to the server (based on a username-to-certificate mapping), forward the modified request, read the response, convert it back to plaintext, and send it back to the client.
Write a proxy server by hand that does everything I just mentioned.
Think of completely different and hopefully better way to solve this problem.
Rationale
The rationale for trying to find and/or write a SOAP proxy server is that our existing .NET wrapper library wouldn't have to be modified at all. We would simply point it at the proxy server instead of the real web service endpoint, using a plain HTTP connection instead of HTTPS. The proxy server will handle the request, modify it to so that the real web service will accept it (i.e. things like changing the SOAPAction header so that it is correct), handle the SSL/certificate handshake, and send the raw response data back to the client.
However, this sounds like an awful hack to me me at best. So, what our my options here?
Do I bite the bullet and write my own HTTP/SSL/SOAP/X509 aware proxy server to do all this?
Or...is there a ready-made solution with an extensible enough API that I can easily make it do what I want
Or...should I take a completely different approach?
The key issues we are trying to solve are (a) centralizing where certificates are stored to simplify installation and management of certificates and (b) setting things up so that the VPN connection to the web server only occurs from a single machine, instead of needing every client to have VPN client software installed.
Note we do not control the web server that is hosting the web service.
EDIT: To clarify, I have already implemented a (rather crappy) proxy server in C# that does meet the requirements, but something feels fundamentally wrong to me about this whole approach to the problem. So, ultimately, I am looking either for reassurance that I am on the right track, or helpful advice telling me I'm going about this the completely wrong way, and any tips for doing it a better way (if there is one, which I suspect there is).
Apache Camel would fit the bill perfectly. Camel is a lightweight framework for doing exactly this kind of application integration. I've used it to do some similar http proxying in the past.
Camel uses a very expressive DSL for defining routes between endpoint. In your case you want to stand up a server that is visible to all the client machines at your customer site and whatever requests it receives you want to route 'from' this endpoint 'to' your secure endpoint via https.
You'll need to create a simple class that defines the route. It should extend RouteBuilder and override the configure method
public class WebServiceProxy extends RouteBuilder
{
public void configure()
{
from("jetty:http://0.0.0.0:8080/myServicePath")
.to("https://mysecureserver/myServicePath");
}
}
Add this to a Camel context and you'll be good to go.
CamelContext context = new DefaultCamelContext();
context.addRoute(new WebServiceProxy());
context.start();
This route will create a webserver using jetty bound to 8080 on all local interfaces. Any requests sent to /myServicePath will get routed directly to your webservice defined by the uri https://mysecureserver/myServicePath. You define the endpoints using simple uris and the dsl and camel takes care of the heavy lifting.
You may need to configure a keystore with your certs in in and make it available to the http component. Post again if you've trouble here ;)
I'd read the camel docs for the http component for more details, check the unit tests for the project too as they are chock full of examples and best practices.
HTH.
FYI: To have the http component use your keystore, you'll need to set the following properties
System.setProperty("javax.net.ssl.trustStore", "path/to/keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "keystore-password");
You should look into WCF, which supports the WS-Addressing protocol. I believe I've seen articles (in MSDN, I think) on writing routers using WCF.
You should also get rid of WSE 2.0 as soon as possible. It's very badly obsolete (having been replaced by WSE 3.0, which is also obsolete). All of its functions have been superceded by WCF.
I believe an ESB (Enterprise Service Bus) could be a viable, robust solution to your problem. There is an open source ESB called Mule, which I've never used. I did mess around with ALSB (AquaLogic Service Bus) a while back, but it would be expensive for what you are describing. Anyway, the thing that you would want to look at in particular is the routing. I'm not sure it would be a simple plug 'n play, but it is indeed another option.
You can also do this with Microsoft ISA Server, a commercial Proxy/Cache server. It will do many of the things you need out of the box. For anything that is not possible out of the box, you can write an extension to the server to get it done.
ISA Server is not free.
ISA is now being renamed to "Microsoft Forefront Threat Management Gateway".
It is much more than a web proxy server, though - it has support for many protocols and
lots of features. Maybe more than you need.
There is a service virtualization tool from Microsoft available on Codeplex called the Managed Service Engine which is intended to decouple the client from the web service implementation. It might fill the bill or give you a running start. I haven't really investigated it thoroughly, just skimmed an article in MSDN and your description reminded me of it.
http://www.codeplex.com/servicesengine
http://msdn.microsoft.com/en-us/magazine/dd727511.aspx
Your security model doesn't make sense to me. What is the purpose of using HTTPS? Usually it is to authenticate the service to the clients. In that case, why does the server need to keep the clients' certificates? It is the clients who should be keeping the server's X509 Certificate.
Why do you need to go through VPN? If you need to authenticate clients, there are better ways to do that. You can either enable mutual authentication in SSL, or use XML-Security and possibly WS-Security to secure the service at the SOAP level. Even if you do use SSL to authenticate clients, you still shouldn't keep all the client certificates on the server, but rather use PKI and verify the client certificates to a trusted root.
Finally, specifically for your proposed proxy-based solution, I don't see why you need anything SOAP-specific. Don't you just need a web server that can forward any HTTP request to a remote HTTPS server? I don't know how to do this offhand, but I'd be investigating the likes of Apache and IIS...