Option request (CORS) blocked by webHttpBinding security - wcf

Following manual to enable CORS in WCF. I can't have the CORS with security mode enabled. It gets rejected by error 401. However, without the security option it works fine. Is there a method to exclude OPTIONS request from security?
EnableCrossOriginResourceSharingBehavior
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
var requiredHeaders = new Dictionary<string, string>();
requiredHeaders.Add("Access-Control-Allow-Origin", "http://localhost:8080");
requiredHeaders.Add("Access-Control-Allow-Credentials", "true");
requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
requiredHeaders.Add("Access-Control-Request-Headers", " X-PINGOTHER, Content-Type");
requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type, X-Requested-With, X-Custom-Information, authorization");
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
}
Web.config:
<endpoint address="secure" binding="webHttpBinding" bindingConfiguration="webHttpBinding_Secure" contract="WebService.IService" behaviorConfiguration="web"/>
<endpoint address="insecure" binding="webHttpBinding" bindingConfiguration="webHttpBinding_InSecure" contract="WebService.IService" behaviorConfiguration="web" />
<webHttpBinding>
<binding name="webHttpBinding_Secure" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
<binding name="webHttpBinding_InSecure" >
...
</binding>
</webHttpBinding>

Related

What is the default timeout for the basichttpbinding in wcf

I am new to wcf, created a service and a consumer. As documentation suggest, default timeout is 10 minutes for ReceiveTimeout.
In consumer side, i tried to reproduce for timeout for the request but event after 25 minutes it works without breaking.
If someone can let me know what exactly the time we can open a channel with basichttp binding?
Below is the wcf app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Raj">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="">
</transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Raj">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCF_NewsService.News_Service" behaviorConfiguration="Raj">
<host>
<baseAddresses>
<add baseAddress="https://localhost:8732/Design_Time_Addresses/WCF_NewsService/News_Service/"/>
</baseAddresses>
</host>
<endpoint address="News_Service" binding="basicHttpBinding" contract="WCF_NewsService.INews_Service" bindingConfiguration="Raj"/>
</service>
</services>
</system.serviceModel>
Consumer Code:
var myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Certificate;
myBinding.MaxReceivedMessageSize = Int32.MaxValue;
myBinding.MaxBufferSize = Int32.MaxValue;
BindingParameterCollection bindingParameters = new BindingParameterCollection();
var address = new EndpointAddress("https:xxxx:8732/Design_Time_Addresses/WCF_NewsService/News_Service/News_Service");
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
//Client Credentials
string _thumbPrint = "5AD9BC96AA4D44852D1B97C91C1628C070E3187C";
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, _thumbPrint);
bindingParameters.Add(clientCredentials);
var factory = myBinding.BuildChannelFactory<IRequestChannel>(bindingParameters);
factory.Open();
var irc = factory.CreateChannel(address);
// --- Without body
Message createRequestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/INews_Service/Getnews");
irc.Open();
var result = irc.Request(createRequestMessage);
Thread.Sleep(TimeSpan.FromMinutes(25));
//--With body
TOInews tOInews = new TOInews { ID = 125, Body = "this is body test", Header = "This is header test" };
createRequestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/INews_Service/GetnewsById", tOInews);
//irc.Open();
var result1 = irc.Request(createRequestMessage);
ReceiveTimeout – used by the Service Framework Layer to initialize the session-idle timeout which controls how long a session can be idle before timing out.
I didn't find that you have ReceiveTimeout configured in the config file, you need to configure it.You can see the code below.You can check the documentation on how to configure the timeout value on the binding.
You can use Message Inspectors to capture WCF operation execution time. See this post for specific steps.
<basicHttpBinding>
<binding name="Raj" openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="">
</transport>
</security>
</binding>
</basicHttpBinding>

WCF netTcpBinding issue: Contract requires Duplex, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it

I'm trying to create a callback in WCF service. Service so far was using basicHttpBinding, so I want to add another end point for netTcpBinding. Service is already hosted in IIS. First It was hosted in IIS 6, but then I installed IIS 7.
So, I'm getting the following error:
The requested service, 'net.tcp://localhost:1801/MyServiceName.svc/NetTcpExampleAddress' could not be activated. See the server's diagnostic trace logs for more information.
When seeing the log, this is the message:
So the main error is:
Contract requires Duplex, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.
Here are my config files:
My Web.config for the server:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="demoServiceNetTcpBinding">
<security mode="None"/>
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="demoServiceHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyServerName.MyServiceName">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:1801/MyServiceName.svc/"/>
<add baseAddress="http://localhost:1800/MyServiceName.svc/"/>
</baseAddresses>
</host>
<endpoint
address="NetTcpExampleAddress"
binding="netTcpBinding"
bindingConfiguration="demoServiceNetTcpBinding"
contract="MyServerName.SharedContract.IMyServiceName"/>
<endpoint
address="BasicHttpExampleAddress"
binding="basicHttpBinding"
bindingConfiguration="demoServiceHttpBinding"
contract="MyServerName.SharedContract.IMyServiceName"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
My App.config for the client:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="demoServiceNetTcpBinding">
<security mode="None"/>
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="demoServiceHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="NetTcpExampleName"
address="net.tcp://localhost:1801/DicomQueryService.svc/NetTcpExampleAddress"
bindingConfiguration ="demoServiceNetTcpBinding"
contract="MyServerName.SharedContract.IMyServiceName"
binding="netTcpBinding" />
<endpoint name="BasicHttpExampleName"
address="http://localhost:1800/MyServiceName.svc/BasicHttpExampleAddress"
bindingConfiguration ="demoServiceHttpBinding"
contract="MyServerName.SharedContract.IMyServiceName"
binding="basicHttpBinding" />
</client>
</system.serviceModel>
Settings in my IIS:
If there are any other pieces of code that you need, please let me know and I'll update the question.
EDIT 1:
Here are more details from the code, of how I'm calling the service from the client (on client side):
public class MyCommandClass : IMyServiceCallback
{
public MyCommandClass()
{
var ctx = new InstanceContext(new MyCommandClass());
DuplexChannelFactory<MyServerName.SharedContract.IMyServiceName> channel = new DuplexChannelFactory<MyServerName.SharedContract.IMyServiceName>(ctx, "NetTcpExampleName");
MyServerName.SharedContract.IMyServiceName clientProxy = channel.CreateChannel();
clientProxy.MyFunction(); //debug point is comming here and then it throws the error
clientProxy.ProcessReport();
(clientProxy as IClientChannel).Close();
channel.Close();
}
public void Progress(int percentageCompleted)
{
Console.WriteLine(percentageCompleted.ToString() + " % completed");
}
}
where interfaces (on server side) are defined as:
[ServiceContract(CallbackContract = typeof(IMyServiceCallback))]
public interface IMyServiceName
{
[OperationContract]
void MyFunction();
[OperationContract(IsOneWay = true)]
void ProcessReport();
}
public interface IMyServiceCallback
{
[OperationContract(IsOneWay = true)]
void Progress(int percentageCompleted);
}
and service (on server side) is defined as:
public class MyServiceName: IMyServiceName
{
public void MyFunction()
{
//do something
}
public void ProcessReport()
{
//trigger the callback method
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
OperationContext.Current.GetCallbackChannel<IMyServiceCallback>().Progress(i);
}
}
}
My methods so far are just a demo. Once the error related to this question is fixed, then I'll start with developing the methods.
Your service contract requires duplex connection (you have ServiceCallback attribute). Therefore all endpoints that this service exposes must support duplex connection. Net.tcp does support it, but basicHttp does not, so you cannot use basicHttp with your service now.

Trouble connecting to API

I am new to WCF/APIs and know little to nothing about security. Let me know if I need to provide any more information.
I am trying to connect to a service using
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISalesOrderService">
<security mode="Transport" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
<binding name="BasicHttpBinding_IDocumentationService">
<security mode="TransportCredentialOnly" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="address1"
name="BasicHttpBinding_ISalesOrderService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ISalesOrderService"
contract="SoCalls.ISalesOrderService" />
<endpoint address="address2"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IDocumentationService"
contract="DocCalls.IDocumentationService"
name="BasicHttpBinding_IDocumentationService" />
</client>
</system.serviceModel>
With this, I get this error:
'System.ServiceModel.Security.MessageSecurityException'
The HTTP request is unauthorized with client authentication scheme 'Basic'.
The authentication header received from the server was 'Basic Realm'.
Edit
I followed the instructions suggested in the link provided in the comments, still is giving me this error. I updated my code but I think I am still a bit confused on whether to use HTTP/HTTPS due to lack of knowledge of either service.
Here is how I instantiate my service:
private static SoCalls.SalesOrderServiceClient CreateSalesOrderServiceClient()
{
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.MaxReceivedMessageSize = 10000 * 2;
myBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress ea = new EndpointAddress("address1");
SoCalls.SalesOrderServiceClient client = new SoCalls.SalesOrderServiceClient();
client.ClientCredentials.UserName.UserName = ("username");
client.ClientCredentials.UserName.Password = ("password");
return client;
}
As it seems, I did not have access to the API with this specific database which is what was giving me my error. I tried sending other credentials for a separate database from the same server and it worked perfectly fine. Purchased the license required and the code works as expected.

Disable CustomUserNamePasswordValidator for specific operation

I am using a CustomUserNamePasswordValidator for my WCF web service. However, i am trying to add a IsAlive operation, which should be able to be called from clients, even when not authenticated.
For example, i want to be able to do a check, if a service is online and accessible on startup, so i can notify the user on missing inet connection or a not available service (due to maintenance).
I have code for all this already in place. What i am missing is how i can access the operation without passing a username and password.
I could probably just add a second service which allows anon access, but i'd really prefer to use the existing service.
The Validator is implemented like this (i ommited the actual checking code):
public sealed class MyCredentialValidator : UserNamePasswordValidator
{
public MyCredentialValidator ()
{
}
public override void Validate(string userName, string password)
{
Debug.WriteLine("MyCredentialValidator : Validate called.");
// do some checks
var isValid = CheckCredentials(userName, password)
if(!isValid)
{
throw new FaultException(...);
}
}
}
It is registered in the web.config like so:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyCredentialValidator,..."/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="my service" behaviorConfiguration="SecureBehavior">
<endpoint address="" binding="wsHttpBinding" contract="my contract" bindingConfiguration="SecureBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
client side configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding"
closeTimeout="00:10:00"
openTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://my service url"
contract="my contract"
binding="wsHttpBinding"
bindingConfiguration="SecureBinding"
name="secure" />
</client>
</system.serviceModel>
client side wcf call code:
var cf = new ChannelFactory<my contract>("secure");
using (IClientChannel channel = (IClientChannel)cf.CreateChannel())
{
channel.OperationTimeout = TimeSpan.FromSeconds(3);
bool success = false;
try
{
channel.Open();
result = ((my contract)channel).IsAlive();
channel.Close();
success = true;
}
finally
{
if (!success)
{
channel.Abort();
}
}
}
I have done something like this before,
depending on how you have integrated your custom validator in the wcf pipleline,
you could simply before you do the actual validation, which I guess returns something like true or false, you could check the incoming url or address and see if it is going to be going to your IsAlive operation, if that is the case, you could simply do a early return true.
Wcf has a few ways with which you can check what operation the client has called.
to be more accurate, I would need to know how you wrote your custom validator and where in the pipeline it integrates.

MSMQ + WCF: The WindowsDomain MsmqAuthenticationMode requires the sender's SID

I'm receiving the following error when attempting to send/receive to an MSMQ queue using WCF:
"Creation of a message security context failed because the sender's SID was not found in the message. The message cannot be received. The WindowsDomain MsmqAuthenticationMode requires the sender's SID."
This is causing all messages to fail and therefore move to another poison queue. The error appears to be firing on the receiving service.
The client configuration is as follows:
<netMsmqBinding>
<binding name="OrderServiceMsmqBinding"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveErrorHandling="Move"
receiveRetryCount="1"
retryCycleDelay="00:0:05"
deadLetterQueue="Custom"
customDeadLetterQueue="net.msmq://localhost/private/Services.DeadOrderListenerService/DeadOrderListenerService.svc"
useMsmqTracing="true">
<security mode="None" />
<readerQuotas maxStringContentLength="2147483647" />
</binding>
</netMsmqBinding>
as well as:
<client>
<endpoint address="net.msmq://localhost/private/Services.OrderPlacementProviderService/OrderPlacementProviderService.svc" binding="netMsmqBinding" bindingConfiguration="OrderServiceMsmqBinding" contract="Providers.IOrderPlacementService" name="orderingMsmqEndpoint" />
</client>
The receiving service is configured much the same:
<netMsmqBinding>
<binding name="OrderServiceMsmqBinding"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveErrorHandling="Move"
receiveRetryCount="1"
retryCycleDelay="00:0:05"
deadLetterQueue="Custom" customDeadLetterQueue="net.msmq://localhost/private/Services.DeadOrderListenerService/DeadOrderListenerService.svc"
timeToLive="00:01:00"
useActiveDirectory="false"
useMsmqTracing="true">
<readerQuotas maxStringContentLength="2147483647" />
</binding>
</netMsmqBinding>
And:
<service name="Services.OrderPlacementProviderService" behaviorConfiguration="OrderServiceBehavior">
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" name="MexOrderService" contract="IMetadataExchange" />
<endpoint address="net.msmq://localhost/private/Services.OrderPlacementProviderService/OrderPlacementProviderService.svc" binding="netMsmqBinding" bindingConfiguration="OrderServiceMsmqBinding" contract="Providers.IOrderPlacementService" name="msmqEndpoint" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/Services.OrderPlacementProviderService" />
</baseAddresses>
</host>
</service>
The queues are unauthenticated and have allowed access to Everyone for the time being. This SID issue has only just started occurring. It consistently occurs on different environments so I assume I've configured something wrongly?
Some more information: The client places an order (on the queue) like so:
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
_orderPlacementClient.PlaceOrder(basket, transactionRef, user);
scope.Complete();
}
and the listening service looks like:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void PlaceOrder(BasketDTO basket, string transactionReference, UserDTO user)
{
_log.Info("Order placed: " + transactionReference + " for user " + user.Id);
try
{
_prov.PlaceOrder(basket, transactionReference, user);
}
catch (Exception ex)
{
_log.Error("Error placing order", ex);
}
}