2010-08-26 30 views
15

Je tente d'utiliser la bibliothèque .NET System.DirectoryServices.AccountManagement pour obtenir UserPrincipal pour un utilisateur Active Directory particulier.UserPrincipal.FindByIdentity Autorisations

J'ai le code suivant:

PrincipalContext context = new PrincipalContext(ContextType.Domain, "DomainName"); 
userPrincipal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); 

Ce code est en cours d'exécution en tant qu'utilisateur de domaine valide, mais quand je l'exécute, je reçois l'exception suivante:

System.DirectoryServices. DirectoryServicesCOMException (0x8007052E): Échec d'ouverture de session: nom d'utilisateur inconnu ou mot de passe incorrect.

Ce qui est intéressant est que je peux faire l'appel suivant, en utilisant le même contexte, sans problème:

context.ValidateCredentials(username, password, ContextOptions.Negotiate) 

Idées?

+0

Cocher cette réponse: http://stackoverflow.com/questions/1863801/findbyidentity-failing-with-pricipaloperationexception-in-asp-net-webapp/3515280#3515280 –

Répondre

12

Vous devez utiliser le constructeur PrincipalContext qui prend le nom d'utilisateur et le mot de passe.

La raison pour laquelle Validate fonctionne est parce qu'elle utilise les informations d'identification fournies pour se lier au répertoire.

+0

Cela ne veut pas avoir beaucoup de sens pour moi. Vous dites que l'appel ValidateCredentials utilise les informations d'identification d'identités en cours, mais pas l'appel UserPrincipal.FindByIdentity, qui accepte le contexte en question? Si c'est le cas, comment puis-je l'utiliser pour utiliser l'identité actuelle (comme dans l'identité du thread) pour faire l'appel? Je n'ai pas de nom d'utilisateur ou de mot de passe à transmettre, car il s'agit d'une application exécutée en tant que compte de service lors de l'installation. Je ne peux pas stocker ces informations d'identification nulle part. – RMD

+0

Je pense que vous avez mal compris, ValidateCredentials utilise les informations d'identification fournies dans la liste des paramètres de ValidateCredentials - le contexte que vous avez défini n'a pas d'informations d'identification qui lui sont associées en dehors de celles du thread actuel. Je soupçonne que vos problèmes sont dans la configuration/déploiement du serveur. Assurez-vous que le compte exécutant le service a été délégué au sein du domaine. – Nate

+0

Oui, j'ai mal compris. L'utilisateur du thread actuel est définitivement un utilisateur de domaine valide. Quand vous dites "délégué au sein du domaine", que voulez-vous dire exactement? – RMD

3

Il semble que vous ayez des informations d'identification réseau stockées. Sous Windows, vous pouvez spécifier d'utiliser des informations d'identification réseau différentes lorsque vous tentez d'accéder à des ressources réseau. Je peux reproduire exactement le même problème que vous voyez en mettant en place une mauvaise identification de réseau.

En supposant que votre domaine s'appelle yourdomain.com, vous pouvez dire à Windows de toujours utiliser un nom d'utilisateur et un mot de passe spécifiques lorsqu'il parle à n'importe quel ordinateur avec votredomaine.com.

=== === de Windows 7/2008

  1. Lancer le "Crendentail Manager".
  2. Sous section Informations d'identification Windows, cliquez sur Add a Windows credentials
  3. Dans l'adresse réseau, mis en *.yourdomain.com
  4. nom d'utilisateur et mot de passe, mettre dans un mauvais nom d'utilisateur ou mot de passe incorrect

=== Windows XP/2000/2003 ===

  1. Cliquez sur Démarrer et Exécuter
  2. Tapez control keymgr.dll
  3. Cliquez sur le bouton Ajouter sur zone de texte « enregistré des noms d'utilisateur et mots de passe » dialogue
  4. Dans le serveur, mis en *.yourdomain.com
  5. nom d'utilisateur et mot de passe, mettre en mauvais nom d'utilisateur ou mot de passe incorrect

Si cela est vraiment le problème que vous rencontrez, la solution facile est de supprimer les mots de passe stockés.

Pourquoi contexte.ValidateCredentials (nom d'utilisateur, mot de passe, ContextOptions.Negotiate) fonctionne-t-il?C'est simplement parce que vous initialisez une autre authentification Kerberos/NTLM puisque vous fournissez à nouveau uername et password. Sous le capot, si Kerberos est choisi, il enverra au contrôleur de domaine le nom d'utilisateur et le mot de passe fournis et échangera contre un ticket Kerberos TGT. Ensuite, votre machine obtient un ticket de service sur le serveur LDAP en utilisant ce ticket TGT. Ensuite, votre machine enverra ce ticket de service au serveur LDAP. Notez que ce ticket de service ne sera pas conservé dans la session d'ouverture de session en cours.

Pourquoi UserPrincipal.FindByIdentity ne fonctionne pas? Si vous n'avez pas de mot de passe stocké, normalement cela devrait fonctionner car Windows utilisera simplement le ticket TGT de l'utilisateur d'ouverture de session en cours d'échange pour le ticket de service du serveur LDAP. Aucun processus de validation de nom d'utilisateur/mot de passe n'est impliqué. Toutefois, si vous avez un mot de passe de nom d'utilisateur incorrect, Windows pense qu'il ne doit pas utiliser le ticket TGT de l'utilisateur d'ouverture de session en cours. Au lieu de cela, il devrait obtenir un nouveau ticket TGT en utilisant le mot de passe réseau stocké. C'est la raison pour laquelle vous voyez System.DirectoryServices.DirectoryServicesCOMException (0x8007052E): Logon failure: unknown user name or bad password.

+0

Intéressant. Ce code fonctionne avec le contexte d'une application ASP.NET, donc je ne pense pas que les mots de passe stockés feraient une différence. Je vais vérifier pour voir si vous avez raison. – RMD

+0

@RMD Ah, vous avez manqué cette information. Utilisez-vous l'authentification Windows? Ou utilisez-vous simplement le compte de service local pour accéder à l'AD? –

+0

Comme je l'ai dit dans mon post original: "Ce code fonctionne comme un utilisateur de domaine valide". – RMD