I have my own C # consol web interface for websites. It serves several web applications that use AngularJS to execute asynchronous HTTP requests. It must have CORS support and NTLM authentication.
I currently have both options, but it seems that the way I implemented them forces them to cancel themselves. I believe this is due to my initial 401 answer from the server. This usually leads to authentication between them, but looking at it in Fiddler, this initial 401 answer does not have an Access-Control-Allow-Origin tag, and this forces the browser to refuse a handshake. I took the application and gave them the same hostname to disable the need for CORS, and the handshake works fine. I disabled NTLM authentication, replacing my custom NtlmSelfHostConfiguration with the original HttpSelfHostConfiguration, and the Access-Control-Allow-Origin tag works fine to enable CORS. only when they are both active that everything does not work.
UPDATE: I put a breakpoint in my CorsHandle on a request that would not require it, just to make sure that the web server can actually call it when using NtlmSelfHostConfiguration, and it was successfully deleted. I just wanted to make sure that there was nothing in NtlmSelfHostConfiguration that physically prevented Corshandle from ever being called. Everything works perfectly. Definitely, I need to find a way to call CorsHandle even on requests that do not authenticate.
Here is my example:
Program.cs:
using System.Web.Http; using System.Web.Http.Validation.Providers; using System.Web.Http.SelfHost; namespace DCMAPI { class Program { static void Main(string[] args) { string BaseAddress = "http://localhost:8080/";
NtlmSelfHostConfiguration.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Http; using System.Web.Http.SelfHost; using System.Web.Http.SelfHost.Channels; using System.ServiceModel; using System.ServiceModel.Channels; namespace DCMAPI { public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration { public NtlmSelfHostConfiguration(string baseAddress) : base(baseAddress) { } public NtlmSelfHostConfiguration(Uri baseAddress) : base(baseAddress) { } protected override BindingParameterCollection OnConfigureBinding (HttpBinding httpBinding) { httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly; httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm; return base.OnConfigureBinding(httpBinding); } } }
CorsHandle.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Net.Http; using System.Threading.Tasks; using System.Threading; using System.Net; namespace DCMAPI { public class CorsHandler : DelegatingHandler { const string Origin = "Origin"; const string AccessControlRequestMethod = "Access-Control-Request-Method"; const string AccessControlRequestHeaders = "Access-Control-Request-Headers"; const string AccessControlAllowOrigin = "Access-Control-Allow-Origin"; const string AccessControlAllowMethods = "Access-Control-Allow-Methods"; const string AccessControlAllowHeaders = "Access-Control-Allow-Headers"; protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken) { bool isCorsRequest = request.Headers.Contains(Origin); bool isPreflightRequest = request.Method == HttpMethod.Options; if (isCorsRequest) { if (isPreflightRequest) { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First()); string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod) .FirstOrDefault(); if (accessControlRequestMethod != null) { response.Headers.Add( AccessControlAllowMethods, accessControlRequestMethod); } string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders)); if (!string.IsNullOrEmpty(requestedHeaders)) { response.Headers.Add(AccessControlAllowHeaders, requestedHeaders); } TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>(); tcs.SetResult(response); return tcs.Task; } else { return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(t => { HttpResponseMessage resp = t.Result; resp.Headers.Add( AccessControlAllowOrigin, request.Headers.GetValues(Origin).First()); return resp; }); } } else { return base.SendAsync(request, cancellationToken); } } } }