6

I have implemented a self-hosted WCF Rest Service and an according Angular CLI Client. I ran into troubles with CORS, but I was able to solve them when HttpClientCredentialType.None is set within the WebHttpBinding.

The problem is, that I need to use HttpClientCredentialType.Windows, because I have to know the identity of the Windows user using the system.
Here is the used binding:

new WebHttpBinding
{
    MaxBufferSize = int.MaxValue,
    MaxBufferPoolSize = 524288,
    MaxReceivedMessageSize = int.MaxValue,                
    OpenTimeout = TimeSpan.FromMinutes(1),
    SendTimeout = TimeSpan.FromMinutes(1),
    ReceiveTimeout = TimeSpan.FromMinutes(10),
    CloseTimeout = TimeSpan.FromMinutes(1),
    ReaderQuotas =
    {
        MaxStringContentLength = int.MaxValue,
        MaxArrayLength = int.MaxValue,
        MaxDepth = int.MaxValue,
        MaxNameTableCharCount = int.MaxValue
    },
    Security =
    {
        Mode = WebHttpSecurityMode.Transport,
        Transport = { ClientCredentialType = HttpClientCredentialType.Windows }
        //Transport = { ClientCredentialType = HttpClientCredentialType.None}
    }
};

But now the CORS-Options call is rejected with HttpStatus 401 Unauthorized, because there is no authentication header in it. Therefore, the whole call is rejected (what is right...in theory).

Of course I already added all necessary headers. As said, it works with None authentication.

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Id, Origin, Authorization");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Credentials", "true");

So I see three possibilities to solve my problem.

  1. Get the CORS-Options call in my Angular client somehow to pass my Windows Credentials.
  2. Get the WCF service to ignore the Authentication in CORS-Options call.
  3. Set Authorization back to None and pass my Windows Credentials in some other way (without forcing the user to enter his credentials).

It also works even with Windows Authentication, when I use --disable-web-security in Chrome Browser. But for me, this is not a solution for a production system.

Maybe someone has any ideas or even a solution to my problem.

hirosht
  • 932
  • 2
  • 17
  • 31
Obl Tobl
  • 5,604
  • 8
  • 41
  • 65
  • You need to do #2. The server must not require authentication for the CORS preflight OPTIONS request. If it does, then the preflight will always fail in the browser — because the CORS spec prohibits the browser from sending authentication credentials in the preflight OPTIONS request. And #1 is not a possibility — because it’s not the Angular client code that sends the preflight OPTIONS request; instead it’s the browser itself that automatically on its own sends the OPTIONS request. And it never sends authentication credentials as part of that request. – sideshowbarker Jul 05 '18 at 12:45
  • @sideshowbarker thanks, you are absolutely right. But how to tell the wcf service to ignore the preflight request? – Obl Tobl Jul 05 '18 at 12:47

2 Answers2

0

The option here is to use Microsoft.AspNet.WebApi.Cors.

I ran into this issue using Web Api and found this solution (nuget package) that works well with WCF as well.

you need to use this decorator above your class:

[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]

and then above your method add the decorator:

[AcceptVerbs("POST")]

This will ignore the pre-flight request and will only send your actual request.

EDIT:

after looking at your code a little bit more, I understood the issue: you need an extra parameter:

var cors = new EnableCorsAttribute("http://IP:PORT", "*", "*") { SupportsCredentials = true };
config.EnableCors(cors); 

there is an excellent post at asp.net forums to help with your situation as well.

AS REQUESTED

Here is a workaround for HttpConfiguration in wcf.

Barr J
  • 10,636
  • 1
  • 28
  • 46
  • After removing previous attempts I added the package and your code to my Service class and still get a 401 with windows authentication. If it works in your project, maybe you could specify your steps a little more explicit? – Obl Tobl Jul 11 '18 at 09:45
  • If 'config' is HttpConfiguration: That's the configuration for a WebApi Service. This has nothing to do with a WCF. Or you can tell me how to configure my WCF with a HttpConfiguration, then of course all problems are solved! But I can't see the light at the end of the tunnel at the moment ;-) – Obl Tobl Jul 11 '18 at 11:02
  • there is a workaround for that using token, link is attached :) – Barr J Jul 11 '18 at 11:08
-1

Can't you just add a global.asax and add an Access-Control-Allow-Origin Header

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://YourDomain");
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");

        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • 1
    The headers are not the problem. The problem is the windows authentication in combination with the preflight requests. With Windows authentication, the request won't even begin. – Obl Tobl Jul 12 '18 at 06:30
  • Obi did you try this? The If statement handling options should take care of preflight – johnny 5 Jul 12 '18 at 12:34