How to enable CORS support and NTLM authentication

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 is defined in HttpSelfHostConfiguration.cs //it inherits from HttpSelfHostConfiguration //and enables Ntlm Authentication. var config = new NtlmSelfHostConfiguration(BaseAddress); config.Routes.MapHttpRoute( "API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); //CorsHandler is also defined in CorsHandler.cs. It is what enables CORS config.MessageHandlers.Add(new CorsHandler()); var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault (t => t.MediaType == "application/xml"); config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType); config.Services.RemoveAll (typeof(System.Web.Http.Validation.ModelValidatorProvider), v => v is InvalidModelValidatorProvider); using (HttpSelfHostServer server = new HttpSelfHostServer(config)) { server.OpenAsync().Wait(); Console.WriteLine("running"); Console.ReadLine(); } } } } 

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); } } } } 
+6
source share
1 answer

This may be a bit late, and I'm not sure if this will help you, but it may help someone who wants to have both NTLM and CORS.

I am using Web API 2 for the basic REST API. And AngularJS for the interface.

First, since you are using NTLM, your XMLHttpRequest call must send credentials. In AngularJs, you like this:

 $http.get(url, { withCredentials: true }); 

Then you must enable CORS on your server (in WebApiConfig.Register() ):

  var enableCorsAttribute = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true }; config.EnableCors(enableCorsAttribute); 

SupportsCredentials = true means that we will add the answer Access-Control-Allow-Credentials .

Wildcards mean that we allow:

  • CORS from any source
  • All request headers
  • Any HTTP verb (method)
+8
source

Source: https://habr.com/ru/post/943842/


All Articles