Imansible autenticare il servizio Api Web ASP.NET con HttpClient

Dispongo di un servizio API Web ASP.NET che viene eseguito su un server Web con l’autenticazione di Windows abilitata.

Ho un sito client creato su MVC4 che viene eseguito in un sito diverso sullo stesso server Web che utilizza HttpClient per estrarre i dati dal servizio. Questo sito client viene eseguito con la rappresentazione di id quadro abilitata e utilizza anche l’autenticazione di Windows.

Il server Web è Windows Server 2008 R2 con IIS 7.5.

La sfida che sto avendo è ottenere HttpClient per passare l’utente Windows corrente come parte del suo processo di autenticazione. Ho configurato HttpClient in questo modo:

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

La mia comprensione è che l’esecuzione del sito con la rappresentazione di id quadro triggersta e quindi la creazione del client in questo modo dovrebbe comportare l’autenticazione del client con il servizio utilizzando l’identity framework rappresentata dell’utente attualmente connesso.

Questo non sta succedendo. In effetti, il client non sembra affatto autenticare.

Il servizio è configurato per utilizzare l’autenticazione di Windows e questo sembra funzionare perfettamente. Posso andare su http: // server / api / shippers nel mio browser web e chiedere l’autenticazione di Windows, una volta inserito ricevo i dati richiesti.

Nei registri di IIS vedo le richieste API ricevute senza autenticazione e ricevendo una risposta di prova 401.

La documentazione su questo sembra essere scarsa.

Ho bisogno di alcune informazioni su ciò che potrebbe essere sbagliato o un altro modo di utilizzare l’autenticazione di Windows con questa applicazione.

Grazie, Craig

    Ho studiato il codice sorgente di HttpClientHandler (l’ultima versione che sono riuscito a mettere le mani su) e questo è ciò che può essere trovato nel metodo 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); 

    Ora, se controlli all’interno del tuo codice il valore di SecurityContext.IsWindowsIdentityFlowSuppressed () probabilmente diventerai vero. Di conseguenza, il metodo StartRequest viene eseguito nel nuovo thread con le credenziali del processo asp.net (non le credenziali dell’utente rappresentato).

    Ci sono due possibili modi per uscire da questo. Se hai accesso al tuo server aspnet_config.config, dovresti impostare le seguenti impostazioni (l’impostazione di quelle in web.config sembra non avere alcun effetto):

       

    Se non è ansible modificare aspnet_config.config, sarà necessario creare il proprio HttpClientHandler per supportare questo scenario.

    AGGIORNAMENTO SULL’USO DEL FQDN

    Il problema che hai riscontrato è una funzionalità di Windows progettata per la protezione dagli “attacchi di riflessione”. Per ovviare a ciò è necessario autorizzare il dominio a cui si sta tentando di accedere sulla macchina che sta tentando di accedere al server. Segui i passaggi seguenti:

    1. Vai a Start -> Esegui -> regedit
    2. Individua la HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 .
    3. Fai clic destro su di esso, scegli Nuovo e quindi Valore multistringa .
    4. Digitare BackConnectionHostNames ( INVIO ).
    5. Fare clic con il tasto destro del mouse sul valore appena creato e selezionare Modifica .
    6. Inserire i nomi host per i siti che si trovano sul computer locale nella casella del valore e fare clic su OK (ciascun nome host / nome di dominio completo deve essere sulla stessa riga, nessun carattere jolly, il nome deve corrispondere esattamente) .
    7. Salva tutto e riavvia la macchina

    Puoi leggere l’intero articolo KB relativo al problema qui .

    Stavo anche avendo lo stesso problema. Grazie alla ricerca fatta da @tpeczek, ho sviluppato la seguente soluzione: invece di usare HttpClient (che crea thread e invia richieste async), ho usato la class WebClient che emette richieste sullo stesso thread. Ciò consente di trasmettere l’id quadro dell’utente a WebAPI da un’altra applicazione ASP.NET.

    Lo svantaggio evidente è che questo non funzionerà in modo asincrono.

     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: richiede il pacchetto NuGet: Newtonsoft.Json, che è lo stesso serializzatore JSON utilizzato da WebAPI.

    Il motivo per cui questo non funziona è perché è necessaria l’autenticazione doppio hop.

    Il primo hop è il web server, ottenere la rappresentazione con l’autenticazione di Windows per lavorare non ci sono problemi. Tuttavia, quando si utilizza HttpClient o WebClient per autenticare l’utente su un altro server, il server Web deve essere eseguito su un account che disponga dell’authorization necessaria per eseguire la delega necessaria.

    Vedi il seguente per maggiori dettagli:
    http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx

    Correggere usando il comando “setspn”:
    http://www.phishthis.com/2009/10/24/how-to-configure-ad-sql-and-iis-for-two-hop-kerberos-authentication-2/ (Avrete bisogno di diritti di accesso sufficienti per eseguire queste operazioni.)

    Pensa solo a cosa succederebbe se a qualsiasi server fosse consentito inoltrare le tue credenziali come preferisce … Per evitare questo problema di sicurezza, il controller di dominio deve sapere a quali account è consentito eseguire la delega.

    Per impersonare l’utente originale (autenticato), utilizzare la seguente configurazione nel file Web.config:

       

    Con questa configurazione, ASP.NET impersona sempre l’utente autenticato e tutti gli accessi alle risorse vengono eseguiti utilizzando il contesto di sicurezza dell’utente autenticato.