jquery - length - Obtener un Desafío NTLM desde un POSTE AJAX en una sola página
load jquery ejemplo (2)
¿Qué está pasando en los métodos de acción que están causando el desafío NTLM? ¿Estás seguro de que estos métodos de acción específicos no están accediendo a otro servidor o a Internet a través de un proxy que requiere autenticación? En su entorno de desarrollo, su usuario o el usuario que ejecuta el grupo de aplicaciones en IIS puede tener los permisos necesarios, pero el usuario en el servidor no puede.
En lugar de arrojar una Excepción clara relacionada con la seguridad, ASP.NET traducirá esto en un desafío NTLM que se devuelve al cliente, y un 401 en caso de credenciales no válidas, en lugar de un 500 que contenga la pila que lo lleve al punto donde el servidor cuenta no tenía suficientes privilegios ...
Todo el misterio aquí. Tengo una aplicación web ASP.NET MVC 4 con Autenticación de Windows que se ha mantenido durante más de 18 meses sin problemas. Recientemente, se implementó en un sitio nuevo y me encontré con el siguiente comportamiento muy extraño.
Estoy utilizando una llamada jQuery 1.8.2 $.ajax
para enviar datos POST a los puntos finales del servidor para actualizar los datos. Esto funciona bien, excepto en una página, donde el AJAX POST desencadena una nueva Negociación NTLM. El mismo problema se muestra en Chrome, IE y Firefox. Si bien el problema es el mismo en todos los navegadores, se manifiesta de maneras ligeramente diferentes:
- Firefox: Recibió una respuesta de Desafío 401 del servidor y muestra un diálogo de nombre de usuario / contraseña que solicita una credencial en un ciclo infinito. La cancelación de las comprobaciones de credenciales hace que la solicitud falle con una respuesta no autorizada.
- IE: no hay respuesta del servidor y el estado de la solicitud se muestra como "(Abortado)" en el monitor de red
- Chrome: no hay respuesta del servidor y el estado de la solicitud muestra un "(error)" en el monitor de red.
El problema central parece ser que el encabezado Connection: keep-alive
no se envía con la problemática solicitud AJAX, pero sí en los demás casos. Sin embargo, el código JavaScript subyacente es casi idéntico, y las llamadas AJAX funcionan correctamente en un entorno de desarrollo que también está configurado para usar la autenticación de Windows.
Además, intentar establecer el encabezado de solicitud de Connection
en la beforeSend
llamada beforeSend
no tiene ningún efecto.
Cualquier idea sobre la raíz del problema, o formas de aislar cualquier diferencia existente entre los dos POST de AJAX son muy apreciadas.
Código de trabajo y encabezados de solicitud
$.ajax({
url: url,
type: "POST",
data: $("#myForm").serialize(),
cache: false,
success: function (response) {
}
});
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:621
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:www.xxx.yyy.zzz
Origin:http://www.xxx.yyy.zzz
Referer:http://www.xxx.yyy.zzz/app/resource/path
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With:XMLHttpRequest
Código fallido y encabezados de solicitud
$.ajax({
url: url,
type: "POST",
data: data,
cache: false,
success: function (data, status, xhr) {
}
});
WARN: Provisional headers are shown
Accept:*/*
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Origin:http://www.xxx.yyy.zzz
Referer:http://www.xxx.yyy.zzz/app/resource/item/1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With:XMLHttpRequest
También miré el proceso de red en Chrome chrome://net-internals/#events
viewer. Aquí está el registro de eventos de la solicitud fallida en el punto en que se desvía de la exitosa. Cuando la solicitud fallida obtiene un "HTTP / 1.1 401 no autorizado", la solicitud correcta obtiene una respuesta "HTTP / 1.1 200 OK", presumiblemente debido a la presencia del encabezado Connection: keep-alive
.
2303: URL_REQUEST
Start Time: 2015-04-28 13:53:41.788
t=14736 [st= 0] +REQUEST_ALIVE [dt=71]
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] +URL_REQUEST_START_JOB [dt=70]
--> load_flags = 2688000 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
--> method = "POST"
--> priority = "LOW"
--> upload_id = "0"
--> url = "http://..."
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] HTTP_CACHE_GET_BACKEND [dt=0]
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] +HTTP_STREAM_REQUEST [dt=0]
t=14736 [st= 0] HTTP_STREAM_REQUEST_BOUND_TO_JOB
--> source_dependency = 2305 (HTTP_STREAM_JOB)
t=14736 [st= 0] -HTTP_STREAM_REQUEST
t=14736 [st= 0] +HTTP_TRANSACTION_SEND_REQUEST [dt=0]
t=14736 [st= 0] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
--> POST ... HTTP/1.1
Host: www.xxx.yyy.zzz
Connection: keep-alive
Content-Length: 105
Accept: */*
Origin: http://www.xxx.yyy.zzz
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://www.xxx.yyy.zzz/app/resource/item/1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
t=14736 [st= 0] HTTP_TRANSACTION_SEND_REQUEST_BODY
--> did_merge = true
--> is_chunked = false
--> length = 105
t=14736 [st= 0] -HTTP_TRANSACTION_SEND_REQUEST
t=14736 [st= 0] +HTTP_TRANSACTION_READ_HEADERS [dt=0]
t=14736 [st= 0] HTTP_STREAM_PARSER_READ_HEADERS [dt=0]
t=14736 [st= 0] HTTP_TRANSACTION_READ_RESPONSE_HEADERS
--> HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
X-UA-Compatible: IE=9
Date: Tue, 28 Apr 2015 18:53:41 GMT
Content-Length: 1293
Editar
Jugar con diferentes solicitudes desde la consola da la siguiente tabla de resultados (en Chrome). La URL base actual es http://IPAddress /app/topic/item
y todas las pruebas simplemente ejecutan un $.ajax({ url: url, type: ''POST'' })
+--------------------------------------+----------------------------+
| URL | Response |
+--------------------------------------+----------------------------+
| http://IP/app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| //IP/app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| /app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| 1/subitem/1 | net::ERR_INVALID_HANDLE |
| 1/foo | 404 (Not Found) [expected] |
| 1 | 302 (Redirect) [expected] |
+--------------------------------------+----------------------------+
Debido a que el error solo afecta un subconjunto de los métodos de acción POST
en un controlador, al principio pensé que era un problema del lado del servidor, pero después de descubrir el problema del encabezado de Connection
faltante, en realidad parece ser un problema del lado del cliente. Exactamente cómo se desencadena el problema sigue siendo un misterio para mí.
También verifiqué que los encabezados de respuesta para la página de trabajo y la página problemática son los mismos. Lo más relevante es que siempre se devuelve el encabezado Persistent-Auth: true
en ambos casos.
Algunas suposiciones salvajes:
Esto sucede cuando solicita un Rol que no está en las Reclamaciones del usuario actualmente conectado. Verifique que, si está utilizando
[Authorize(Roles = "xyz")]
, el usuario actual realmente tiene ese rol.No está claro si su aplicación usa una cookie para la autenticación. Si es así, debería verlo con la solicitud. ¿Estás configurando
withCredentials: true
para cada solicitud?