I have a WCF webservice that can be accessed via a http endpoint. Now, this service shall be published with a load balancer via https. Clients are created in .Net via svcutil.exe but the WSDL is also needed for a Java client.
What I understand is:
Internally the webservice is a http service and nothing needs to be changed. The address is http://myserver.com/example.svc with WSDL ..?wsdl
Externally the service has to show up as a https service with address https://loadbalancer.com/example.svc and WSDL ..?wsdl
From other posts I have learned that the load balancer problem can be solved with following behaviour configuration:
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<!-- Use your own port numbers -->
<add scheme="http" port="81" />
<add scheme="https" port="444" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
Using this workaround I get both URLs resolved to the services help page, but calling
https://loadbalancer.com/example.svc the page leads me to http://loadbalancer.com/example.svc?wsdl. When I replace the http by https I can load the wsdl but it has all internal links as http and not https.
Trying to switch httpsGetEnabled="true" leads me to a lot of https related issues and I don't know if this can help me as my server itself only knows http.
So, my problem is the https for the load balanced URL. Can I tell WCF that it shall show https in the WSDL meta data instead of http and how can I do this?
I have had this issue before and the fix pretty much was overriding the SoapExtensionReflector method name: ReflectDescription.
using System.Web.Services.Description;
namespace LoadBalancer
{
public class HttpsSoapExtensionReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
//no-op
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
SoapAddressBinding binding = extension as SoapAddressBinding;
if (null != binding)
{
binding.Location = binding.Location.Replace("http://", "https://");//Updating the soap address binding location to use https
}
}
}
}
}
}
}
Once you create the above class into a new or an existing dll project (In my example the dll name is LoadBalancer) you just need to invoke our new extension from the server web config like:
<webServices>
<soapExtensionReflectorTypes>
<add type="LoadBalancer.HttpsSoapExtensionReflector, LoadBalancer"/>
</soapExtensionReflectorTypes>
</webServices>
If it is under LoadBalancer then it will go ahead and modify the binding location and it will be generate the WSDL with the HTTPS url.
Tested on SoapUI and from Visual Studio adding service references (app.config will reflect https).
Thanks
no, no way to tell the WCF to show the https in WSDL meta data instead of http.
our solution is, create both http and https endpointbindings, check if the incoming request is http or https, the incoming request type determine which endpointbindings will be used.
Related
I have a WCF Service that Hosted in Windows Service
It uses NetTCPBinding and i could connect, i want to implement new Silverlight client to access the service
i have walk through the normal way to add service reference, and it was added with Empty "ServiceReferences.ClientConfig"
so i have viewed some threads and topics, at last i have write my configuration manually for the service
when i try to connect it show's this exception
Could not connect to net.tcp://localhost:4502/MyService/Service. The connection attempt lasted for a time span of 00:00:02.2111265. TCP error code 10013: An attempt was made to access a socket in a way forbidden by its access permissions.. This could be due to attempting to access a service in a cross-domain way while the service is not configured for cross-domain access. You may need to contact the owner of the service to expose a sockets cross-domain policy over HTTP and host the service in the allowed sockets port range 4502-4534.
i believe that the problem related to ClientAccessPolicy.xml file
after search people say i need to have IIS7 installed and file is accessible through it, i have tried this but i couldn't make it work
but, i have worked on this before, but i was using PollinghttpBinding no NetTCP, and i have created another service contract to return the ClientAccessPolicy file
i have tried to do the same i do before with PollinghttpBinding but i can't write the right Configuration of the Service
My client refuse to use IIS, so could i use this way and what is the right configuration i should use with this service?
this is the configuration i use for my Service
<service behaviorConfiguration="serviceBehavior" name="MyService">
<endpoint address="net.tcp://localhost:4502/MyService/Service" behaviorConfiguration="endpointBehavior" binding="netTcpBinding" bindingConfiguration="netTcpServiceBinding" contract="IMyService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:7000/MyService/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
can anyone give help?
Net.tcp bindings are not supported "out-of-the-box" in Silverlight. That's why the config is empty. But you can use it anyway, by using a customBinding and setting the properties you need. However, I have never tried this fyself.
If this is a cross domain problem, this is nedeed related to the ClientAccessPolicy.xml file.
Normally (as stated many places on various forums), this is solved by putting the file in the root of the site. So if your service runs on "http://localhost/MyService", the file should be put so it's available in "http://lovalhost".
However, without a IIS available, this has to be done another way. You will have to create an endpoint on the root manually in the Windows Service, where this file is available.
This is a normal BasicHttp binding either you use "net.tcp" or "http".
I have done this with success this way:
Policy interface:
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace MyPolicyService
{
[ServiceContract]
public interface IPolicyRetriever
{
[OperationContract]
Stream GetPolicy();
}
}
Policy class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ServiceModel.Web;
namespace MyPolicyService
{
public class PolicyRetrieverBase : IPolicyRetriever
{
public Stream StringToStream(String result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetSilverlightPolicy()
{
string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"" http-methods=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
return StringToStream(result);
}
public Stream GetFlashPolicy()
{
string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
<cross-domain-policy>
<site-control permitted-cross-domain-policies=""all""/>
<allow-access-from domain=""*"" secure=""false"" />
<allow-http-request-headers-from domain=""*"" headers=""*"" secure=""false"" />
</cross-domain-policy>";
return StringToStream(result);
}
}
}
When these classes are created, create the service almost just as you would start the "net.tcp" service, but of course change it to BasicHttpBinding and use some different behaviors and property values related to the BasicHttpBinding (like TransferMode = Buffered etc).
This policy service should, needless to say, be started on the site root (http://localhost).
ID YOU HAVE THE IIS running on this server, do NOT start this policy service because this will take over this address :-)
Hope that gets you moving in the correct-ish direction :-)
We have a service on our 3rd party site which is configured to be invoked on a https (server to firewall and routing everything is configured for https)! Since We are unable to communicate with it due to certificate issue with DataPower on our side, we thought why not test the connectivity on http!
So now they trying to make the WCF Service as http on the same IP and port, they could see the Service not responding to inbound calls and ignoring the http request coming on a https configured IP + port!
I am not sure what can be done to say the .net WCF Service, hey ignore its on http and just get it rolling! They did disable https binding and just try with a http binding!
Any ideas would be great! Thanks!
(P.S. I dont have access to their code or config!)
Is is IIS hosted or self hosted?
If it is hosted in IIS, then IIS needs to have the SSL certificate removed and the configuration set to HTTP instead of HTTPS.
In WCF, you would have to disable Transport security, which is usually in the configuration on the binding, like:
<binding>
<security mode="Transport">
To disable HTTPS you would need to set mode="None" (or something other than Transport).
This worked for me... Adding this to webconfig or appconfig of the project
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
TL;DR version is at the bottom.
I have constructed three WCF web services -- one that's using .NET 4 and two that's using .NET 3.5 -- that is consumed by an Android client. The Android client performs the calls using ksoap2-android. When the services were complete and the client could make all the calls and get all the data from the services, we decided to activate HTTPS communication for the web services. They are hosted on a server running IIS.
I'm not alone on this task. I work full-time with it, mainly the Android client. I have two coworkers, both of which have a lot of other responsibilities. The first is mostly involved in the services and the second is mostly involved in the server.
I've read a lot of guides, blogs and articles on the Internet on how to enable HTTPS for a WCF web service, but still I haven't been able to completely resolve this. For the Android client to be able to consume the client, we are limited to using the basicHttpBinding, since the wsHttpBinding contains some security details that are not supported by Android, or something. I'm not sure, but I read it some forum somewhere. If I'm wrong, I'd happily be corrected!
Okay, so I'll give a short account of what I've done so far:
I've enabled transport security, this is how the binding(s) looks:
<bindings>
<basicHttpBinding>
<binding name="basicHttp" closeTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
I've enabled meta data publishing over HTTPS using this line of code:
<serviceMetadata httpsGetEnabled="true" />
and this:
<endpoint address="" binding="mexHttpsBinding" contract="IMetadataExchange" />
Also, my second coworker has installed a trusted certificate (a real certificate from a CA) on the IIS server and added a https binding on the server.
Okay, so far, so good. Now we could connect to the services in the browser.
When we had done this it was possible to visit the service in the browser in a secure, encrypted, manner.
The problem is that it isn't possible to make a call to the service, neither in Android nor WCF Test Client. If I call the service on the https address, I get a 404 in response. WCF Test Client returns this:
There was no endpoint listening at https://[my service address] that could accept the message. This is often caused by an incorrect address or SOAP action.
To be able to debug this, I'm using Wireshark to intercept the messages and see what really happens. I've found out that after the set up procedures (handshake, establishing trust etc.) the client sends the header and get a 101 Continue in response, after which it POSTs the body. This should be normal behavior. But then the service returns 404 Not Found. Wireshark says that the full request URI is the http address. I've configured the server to use the https address, so why does it make a call to the http address?
I've tried setting the address and listenUri attribute of the endpoint to https and http respectively and the other way around. If I do that, the server answers the request with 405 Method Not Allowed.
Is there any way to solve this? What am I missing?
What am I missing?
TL;DR version below
I'm hosting three WCF SOAP web services with IIS, one using .NET 4 and the others using .NET 3.5. I'm trying to make a call from the WCF Test Client over HTTPS. I've enabled transport security, meta data publishing over HTTPS, installed a trusted certificate and added a https binding on the server.
When I try to make a call from WCF Test Client it says that there was no endpoint listening at the address. Wireshark tells me it makes the call to the http version of the service (i.e. "http://[my address]" instead of "https://[my address]"), although it is configured to call the https address. The service returns 404 Not Found. If I set the address of the service to https and listenUri to http, I get 405 Method Not Allowed. If I do it the other way around it says that it cannot be activated. What am I missing?
I solved this by removing the endpoint and using the <protocolMapping> tag, like this:
<protocolMapping>
<add scheme="https" binding="basicHttpBinding" bindingConfiguration="basicHttps" />
</protocolMapping>
My WCF Service implementation appears to have all necessary HTTPS configuration settings. The whole client-> service comms work just fine, my issue is that request responses do not appear to be transported over HTTPS.
My configuration:
wsHttpBinding - check
mexHttpsBinding - check
security mode="Message" - check
httpsGetEnabled - check
When I examined the comms in Fiddler then I see the request and response being made over HTTP rather than HTTPS. This ties up with the WSDL action which states:
location="http://ws019.sms.com/Alpha.Services.AMSB2B/DeviceService.svc/Journey"/
wsa10:Address
http://ws019.sms.com/Alpha.Services.AMSB2B/DeviceService.svc/Journey
/wsa10:Address
Also in my endpoint configuration on the client side, the endpoint is pointing at the HTTP address rather than the HTTPS address (presumably this is looking at the WSDL) eg.
endpoint address="http://ws019.sms.com/Alpha.Services.AMSB2B/DeviceService.svc/Device"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IDeviceService"
contract="AMSB2B.IDeviceService" name="WSHttpBinding_IDeviceService"
Why does the WSDL / client endpoint address have HTTP in there, rather than HTTPS? If I change the configuration manually, it complains at runtime about expecting HTTP.
Any ideas?
Thanks.
Your configuration is wrong. WsHttpBinding with Message security uses HTTP. You must use Transport security.
How can I correctly serve WSDL of a WCF webservice located in a private LAN from behind a reverse proxy listening on public IP?
I have an Apache webserver configured in reverse proxy mode which listens for requests on a public IP address and serves them from the internal IIS host. WCF webservice generates WSDL using the FQDN address of the LAN host which, of course, cannot be read by an internet web service client.
Is there any setting that can be configured in wcf application's web.config or in IIS in order to customize the WSDL generated containing host address and put public address instead?
Add the following attribute to your service class:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
This allows the service to be addressed by the client as https://... but the service can still be hosted on http://.....
See my answer on How to specify AddressFilterMode.Any declaratively for how to create an extension to allow AddressFilterMode.Any to be specified through configuration without requiring code attributes.
In the web.config of the service host, the endpoint element must have an absolute URL in the address attribute that is the public URL that will be used by the client. In the same endpoint element, set the listenUri attribute to the absolute URL on which the service host is listening.
The way I determine what the default absolute URI the host is listening on is to add a service reference in a client application which points the the physical server where the service is hosted. The web.config of the client will have an address for the service. I then copy that into the listenUri attribute in the hosts web.config.
In your service behavior configuration, add the element serviceMetaData with attribute httpGetEnabled=true
So you'll have something like this:
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<!-- ... -->
<services>
<service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
<endpoint listenUri="http://www.servicehost.com"
address="https://www.sslloadbalancer.com"
binding="someBinding"
contract="IMyServiceInterface" ... />
</service>
</services>
I am not sure if this works with message security or transport security. For this particular application, the credentials were passed as part of the DataContract so we had basicHttpBinding > security > mode=none. Since the transport is secure (to the ssl load balancer) there were no security issues.
It is also possible in to leave the listenUri attribute blank, however it must be present.
Unfortunately, there is a bug in WCF where the the base address of imported schemas in the WSDL have the listenUri base address rather than the public base address (the one configured using the address attribute of the endpoint). To work around that issue, you need to create an IWsdlExportExtension implementation which brings the imported schemas into the WSDL document directly and removes the imports.
An example of this is provided in this article on Inline XSD in WSDL with WCF. Additionally you can have the example class inherit from BehaviorExtensionElement and complete the two new methods with:
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(InlineXsdInWsdlBehavior)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New InlineXsdInWsdlBehavior()
End Function
This will allow you to add an extension behavior in the .config file and add the behavior using configuration rather than having to create a service factory.
Under the system.servicemodel configuration element add:
<behaviors>
<endpointBehaviors>
<behavior name="SSLLoadBalancerBehavior">
<flattenXsdImports/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!--The full assembly name must be specified in the type attribute as of WCF 3.5sp1-->
<add name="flattenXsdImports" type="Org.ServiceModel.Description.FlattenXsdImportsEndpointBehavior, Org.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
And then reference the new endpoint behavior in your endpoint configuration using the behaviorConfiguration attribute
<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">
I'm having similar issues, one of which was the resolution of public and server addresses. This solved that issue although I still have a couple authentication problems.
See: How to change HostName in WSDL for an IIS-hosted service? by Wenlong Dong
archive
See: Service Station WCF Addressing In Depth by Aaron Skonnard
archive link