Programing

Active Directory에서 사용자 그룹을 가져 오는 방법은 무엇입니까?

lottogame 2020. 8. 14. 08:13
반응형

Active Directory에서 사용자 그룹을 가져 오는 방법은 무엇입니까? (c #, asp.net)


이 코드를 사용하여 현재 사용자의 그룹을 가져옵니다. 하지만 수동으로 사용자에게 부여한 다음 그의 그룹을 얻고 싶습니다. 어떻게 할 수 있습니까?

using System.Security.Principal;

public ArrayList Groups()
{
    ArrayList groups = new ArrayList();

    foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
    {
        groups.Add(group.Translate(typeof(NTAccount)).ToString());
    }

    return groups;
}

.NET 3.5 이상을 사용하는 경우 새 System.DirectoryServices.AccountManagement(S.DS.AM) 네임 스페이스를 사용하면 예전보다 훨씬 쉽게 만들 수 있습니다.

여기에서 모든 내용을 읽어보십시오 : .NET Framework 3.5에서 디렉터리 보안 주체 관리

업데이트 : 이전 MSDN 잡지 기사가 더 이상 온라인 상태가 아닙니다. Microsoft에서 2008 년 1 월 MSDN 잡지의 CHM다운로드하고 해당 기사를 읽어야합니다.

기본적으로 "주요 컨텍스트"(일반적으로 도메인)와 사용자 주체가 있어야하며 그룹을 매우 쉽게 얻을 수 있습니다.

public List<GroupPrincipal> GetGroups(string userName)
{
   List<GroupPrincipal> result = new List<GroupPrincipal>();

   // establish domain context
   PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

   // find your user
   UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);

   // if found - grab its groups
   if(user != null)
   {
      PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();

      // iterate over all groups
      foreach(Principal p in groups)
      {
         // make sure to add only group principals
         if(p is GroupPrincipal)
         {
             result.Add((GroupPrincipal)p);
         }
      }
   }

   return result;
}

그게 전부입니다! 이제 사용자가 속한 권한 그룹의 결과 (목록)가 생겼습니다.이를 반복하고 이름을 인쇄하거나 수행해야하는 모든 작업을 수행 할 수 있습니다.

업데이트 :UserPrincipal 개체 에 표시되지 않는 특정 속성에 액세스 하려면 기본을 파헤쳐 야합니다 DirectoryEntry.

public string GetDepartment(Principal principal)
{
    string result = string.Empty;

    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry);

    if (de != null)
    {
       if (de.Properties.Contains("department"))
       {
          result = de.Properties["department"][0].ToString();
       }
    }

    return result;
}

업데이트 # 2 : 이 두 코드 조각을 합치는 것이 너무 어렵지는 않을 것 같습니다 ....하지만 좋아요-여기에 있습니다.

public string GetDepartment(string username)
{
    string result = string.Empty;

    // if you do repeated domain access, you might want to do this *once* outside this method, 
    // and pass it in as a second parameter!
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

    // find the user
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);

    // if user is found
    if(user != null)
    {
       // get DirectoryEntry underlying it
       DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);

       if (de != null)
       {
          if (de.Properties.Contains("department"))
          {
             result = de.Properties["department"][0].ToString();
          }
       }
    }

    return result;
}

GetAuthorizationGroups()중첩 된 그룹을 찾지 못합니다. 특정 사용자가 구성원 인 모든 그룹 (중첩 된 그룹 포함)을 실제로 얻으려면 다음을 시도하십시오.

using System.Security.Principal

private List<string> GetGroups(string userName)
{
    List<string> result = new List<string>();
    WindowsIdentity wi = new WindowsIdentity(userName);

    foreach (IdentityReference group in wi.Groups)
    {
        try
        {
            result.Add(group.Translate(typeof(NTAccount)).ToString());
        }
        catch (Exception ex) { }
    }
    result.Sort();
    return result;
}

내가 사용하는 try/catch일부 SID를 더 이상 사용할 수 있기 때문에 매우 큰 AD 200 개 그룹이 밖으로 몇 가지 예외가 없었기 때문에. ( Translate()호출은 SID-> 이름 변환을 수행합니다.)


First of all, GetAuthorizationGroups() is a great function but unfortunately has 2 disadvantages:

  1. Performance is poor, especially in big company's with many users and groups. It fetches a lot more data then you actually need and does a server call for each loop iteration in the result
  2. It contains bugs which can cause your application to stop working 'some day' when groups and users are evolving. Microsoft recognized the issue and is related with some SID's. The error you'll get is "An error occurred while enumerating the groups"

Therefore, I've wrote a small function to replace GetAuthorizationGroups() with better performance and error-safe. It does only 1 LDAP call with a query using indexed fields. It can be easily extended if you need more properties than only the group names ("cn" property).

// Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain")
public static List<string> GetAdGroupsForUser2(string userName, string domainName = null)
{
    var result = new List<string>();

    if (userName.Contains('\\') || userName.Contains('/'))
    {
        domainName = userName.Split(new char[] { '\\', '/' })[0];
        userName = userName.Split(new char[] { '\\', '/' })[1];
    }

    using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName))
        using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName))
            using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name)))
            {
                searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName);
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PropertiesToLoad.Add("cn");

                foreach (SearchResult entry in searcher.FindAll())
                    if (entry.Properties.Contains("cn"))
                        result.Add(entry.Properties["cn"][0].ToString());
            }

    return result;
}

Within the AD every user has a property memberOf. This contains a list of all groups he belongs to.

Here is a little code example:

// (replace "part_of_user_name" with some partial user name existing in your AD)
var userNameContains = "part_of_user_name";

var identity = WindowsIdentity.GetCurrent().User;
var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>();

var allSearcher = allDomains.Select(domain =>
{
    var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name));

    // Apply some filter to focus on only some specfic objects
    searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains);
    return searcher;
});

var directoryEntriesFound = allSearcher
    .SelectMany(searcher => searcher.FindAll()
        .Cast<SearchResult>()
        .Select(result => result.GetDirectoryEntry()));

var memberOf = directoryEntriesFound.Select(entry =>
{
    using (entry)
    {
        return new
        {
            Name = entry.Name,
            GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString())
        };
    }
});

foreach (var item in memberOf)
{
    Debug.Print("Name = " + item.Name);
    Debug.Print("Member of:");

    foreach (var groupName in item.GroupName)
    {
        Debug.Print("   " + groupName);
    }

    Debug.Print(String.Empty);
}
}

In my case the only way I could keep using GetGroups() without any expcetion was adding the user (USER_WITH_PERMISSION) to the group which has permission to read the AD (Active Directory). It's extremely essential to construct the PrincipalContext passing this user and password.

var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS");
var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName);
var groups = user.GetGroups();

Steps you may follow inside Active Directory to get it working:

  1. Into Active Directory create a group (or take one) and under secutiry tab add "Windows Authorization Access Group"
  2. Click on "Advanced" button
  3. Select "Windows Authorization Access Group" and click on "View"
  4. Check "Read tokenGroupsGlobalAndUniversal"
  5. Locate the desired user and add to the group you created (taken) from the first step

In case Translate works locally but not remotly e.i group.Translate(typeof(NTAccount)

If you want to have the application code executes using the LOGGED IN USER identity, then enable impersonation. Impersonation can be enabled thru IIS or by adding the following element in the web.config.

<system.web>
<identity impersonate="true"/>

If impersonation is enabled, the application executes using the permissions found in your user account. So if the logged in user has access, to a specific network resource, only then will he be able to access that resource thru the application.

Thank PRAGIM tech for this information from his diligent video

Windows authentication in asp.net Part 87:

https://www.youtube.com/watch?v=zftmaZ3ySMc

But impersonation creates a lot of overhead on the server

The best solution to allow users of certain network groups is to deny anonymous in the web config <authorization><deny users="?"/><authentication mode="Windows"/>

and in your code behind, preferably in the global.asax, use the HttpContext.Current.User.IsInRole :

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
If HttpContext.Current.User.IsInRole("TheDomain\TheGroup") Then
//code to do when user is in group
End If

NOTE: The Group must be written with a backslash \ i.e. "TheDomain\TheGroup"


This works for me

public string[] GetGroupNames(string domainName, string userName)
    {
        List<string> result = new List<string>();

        using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domainName))
        {
            using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(principalContext, userName).GetGroups())
            {
                src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
            }
        }

        return result.ToArray();
    }

The answer depends on what kind of groups you want to retrieve. The System.DirectoryServices.AccountManagement namespace provides two group retrieval methods:

GetGroups - Returns a collection of group objects that specify the groups of which the current principal is a member.

This overloaded method only returns the groups of which the principal is directly a member; no recursive searches are performed.

GetAuthorizationGroups - Returns a collection of principal objects that contains all the authorization groups of which this user is a member. This function only returns groups that are security groups; distribution groups are not returned.

This method searches all groups recursively and returns the groups in which the user is a member. The returned set may also include additional groups that system would consider the user a member of for authorization purposes.

So GetGroups gets all groups of which the user is a direct member, and GetAuthorizationGroups gets all authorization groups of which the user is a direct or indirect member.

Despite the way they are named, one is not a subset of the other. There may be groups returned by GetGroups not returned by GetAuthorizationGroups, and vice versa.

Here's a usage example:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "MyDomain", "OU=AllUsers,DC=MyDomain,DC=Local");
UserPrincipal inputUser = new UserPrincipal(domainContext);
inputUser.SamAccountName = "bsmith";
PrincipalSearcher adSearcher = new PrincipalSearcher(inputUser);
inputUser = (UserPrincipal)adSearcher.FindAll().ElementAt(0);
var userGroups = inputUser.GetGroups();

참고URL : https://stackoverflow.com/questions/5309988/how-to-get-the-groups-of-a-user-in-active-directory-c-asp-net

반응형