web-dev-qa-db-fra.com

System.DirectoryServices - Le serveur n'est pas opérationnel

Je reçois une erreur d'un site Web sur lequel j'utilise l'authentification Windows.

Des choses étranges:

  • Ne survient que si l'utilisateur n'est pas encore enregistré dans la base de données (nouvel utilisateur inconnu)
  • Apparaît uniquement sur le système actif, tout va bien sur l'environnement de développement local

Voici ce que je reçois dans un courrier de connexion:

Source: System.DirectoryServices

Message: Le serveur n'est pas opérationnel.

Trace:
à System.DirectoryServices.DirectoryEntry.Bind (Boolean throwIfFail)
sur System.DirectoryServices.DirectoryEntry.Bind ()
sur System.DirectoryServices.DirectoryEntry.get_AdsObject ()
à System.DirectoryServices.DirectorySearcher.FindAll (Boolean findMoreThanOne)
sur System.DirectoryServices.DirectorySearcher.FindOne ()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser (String windowsUserName) 

Voici comment j'implémente DirectorySearch:

private void SaveUser(string windowsUserName)
{
    string[] domainAndUser = windowsUserName.Split('\\');
    string domain = domainAndUser[0];
    string username = domainAndUser[1];

    DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
    DirectorySearcher search = new DirectorySearcher(entry);

    try
    {
        // Bind to the native AdsObject to force authentication.
        search.Filter = "(SAMAccountName=" + username + ")";
        search.PropertiesToLoad.Add("cn");
        search.PropertiesToLoad.Add("sn");
        search.PropertiesToLoad.Add("givenName");
        search.PropertiesToLoad.Add("mail");

        SearchResult result = search.FindOne();

        if (result == null)
        {
            throw new Exception("No results found in Windows authentication.");
        }

        User userToSave = new User();
        userToSave.FirstName = (String) result.Properties["givenName"][0];
        userToSave.LastName = (String) result.Properties["sn"][0];
        userToSave.Email = (String) result.Properties["mail"][0];
        userToSave.Username = windowsUserName;
        userToSave.Guid = Guid.NewGuid();

        SaveUser(userToSave);
    }
    catch (Exception ex)
    {
        throw new Exception("Error authenticating user. " + ex.Message, ex);
    }
    finally
    {
        //Dispose service and search to prevent leek in memory
        entry.Dispose();
        search.Dispose();
    }
}

Si d'autres exemples de code sont nécessaires, dites-le moi simplement.

14
Tai Kahar

Votre problème est que vous utilisez un nom de domaine "ordinaire" pour la liaison - cela ne fonctionnera pas dans LDAP. En fait, si vous essayez de vous lier à LDAP://MyDomain, ce que vous êtes vraiment essayez de lier au server appelé MyDomain

Vous avez besoin d'une chaîne de liaison LDAP valide - quelque chose comme LDAP://dc=yourdomain,dc=local ou quelque chose.

Pour connaître votre contexte de liaison LDAP par défaut, utilisez l'extrait de code suivant:

DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");

if (deRoot != null)
{
   string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}

Une fois que vous avez cette chaîne, utilisez-la comme chaîne de liaison à votre serveur LDAP.

Et si vous êtes sur .NET 3.5 et supérieur, vous devriez vérifier l'espace de noms System.DirectoryServices.AccountManagement (S.DS.AM). Lisez tout a propos de ça ici:

Fondamentalement, vous pouvez définir un contexte de domaine et rechercher facilement des utilisateurs et/ou des groupes dans AD:

// set up domain context -- no domain name needed, uses default domain 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);

if(user != null)
{
   // do something here....     
}

Le nouveau S.DS.AM simplifie vraiment les discussions avec les utilisateurs et les groupes dans AD!

19
marc_s

Pour ajouter à la réponse de marc_s ci-dessus , je devais effectuer une recherche dans plusieurs domaines. Donc, pour chaque domaine, j’ai fait ce qui suit:

DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
1
Claudio Viz

Une erreur similaire m'est survenue (bien que cela se produise tout le temps et non dans des cas spécifiques, comme indiqué ici) en raison d'une mauvaise chaîne de connexion Active Directory. J'ai utilisé le corp au lieu de la prod 1. Utilisez quelque chose qui fonctionne pour une autre application de votre organisation, le cas échéant. 

0
boaz levinson

Vous pouvez utiliser des chaînes de liaison au format LDAP: //mydomain.com: 389. Je continuais à obtenir "Accès refusé" lorsque j'essayais d'utiliser le format LDAP: // DC = mydomain, DC = com. Une fois que je suis passé au format LDAP: //mydomain.com: 389 et lié à l'aide de l'indicateur AuthenticationTypes.ServerBind lors de la construction de mon DirectoryEntry, cela a très bien fonctionné. C'était dans Azure App Service.

0
r590