32

Tengo un servicio ASP.NET Web API que se ejecuta en un servidor web con la Autenticación de Windows habilitada.No se puede autenticar en el servicio ASP.NET Web Api con HttpClient

Tengo un sitio de cliente creado en MVC4 que se ejecuta en un sitio diferente en el mismo servidor web que utiliza HttpClient para extraer datos del servicio. Este sitio de cliente se ejecuta con suplantación de identidad habilitada y también usa la autenticación de Windows.

El servidor web es Windows Server 2008 R2 con IIS 7.5.

El reto que tengo es conseguir que el HttpClient pase al usuario actual de Windows como parte de su proceso de autenticación. He configurado el HttpClient de esta manera:

var clientHandler = new HttpClientHandler(); 
clientHandler.UseDefaultCredentials = true; 
clientHandler.PreAuthenticate = true; 
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic; 
var httpClient = new HttpClient(clientHandler); 

Mi entendimiento es que ejecuta el sitio de suplantación de identidad habilitado y luego construir el cliente de esta manera debe dar lugar a que el cliente autenticarse en el servicio utilizando la identidad suplantada de la usuario actualmente conectado.

Esto no está sucediendo. De hecho, el cliente no parece autenticarse en absoluto.

El servicio está configurado para usar la autenticación de Windows y esto parece funcionar perfectamente. Puedo ir al http://server/api/shippers en mi navegador web y se me solicita la autenticación de Windows. Una vez ingresado, recibo los datos solicitados.

En los registros de IIS veo que se reciben las solicitudes de API sin autenticación y se recibe una respuesta de desafío 401.

La documentación sobre este parece ser escasa.

Necesito una idea de lo que podría estar mal u otra forma de usar la autenticación de Windows con esta aplicación.

gracias, Craig

Respuesta

31

he investigado el código fuente de HttpClientHandler (la versión más reciente pude tener en mis manos) y esto es lo que se puede encontrar en el método SendAsync:

// BeginGetResponse/BeginGetRequestStream have a lot of setup work to do before becoming async 
// (proxy, dns, connection pooling, etc). Run these on a separate thread. 
// Do not provide a cancellation token; if this helper task could be canceled before starting then 
// nobody would complete the tcs. 
Task.Factory.StartNew(startRequest, state); 

Ahora, si verifica dentro de su código el valor de SecurityContext.IsWindowsIdentityFlowSuppressed(), probablemente sea cierto. Como resultado, el método StartRequest se ejecuta en un nuevo hilo con las credenciales del proceso asp.net (no las credenciales del usuario suplantado).

Existen dos formas posibles de solucionar esto. Si usted tiene acceso a aspnet_config.config servidor suyo, debe establecer la siguiente configuración (configuración de los de web.config parece tener ningún efecto):

<legacyImpersonationPolicy enabled="false"/> 
<alwaysFlowImpersonationPolicy enabled="true"/> 

Si no puede cambiar el aspnet_config.config que tendrá para crear su propio HttpClientHandler para soportar este escenario.

ACTUALIZACIÓN sobre el uso del nombre de dominio completo

La cuestión que ha golpeado aquí es una característica de Windows que está diseñado para proteger contra ataques de "reflexión". Para solucionar este problema, debe incluir en la lista blanca el dominio al que intenta acceder en la máquina que intenta acceder al servidor.Siga los pasos siguientes:

  1. vaya a Inicio -> Ejecutar -> regedit
  2. Localizar HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 clave de registro.
  3. Haga clic derecho en él, elija Nuevo y luego valor de cadenas múltiples.
  4. Tipo BackConnectionHostNames (ENTER).
  5. Haga clic con el botón derecho en el valor creado y elija Modificar.
  6. Ponga los nombres de host para los sitios que están en la computadora local en el cuadro de valor y haga clic en Aceptar (cada nombre de host/FQDN debe estar en su propia línea, sin comodines, el nombre debe ser coincidencia exacta).
  7. Guardar todo y reiniciar la máquina

Puede leer el artículo completo KB respecto al tema here.

+0

Bien manchado! .. – Aliostad

+0

Seguí adelante y establecí estos valores sin ningún cambio en el comportamiento. Lo curioso es que puedo ver al cliente presionando el servidor y obteniendo una respuesta 401. El HttpClient simplemente NO envía información de autenticación y simplemente recibe el 401 y se cierra. ¿Alguna idea adicional? –

+0

Además, cambié la identidad del grupo de aplicaciones en el que se ejecuta el cliente para que sea una cuenta de Windows que tiene acceso al servicio. Esto no produce ningún cambio. Estoy perdido en este? –

8

También estaba teniendo el mismo problema. Gracias a la investigación realizada por @tpeczek, desarrollé la siguiente solución: en lugar de usar HttpClient (que crea subprocesos y envía solicitudes asincrónicas), utilicé la clase WebClient que emite solicitudes en el mismo hilo. Hacerlo me permite pasar la identidad del usuario a WebAPI desde otra aplicación ASP.NET.

El inconveniente obvio es que esto no funcionará de manera asincrónica.

var wi = (WindowsIdentity)HttpContext.User.Identity; 

var wic = wi.Impersonate(); 
try 
{ 
    var data = JsonConvert.SerializeObject(new 
    { 
     Property1 = 1, 
     Property2 = "blah" 
    }); 

    using (var client = new WebClient { UseDefaultCredentials = true }) 
    { 
     client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8"); 
     client.UploadData("http://url/api/controller", "POST", Encoding.UTF8.GetBytes(data)); 
    } 
} 
catch (Exception exc) 
{ 
    // handle exception 
} 
finally 
{ 
    wic.Undo(); 
} 

Nota: Requiere NuGet paquete: Newtonsoft.Json, que es utiliza el mismo serializador WebAPI JSON.

+0

Gracias, esto es lo que necesitaba. –

+0

Wow. WindowsImpersonationContext. Salvaste el día y mi cordura. Gracias. – granadaCoder

+0

¿Ha intentado utilizar las contrapartes asíncronas, como UploadDataAsync :-) –

0

La razón por la que esto no funciona es porque necesita autenticación de doble salto.

El primer salto es el servidor web, obteniendo la suplantación con la autenticación de Windows para que funcione no hay problema. Pero al usar HttpClient o WebClient para autenticarse en otro servidor, el servidor web debe ejecutarse en una cuenta que tenga permiso para realizar la delegación necesaria.

consulte los siguientes para más detalles:
http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx

arreglo mediante el "setspn" comando:
http://www.phishthis.com/2009/10/24/how-to-configure-ad-sql-and-iis-for-two-hop-kerberos-authentication-2/ (. Tendrá suficientes derechos de acceso para realizar estas operaciones)

Sólo considere lo ocurriría si se permitiera a cualquier servidor reenviar sus credenciales como lo desee ... Para evitar este problema de seguridad, el controlador de dominio necesita saber qué cuentas tienen permiso para realizar la delegación.

0

para suplantar al usuario original (autenticado), utilice la siguiente configuración en el archivo Web.config:

<authentication mode="Windows" /> 
<identity impersonate="true" /> 

Con esta configuración, siempre ASP.NET suplanta al usuario autenticado, y se lleva a cabo todos los accesos a los recursos utilizando el contexto de seguridad del usuario autenticado.

Cuestiones relacionadas