servidor - C#Active Directory: ¿Obtener el nombre de dominio del usuario?
obtener nombre de usuario de windows c# (4)
Como no pude encontrar ningún código de ejemplo, me gustaría compartir mi propia solución. Esto buscará a los padres del objeto DirectoryEntry hasta que llegue a la clase domainDNS.
using System.DirectoryServices;
public static class Methods
{
public static T ldap_get_value<T>(PropertyValueCollection property)
{
object value = null;
foreach (object tmpValue in property) value = tmpValue;
return (T)value;
}
public static string ldap_get_domainname(DirectoryEntry entry)
{
if (entry == null || entry.Parent == null) return null;
using (DirectoryEntry parent = entry.Parent)
{
if (ldap_get_value<string>(parent.Properties["objectClass"]) == "domainDNS")
return ldap_get_value<string>(parent.Properties["dc"]);
else
return ldap_get_domainname(parent);
}
}
}
Úsalo así:
string[] _properties = new string[] { "objectClass", "distinguishedName", "samAccountName", "userPrincipalName", "displayName", "mail", "title", "company", "thumbnailPhoto", "useraccountcontrol" };
string account = "my-user-name";
// OR even better:
// string account = "[email protected]";
using (DirectoryEntry ldap = new DirectoryEntry())
{
using (DirectorySearcher searcher = new DirectorySearcher(ldap))
{
searcher.PropertiesToLoad.AddRange(_properties);
if (account.Contains(''@'')) searcher.Filter = "(userPrincipalName=" + account + ")";
else searcher.Filter = "(samAccountName=" + account + ")";
var user = searcher.FindOne().GetDirectoryEntry();
Console.WriteLine("Name: " + Methods.ldap_get_value<string>(user.Properties["displayName"]));
Console.WriteLine("Domain: " + Methods.ldap_get_domainname(user));
Console.WriteLine("Login: " + Methods.ldap_get_domainname(user) + "//" + Methods.ldap_get_value<string>(user.Properties["samAccountName"]));
}
}
No tengo un bosque para probarlo, pero en teoría esto debería cortarlo.
Sé que este tipo de pregunta se ha hecho antes, pero otros métodos me están fallando en este momento.
En su forma actual, nuestro servicio de Windows sondea AD, dado un LDAP (es decir, LDAP: //10.32.16.80) y una lista de grupos de usuarios dentro de ese servidor AD para buscar. Recupera a todos los usuarios dentro de esos grupos dados, buscando recursivamente esos grupos para más grupos también. Cada usuario se agrega a la lista de otros usuarios autenticados.
Esta parte de la aplicación se está ejecutando con éxito. Sin embargo, necesitamos el nombre de dominio amigable de cada usuario (es decir, la parte de su inicio de sesión DOMINIO / nombre de usuario)
Entonces, si hay un usuario que forma parte del dominio TEST, llamado Steve: TEST / steve es su nombre de usuario. Puedo encontrar a Steve en el AD, sin embargo, también necesito que se almacene "TEST" junto con su información de AD.
Una vez más, puedo encontrar bien a ''steve'' utilizando un buscador de directorios y la IP de LDAP que tengo, pero dada la IP de LDAP, ¿cómo puedo encontrar el nombre de dominio amigable?
Cuando intento el siguiente código, aparece un error cuando intento acceder al ''defaultNamingContext'':
System.Runtime.InteropServices.COMException (0x8007202A): el mecanismo de autenticación es desconocido.
Aquí está el código:
private string SetCurrentDomain(string server)
{
string result = string.Empty;
try
{
logger.Debug("''SetCurrentDomain''; Instantiating rootDSE LDAP");
DirectoryEntry ldapRoot = new DirectoryEntry(server + "/rootDSE", username, password);
logger.Debug("''SetCurrentDomain''; Successfully instantiated rootDSE LDAP");
logger.Debug("Attempting to retrieve ''defaultNamingContext''...");
string domain = (string)ldapRoot.Properties["defaultNamingContext"][0]; //THIS IS WHERE I HIT THE COMEXCEPTION
logger.Debug("Retrieved ''defaultNamingContext'': " + domain);
if (!domain.IsEmpty())
{
logger.Debug("''SetCurrentDomain''; Instantiating partitions/configuration LDAP entry");
DirectoryEntry parts = new DirectoryEntry(server + "/CN=Partitions,CN=Configuration," + domain, username, password);
logger.Debug("''SetCurrentDomain''; Successfully instantiated partitions/configuration LDAP entry");
foreach (DirectoryEntry part in parts.Children)
{
if (part.Properties["nCName"] != null && (string)part.Properties["nCName"][0] != null)
{
logger.Debug("''SetCurrentDomain''; Found property nCName");
if ((string)part.Properties["nCName"][0] == domain)
{
logger.Debug("''SetCurrentDomain''; nCName matched defaultnamingcontext");
result = (string)part.Properties["NetBIOSName"][0];
logger.Debug("''SetCurrentDomain''; Found NetBIOSName (friendly domain name): " + result);
break;
}
}
}
}
logger.Debug("finished setting current domain...");
}
catch (Exception ex)
{
logger.Error("error attempting to set domain:" + ex.ToString());
}
return result;
}
editar
Agregué este método de muestra para intentar una sugerencia, pero obtengo una excepción: "Error no especificado" cuando presioné la llamada "FindAll ()" en el buscador. La cadena que se pasa es: "CN = TEST USER, CN = Users, DC = tempe, DC = ktregression, DC = com"
private string GetUserDomain(string dn)
{
string domain = string.Empty;
string firstPart = dn.Substring(dn.IndexOf("DC="));
string secondPart = "CN=Partitions,CN=Configuration," + firstPart;
DirectoryEntry root = new DirectoryEntry(secondPart, textBox2.Text, textBox3.Text);
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.Filter = "(&(nCName=" + firstPart + ")(nETBIOSName=*))";
try
{
SearchResultCollection rs = searcher.FindAll();
if (rs != null)
{
domain = GetProperty(rs[0], "nETBIOSName");
}
}
catch (Exception ex)
{
}
return domain;
Este artículo me ayudó mucho a entender cómo trabajar con Active Directory.
Howto: (Almost) Everything In Active Directory via C#
A partir de este momento, si necesita más asistencia, hágamelo saber con las preguntas adecuadas en el comentario, y las responderé de la mejor manera posible.
EDITAR # 1
Será mejor que vayas con el filtro de este ejemplo. He escrito algunos ejemplos de código para mostrar brevemente cómo trabajar con los espacios de nombres System.DirectoryServices
y System.DirectoryServices.ActiveDirectory
. El espacio de nombres System.DirectoryServices.ActiveDirectory se usa para recuperar información sobre los dominios dentro de su bosque.
private IEnumerable<DirectoryEntry> GetDomains() {
ICollection<string> domains = new List<string>();
// Querying the current Forest for the domains within.
foreach(Domain d in Forest.GetCurrentForest().Domains)
domains.Add(d.Name);
return domains;
}
private string GetDomainFullName(string friendlyName) {
DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, friendlyName);
Domain domain = Domain.GetDomain(context);
return domain.Name;
}
private IEnumerable<string> GetUserDomain(string userName) {
foreach(string d in GetDomains())
// From the domains obtained from the Forest, we search the domain subtree for the given userName.
using (DirectoryEntry domain = new DirectoryEntry(GetDomainFullName(d))) {
using (DirectorySearcher searcher = new DirectorySearcher()){
searcher.SearchRoot = domain;
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
// The Filter is very important, so is its query string. The ''objectClass'' parameter is mandatory.
// Once we specified the ''objectClass'', we want to look for the user whose login
// login is userName.
searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", userName);
try {
SearchResultCollection results = searcher.FindAll();
// If the user cannot be found, then let''s check next domain.
if (results == null || results.Count = 0)
continue;
// Here, we yield return for we want all of the domain which this userName is authenticated.
yield return domain.Path;
} finally {
searcher.Dispose();
domain.Dispose();
}
}
}
Aquí, no probé este código y podría tener algunos problemas menores que solucionar. Esta muestra se proporciona tal como es para ayudarle. Espero que esto sea de ayuda.
EDITAR # 2
Me enteré de otra salida:
- Primero debe ver si puede encontrar la cuenta de usuario dentro de su dominio;
- Si lo encuentra, entonces obtenga el nombre de dominio NetBIOS; y
- concaténelo en una barra invertida (****) y el inicio de sesión encontrado.
El siguiente ejemplo utiliza un NUnit TestCase que puede probar por sí mismo y ver si hace lo que se le exige.
[TestCase("LDAP://fully.qualified.domain.name", "TestUser1")]
public void GetNetBiosName(string ldapUrl, string login)
string netBiosName = null;
string foundLogin = null;
using (DirectoryEntry root = new DirectoryEntry(ldapUrl))
Using (DirectorySearcher searcher = new DirectorySearcher(root) {
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", login);
SearchResult result = null;
try {
result = searcher.FindOne();
if (result == null)
if (string.Equals(login, result.GetDirectoryEntry().Properties("sAMAccountName").Value))
foundLogin = result.GetDirectoryEntry().Properties("sAMAccountName").Value
} finally {
searcher.Dispose();
root.Dispose();
if (result != null) result = null;
}
}
if (!string.IsNullOrEmpty(foundLogin))
using (DirectoryEntry root = new DirectoryEntry(ldapUrl.Insert(7, "CN=Partitions,CN=Configuration,DC=").Replace(".", ",DC="))
Using DirectorySearcher searcher = new DirectorySearcher(root)
searcher.Filter = "nETBIOSName=*";
searcher.PropertiesToLoad.Add("cn");
SearchResultCollection results = null;
try {
results = searcher.FindAll();
if (results != null && results.Count > 0 && results[0] != null) {
ResultPropertyValueCollection values = results[0].Properties("cn");
netBiosName = rpvc[0].ToString();
} finally {
searcher.Dispose();
root.Dispose();
if (results != null) {
results.Dispose();
results = null;
}
}
}
Assert.AreEqual("FULLY/TESTUSER1", string.Concat(netBiosName, "/", foundLogin).ToUpperInvariant())
}
La fuente de la que me inspiré es:
Encuentra el nombre de NetBios de un dominio en AD
Puede recuperar el nombre del dominio en el que se encuentra el usuario actual utilizando la propiedad Environment.UserDomainName .
string domainName;
domainName = System.Environment.UserDomainName;
Quizás no sea del todo correcto pero ...
DirectoryEntry dirEntry = new DirectoryEntry();
DirectorySearcher dirSearcher = new DirectorySearcher(dirEntry);
dirSearcher.SearchScope = SearchScope.Subtree;
dirSearcher.Filter = string.Format("(&(objectClass=user)(|(cn={0})(sn={0}*)(givenName={0})(sAMAccountName={0}*)))", userName);
var searchResults = dirSearcher.FindAll();
foreach (SearchResult sr in searchResults)
{
var de = sr.GetDirectoryEntry();
string user = de.Properties["SAMAccountName"][0].ToString();
string domain = de.Path.ToString().Split(new [] { ",DC=" },StringSplitOptions.None)[1];
MessageBox.Show(domain + "/" + user);
}
Porque el valor de de.Path es
LDAP: // CN = Nombre completo , DC = dominio , DC = local