How to use SSL with a WCF web service? - wcf

I have a web service in asp.net running and everything works fine. Now I need to access some methods in that web-service using SSL. It works perfect when I contact the web-service using http:// but with https:// I get "There was no endpoint listening at https://...".
Can you please help me on how to set up my web.config to support both http and https access to my web service. I have tried to follow guidelines but I can't get it working.
Some code:
My TestService.svc:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public bool validUser(string email) {
return true;
}
}
My Web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="ServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="TestService">
<endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="ServiceBinding"
contract="TestService" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="ServiceBinding" maxBufferPoolSize="1000000" maxReceivedMessageSize="1000000">
<readerQuotas maxDepth="1000000" maxStringContentLength="1000000" maxArrayLength="1000000" maxBytesPerRead="1000000" maxNameTableCharCount="1000000"/>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>

Instead of using the webHttpBinding, try creating a customBinding instead:
<customBinding>
<binding name="poxBindingHttps" closeTimeout="00:00:20">
<textMessageEncoding writeEncoding="utf-8" />
<httpsTransport manualAddressing="true"/>
</binding>
<binding name="poxBindingHttp" closeTimeout="00:00:20">
<textMessageEncoding writeEncoding="utf-8" />
<httpTransport manualAddressing="true"/>
</binding>
</customBinding>
You'll also need to setup the webHttpBehavior like so:
<behaviors>
<endpointBehaviors>
<behavior name="ajaxBehavior">
<enableWebScript/>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
And finally, your service & endpoint:
<services>
<service name="TestService">
<endpoint name="sslDefault" address="" binding="customBinding" bindingConfiguration="poxBindingHttps" behaviorConfiguration="ajaxBehavior" contract="TestService"/>
<endpoint name="noSslDefault" address="" binding="customBinding" bindingConfiguration="poxBindingHttp" behaviorConfiguration="ajaxBehavior" contract="TestService"/>
</service>
</services>
Hopefully that works out for you in creating an SSL endpoint

It sounds like there is more an issue with IIS no listening on port 443 (The port used for HTTPS). Check IIS that there is a certificate installed and that it is listening on the secure port.

Related

WCF picking basicHttpBinding & ignoring the defined customBindings

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<bindings>
<customBinding>
<binding name="httpBinding">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
</binding>
<binding name="httpsBinding">
<binaryMessageEncoding/>
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
</binding>
</customBinding>
</bindings>
<services>
<service name="MyNamespace.MyIService" behaviorConfiguration="MyNamespace.MyIService" >
<endpoint address="http://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding" contract="MyNamespace.MyIService"
name="httpBinding"/>
<endpoint address="https://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding" bindingConfiguration="httpsBinding"
contract="MyNamespace.MyIService" name="httpsBinding" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyNamespace.MyIService" >
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<client>
<endpoint address="http://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding"
bindingConfiguration="httpBinding"
contract="MyNamespace.MyIService"
name="httpBinding" />
<endpoint address="https://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding"
bindingConfiguration="httpsBinding"
contract="MyNamespace.MyIService"
name="httpsBinding" />
</client>
</system.serviceModel>
I have the above configuration in a WCF service that is hosted in IIS. I can successfully browse to the service in the browser, as you can observer i want to use a customBinding.
When i use visual studio to add a reference to this service in my client application using VS inbuilt add service reference dialogue, below is the client endpoint that visual studio creates for me.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_MyIService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://wcf-client-url/virtualDirectory/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_MyIService"
contract="ServiceReference1.MyIService" name="BasicHttpBinding_MyIService" />
</client>
</system.serviceModel>
What i'm not understanding is why VS is creating for me a client basicHttpBinding yet i have defined a customBinding on the server.
Also, when i test my service in "WCF Test Client" and then double click the config file in WCF Test Client, i see that indeed it displays the below config in the Test Client.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_MyIService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://myPCHostName/virtualDirectory/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_MyIService"
contract="MyIService" name="BasicHttpBinding_MyIService" />
</client>
</system.serviceModel>
</configuration>
I'm sort of new to this WCF development & i'm not clearly understanding how my customBinding are being ignored.
From my config above, is BasicHttpBinding being set any where as the default binding, or is there away i can completely remove it even though i can't seem to figure where its being set from in that configuration.
try to specify behaviorConfiguration and bindingConfiguration for both endpoints on service side. You have specified bindingConfiguration only for https endpoint, and have not done this for behaviors at all.
Should be something like
<bindings>
<customBinding>
<binding name="httpBinding">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
</binding>
<binding name="httpsBinding">
<binaryMessageEncoding/>
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
</binding>
</customBinding>
</bindings>
<services>
<service name="MyNamespace.MyIService" behaviorConfiguration="MyNamespace.MyIService" >
<endpoint address="http://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding"
contract="MyNamespace.MyIService"
bindingConfiguration="httpBinding"
behaviorConfiguration="httpEndpoint"
name="httpBinding"/>
<endpoint address="https://wcf-client-url/virtualDirectory/MyService.svc"
binding="customBinding"
bindingConfiguration="httpsBinding"
behaviorConfiguration="httpEndpoint"
contract="MyNamespace.MyIService"
name="httpsBinding" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="httpEndpoint" >
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>

WCF configuration to HTTPS with SSL not working

I am trying to use an HTTPS service using WCF but it keeps returning all kinds of errors. When I use the basicHttpBinding to call the HTTP URL it works fine but when I swich to webHttpBinding or wsHttpBinding and call the HTTPS URL I'm getting these errors:
The content type text/xml;charset=utf-8 of the response message does not match the content
type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder,
be sure that the IsContentTypeSupported method is implemented properly.
And here is my configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="MentorGraphicsIM">
<endpoint name="MentorGraphicsServiceEndPoint"
address=""
binding="webHttpBinding"
bindingConfiguration="webHttpPadsTouch"
behaviorConfiguration="ServiceEndPointBehavior"
contract="IMentorGraphics">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" />
</basicHttpBinding>
<webHttpBinding>
<binding name="webHttpPadsTouch">
</binding>
</webHttpBinding>
<wsHttpBinding>
<binding name="WsHttpBinding">
<security mode="Transport" />
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<!--Required default endpoint behavior when using webHttpBinding-->
<endpointBehaviors>
<behavior name="ServiceEndPointBehavior">
<webHttp />
</behavior>
<behavior name="ClientEndPointBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Xml" helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint name="PadsTouch_HTTP"
address="https://XXX"
binding="wsHttpBinding"
bindingConfiguration="WsHttpBinding"
contract="IEntitle" />
</client>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
My Interface is:
[ServiceContract(Namespace = "xxx", ProtectionLevel = ProtectionLevel.None)]
public interface IMentorGraphics
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "MyMethod", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
ServiceResponse MyMethod(MyParams #param);
}
replace service binding from bindingConfiguration="webHttpPadsTouch" to bindingConfiguration="WsHttpBinding"

Not able to access the methods from secure wcf rest service

I have a running wcf rest service hosted on IIS. I have successfully added the .x509 certificates to the client and the server and it works fine.As it is a secure service it is accessed using https The problem I am facing is that I am not able to access any of the methods from the service it keeps throwing 404 error however when I browse the service from IIS using https link it open the WSDL fine but throws 404 error while accessing any of the methods.
Here is my Interface implementation of a method from the service.
[ServiceContract]
public interface IRestDemo
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/DoWork/{name}")]
string DoWork(string name);
}
Here is my configuration file:
<system.serviceModel>
<services>
<service name="RestDemo.RestDemo" behaviorConfiguration="serviceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost/RestDemo/RestDemo.svc" />
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" contract="RestDemo.IRestDemo" behaviorConfiguration="web">
<!--<identity>
<dns value="localhost"/>
</identity>-->
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="RestDemo.IRestDemo" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="web" crossDomainScriptAccessEnabled="true">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<!--<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"
trustedStoreLocation="LocalMachine" />
</clientCertificate>
<serviceCertificate findValue="ServerCertificate"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>-->
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" httpsGetUrl="/RestDemo.svc" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint
crossDomainScriptAccessEnabled="true">
</standardEndpoint>
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
Any suggestions would be really appreciated.

WCF Multiple Endpoints is not working

I am trying to let my WCF service to have operations that can be called through a proxy client and through REST call, i am using the following configurations:
<services>
<service behaviorConfiguration="SecureBehavior" name="Payment">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="secureWS" contract="IPayment"/>
<endpoint address="rest" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="IPayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</services>
and here is my code:
[ServiceContract]
public interface IPayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
Now whenever i run my service i receive this error:
Operation 'Finalize' of contract 'IPayment' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
Where here i would like to keep Finalize operation to be only called via .NET client and the GetPayment operation to be called through any browser.
If you do not want your Finalize method to be called from a client connecting via the webhttp endpoint and you don't want GetPayments to be called from a client connecting via wshttp you can simply split your contract in two.
Assuming you are hosting in IIS you might need to do a little trick to make sure that it works. Let me give you an example using the details from the question...
First of all here is the code for the two services...
[ServiceContract]
public interface IPayment
{
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
[DataContract]
public class PaymentResult
{
}
[ServiceContract]
public interface IMakePayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
}
// Maybe you really should have the two services separate but if you do
// want to implement them both in a single class you can do this
public abstract class PaymentBase : IMakePayment, IPayment
{
// ... Implement both interfaces here
public PaymentResult Finalize(string TransactionID, string CertificatePath)
{
return null;
}
public System.IO.Stream GetPayment()
{
return null;
}
}
public class MakePayment : PaymentBase
{
// Empty
}
public class Payment : PaymentBase
{
// Empty
}
Now create two .svc files like so:
MakePayment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.MakePayment" %>
Payment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.Payment" %>
And finally here is the system.servicemodel configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="SecureBehavior" name="WebApplication1.MakePayment">
<endpoint binding="wsHttpBinding" bindingConfiguration="secureWS" contract="WebApplication1.IMakePayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" bindingConfiguration="userMex"/>
</service>
<service behaviorConfiguration="PublicBehavior" name="WebApplication1.Payment">
<endpoint binding="webHttpBinding" behaviorConfiguration="webBehavior" bindingConfiguration="publicWS" contract="WebApplication1.IPayment"/>
</service>
</services>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
<webHttpBinding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
There you go - if you connect to /MakePayment.svc you will connect via WSHTTP and be able to call FinalizePayment and if you go to /Payments.svc/rest it will call the GetPayment method where you are returning a stream.

AspNetMembership provider with WCF service

I'm trying to configure AspNetMembershipProvider to be used for authenticating in my WCF service that is using basicHttpBinding. I have following configuration:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="basicSecureBinding">
<security mode="Message"></security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyApp.Services.ComputersServiceBehavior">
<serviceAuthorization roleProviderName="AspNetSqlRoleProvider" principalPermissionMode="UseAspNetRoles" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="AspNetSqlMembershipProvider"/>
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyApp.Services.ComputersServiceBehavior" name="MyApp.Services.ComputersService">
<endpoint binding="basicHttpBinding" contract="MyApp.Services.IComputersService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
Roles are enabled and membership provider is configured (its working for web site).
But authentication process is not fired at all. There is no calles to data base during request, and when I try to set following attribute on method:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public bool Test()
{
return true;
}
I'm getting access denied exception. Any thoughts how to fix it?
Try this CodePlex Security Guide, the How Tos and Application Scenarios have detailed setup and configurations guides for a number of configuration options that might help you find the missing piece of your puzzle.