Как получить правильные данные из Active Directory для аутентификации - PullRequest
3 голосов
/ 18 мая 2011

У меня есть клиентское сервисное решение, содержащее клиентское приложение Winforms и сервис WCF, размещенный в IIS.

В сервисе WCF я могу легко извлечь имя текущего пользователя (WindowsIdentity.Name), которое зарегистрировано наклиент с помощью пользовательского IAuthorizationPolicy.Это делается путем получения WindowsIdentity от входящего EvaluationContext в методе Evaluate.

WindowsIdentity.Name будет выглядеть примерно так: MyCompanyGroup\MyName

Для возможности связыванияк учетной записи AD в моей собственной модели членства, я должен иметь возможность позволить пользователю выбрать пользователя AD для привязки к клиенту Winforms.Чтобы извлечь группы AD и пользователей для дерева, я использую следующий код:

public static class ActiveDirectoryHandler
{
  public static List<ActiveDirectoryTreeNode> GetGroups()
  {
    DirectoryEntry objADAM = default(DirectoryEntry);
    // Binding object. 
    DirectoryEntry objGroupEntry = default(DirectoryEntry);
    // Group Results. 
    DirectorySearcher objSearchADAM = default(DirectorySearcher);
    // Search object. 
    SearchResultCollection objSearchResults = default(SearchResultCollection);
    // Results collection. 
    string strPath = null;
    // Binding path. 
    List<ActiveDirectoryTreeNode> result = new List<ActiveDirectoryTreeNode>();

    // Construct the binding string. 
    strPath = "LDAP://stefanserver.stefannet.local";
    //Change to your ADserver 

    // Get the AD LDS object. 
    try
    {
        objADAM = new DirectoryEntry();//strPath);
        objADAM.RefreshCache();
    }
    catch (Exception e)
    {
        throw e;
    }

    // Get search object, specify filter and scope, 
    // perform search. 
    try
    {
        objSearchADAM = new DirectorySearcher(objADAM);
        objSearchADAM.Filter = "(&(objectClass=group))";
        objSearchADAM.SearchScope = SearchScope.Subtree;
        objSearchResults = objSearchADAM.FindAll();
    }
    catch (Exception e)
    {
        throw e;
    }

    // Enumerate groups 
    try
    {
        if (objSearchResults.Count != 0)
        {
            //SearchResult objResult = default(SearchResult);
            foreach (SearchResult objResult in objSearchResults)
            {
                objGroupEntry = objResult.GetDirectoryEntry();
                result.Add(new ActiveDirectoryTreeNode() { Id = objGroupEntry.Guid, ParentId = objGroupEntry.Parent.Guid, Text = objGroupEntry.Name, Type = ActiveDirectoryType.Group, PickableNode = false });

                foreach (object child in objGroupEntry.Properties["member"])
                    result.Add(new ActiveDirectoryTreeNode() { Id= Guid.NewGuid(), ParentId = objGroupEntry.Guid, Text = child.ToString(), Type = ActiveDirectoryType.User, PickableNode = true });
            }
        }
        else
        {
            throw new Exception("No groups found");
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.Message);
    }

    return result;
  } 
}

public class ActiveDirectoryTreeNode : ISearchable
{
    private Boolean _pickableNode = false;
#region Properties
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 0, VisibleInListMode = false, Editable = false)]
public Guid Id { get; set; }
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 1, VisibleInListMode = false, Editable = false)]
public Guid ParentId { get; set; }
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 2, Editable = false)]
public string Text { get; set; }
public ActiveDirectoryType Type { get; set; }
#endregion

#region ISearchable
public string SearchString
{
    get { return Text.ToLower(); }
}

public bool PickableNode
{
    get { return _pickableNode; }
    set { _pickableNode = value; }
}
#endregion

}

public enum ActiveDirectoryType
{
    Group,
    User
}

Дерево может выглядеть примерно так:

CN=Users*
- CN=Domain Guests,CN=Users,DC=MyCompany,DC=local
- CN=5-1-5-11,CN=ForeignSecurityPrinipals,DC=MyCompany,DC=local
...
CN=Domain Admins
- CN=MyName,CN=Users,DC=MyCompany,DC=local
...

(* = Group)

Имя имеет другой формат, и я не вижу, как это можно сравнить с именем в службе.

Так как мне извлечь правильные данные Active Directory для дерева?

1 Ответ

1 голос
/ 18 мая 2011

Я не могу утверждать, что понимаю, о чем вы спрашиваете, но вот некоторая информация, которую, я надеюсь, вы найдете полезной.

Имя входа, которое вы видите в своей службе (т.е. «MyName»), соответствует свойству в AD, называемому sAMAccountName. Вы можете получить sAMAccountName из DirectoryEntry через коллекцию Properties. Например, если вы хотите показать sAMAccountName для каждого члена вашей группы, вы можете сделать следующее:

var objSearchADAM = new DirectorySearcher();
objSearchADAM.Filter = "(&(objectClass=group))";
objSearchADAM.SearchScope = SearchScope.Subtree;
var objSearchResults = objSearchADAM.FindAll();

foreach (SearchResult objResult in objSearchResults)
{
    using (var objGroupEntry = objResult.GetDirectoryEntry())
    {
        foreach (string child in objGroupEntry.Properties["member"])
        {
            var path = "LDAP://" + child.Replace("/", "\\/");
            using (var memberEntry = new DirectoryEntry(path))
            {
                if (memberEntry.Properties.Contains("sAMAccountName"))
                {
                    // Get sAMAccountName
                    string sAMAccountName = memberEntry.Properties["sAMAccountName"][0].ToString();
                    Console.WriteLine(sAMAccountName);
                }

                if (memberEntry.Properties.Contains("objectSid"))
                {
                    // Get objectSid
                    byte[] sidBytes = (byte[]) memberEntry.Properties["objectSid"][0];
                    var sid = new System.Security.Principal.SecurityIdentifier(sidBytes, 0);
                    Console.WriteLine(sid.ToString());
                }
            }
        }
    }
}

Вы также можете найти UserPrincipal интересным. С помощью этого класса вы можете очень легко подключиться к объекту пользователя в вашей AD с помощью метода FindByIdentity, как показано ниже:

var ctx = new PrincipalContext(ContextType.Domain, null);
using (var up = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "MyName"))
{
    Console.WriteLine(up.DistinguishedName);
    Console.WriteLine(up.SamAccountName);

    // Print groups that this user is a member of
    foreach (var group in up.GetGroups())
    {
        Console.WriteLine(group.SamAccountName);
    }
}
...