web-dev-qa-db-fra.com

HttpClient & Auth Windows: Passer l'utilisateur du consommateur connecté au service

J'ai du mal à comprendre et à configurer un service et un consommateur où le service s'exécutera en tant qu'utilisateur connecté au consommateur.

Mon consommateur est une application MVC. Mon service est une application Web Api. Les deux fonctionnent sur des serveurs distincts au sein du même domaine. Les deux sont configurés pour utiliser Windows Auth.

Mon code de consommateur est:

private T GenericGet<T>(string p)
    {
        T result = default(T);

        HttpClientHandler handler = new HttpClientHandler() { PreAuthenticate = true, UseDefaultCredentials = true };
        using (HttpClient client = new HttpClient(handler))
        {
            client.BaseAddress = new Uri(serviceEndPoint);

            HttpResponseMessage response = client.GetAsync(p).Result;
            if (response.IsSuccessStatusCode)
                result = response.Content.ReadAsAsync<T>().Result;
        }

        return result;
    }

Dans mon service, j'appelle User.Identity.Name pour obtenir l'identifiant de l'appelant, mais cet identifiant revient toujours en tant qu'ID de pool d'applications consommateur, et non pas l'utilisateur connecté. Le pool d'applications client s'exécute en tant que service réseau, le serveur lui-même est approuvé pour la délégation. Alors, comment puis-je obtenir l'utilisateur connecté? Code de service:

    // GET: /Modules/5/Permissions/
    [Authorize]
    public ModulePermissionsDTO Get(int ModuleID)
    {
        Module module= moduleRepository.Find(ModuleID);
        if (module== null)
            throw new HttpResponseException(HttpStatusCode.NotFound);

        // This just shows as the App Pool the MVC consumer is running as (Network Service).
        IPrincipal loggedInUser = User;

        // Do I need to do something with this instead?
        string authHeader = HttpContext.Current.Request.Headers["Authorization"];

        ModulePermissionsDTO dto = new ModulePermissionsDTO();
        // Construct object here based on User...

        return dto;
    }

Selon cette question , Kerberos est nécessaire pour que cette configuration fonctionne, car HttpClient s'exécute dans un thread séparé. Cependant, cela me confond parce que je pensais que la demande envoyait un en-tête d'autorisation et que le service devrait donc pouvoir l'utiliser et récupérer le jeton de l'utilisateur. Quoi qu'il en soit, j'ai fait quelques tests avec Kerberos pour vérifier que cela fonctionne correctement sur mon domaine en utilisant la démo de "Situation 5" ici et cela fonctionne mais mes deux applications ne transmettent toujours pas correctement l'utilisateur connecté.

Alors, que dois-je faire pour que cela fonctionne? Kerberos est-il nécessaire ou dois-je effectuer quelque chose dans mon service pour décompresser l'en-tête d'autorisation et créer un objet principal à partir du jeton? Tous les conseils appréciés.

14
James

La clé consiste à laisser votre application MVC (consommateur) emprunter l'identité de l'utilisateur appelant, puis à émettre les demandes HTTP de manière synchrone (c'est-à-dire sans générer de nouveau thread). Vous ne devriez pas avoir à vous préoccuper des détails d'implémentation de bas niveau, tels que NTLM vs Kerberos.

Consommateur

Configurez votre application MVC comme suit: 

  1. Démarrer IIS Manager
  2. Sélectionnez votre application Web MVC
  3. Double-cliquez sur 'Authentification'
  4. Activer 'Emprunt d'identité ASP.NET'
  5. Activer 'Authentification Windows'
  6. Disable autres formes d'authentification (sauf peut-être Digest si vous en avez besoin)
  7. Ouvrez le fichier Web.config à la racine de votre application MVC et assurez-vous que <authentication mode="Windows" />

Pour émettre la requête HTTP, je vous recommande d'utiliser l'excellente bibliothèque RestSharp . Exemple:

var client = new RestClient("<your base url here>");
client.Authenticator = new NtlmAuthenticator();
var request = new RestRequest("Modules/5/Permissions", Method.GET);
var response = client.Execute<ModulePermissionsDTO>(request);

Un service

Configurez votre service API Web comme suit: 

  1. Démarrer IIS Manager
  2. Sélectionnez votre service API Web
  3. Double-cliquez sur 'Authentification'
  4. Disable 'Emprunt d'identité ASP.NET'.
  5. Activer 'Authentification Windows'
  6. Si seul un sous-ensemble de vos méthodes de l'API Web requiert l'authentification des utilisateurs, laissez l'option 'Authentification anonyme' activée. 
  7. Ouvrez le fichier Web.config à la racine de votre service API Web et assurez-vous que <authentication mode="Windows" />

Je constate que vous avez déjà décoré votre méthode avec un attribut [Authorize] qui devrait déclencher un défi d'authentification (HTTP 401) lors de l'accès à la méthode. Vous devriez maintenant pouvoir accéder à l'identité de votre utilisateur final via la propriété User.Identity de votre classe ApiController.

13

Le problème clé du double saut est la délégation des informations d'identification de l'utilisateur au deuxième appel. Je veux élaborer un peu à ce sujet. C1 = navigateur client, S1 = premier serveur, S2 = deuxième serveur. 

Supposons notre authentification complète de la fenêtre de support système. Lorsque l'utilisateur accède à S1 à partir du navigateur, ses informations d'identification de fenêtre par défaut sont transmises au serveur S1, mais lorsque S1 appelle la base de données S2, il ne transmet pas par défaut les informations d'identification à S2.

Résolution: 

  1. Nous devons activer l'authentification/l'emprunt d'identité de fenêtre sur les deux machines.
  2. NOUS devons activer la délégation entre serveurs afin que S1 puisse faire confiance à S2 et transmette les informations d'identification à S2.

Vous trouverez des détails utiles aux liens ci-dessous: Http://blogs.msdn.com/b/farukcelik/archive/2008/01/02/how-to-set-up-a-kerberos-authentication -scenario-with-sql-server-linked-servers.aspx

https://sqlbadboy.wordpress.com/2013/10/11/the-kerberos-double-hop-problem/

0
Rahul Garg

Si vous essayez d'accéder à un service hébergé sur une authentification Windows, procédez comme suit.

var request = new RestRequest(Method.POST);

Si vous souhaitez utiliser les informations d'identification par défaut des applications qui doivent avoir un accès sur le serveur de service hébergé

request.UseDefaultCredentials = true;

ou utilisateur ci-dessous pour transmettre les informations d'identification manuellement

request.Credentials = new NetworkCredential("Username", "Password", "Domain");
0
sachin mhalungekar