UserPrincipals.GetAuthorizationGroups An error (1301) occurred while enumerating the groups. After upgrading to Server 2012 Domain Controller

后端 未结 10 1203
陌清茗
陌清茗 2020-12-29 21:17

Research:

Similar Issue with workaround, but not actual solution to existing problem

Similar issue pointing to Microsoft End Point update as

相关标签:
10条回答
  • 2020-12-29 21:54

    If anyone is interested this is a VB.NET version of the same code. Few things you have to do before this code can work

    1) You have to reference the assembly System.DirectoryServices
    2) Make sure to pass "theusername" variable without the domain, so if your domain is "GIS" and your username is "Hussein" Windows generally authenticate you as GIS\Hussein. So you have to send in just purely the username "Hussein". I worked out the case sensitive stuff.
    3) The method GetGroupsNew takes a username and returns a list of groups
    4) The method isMemberofnew takes a username and a group and verifies that this user is part of that group or not, this is the one I was interested in.

    Private Function getGroupsNew(theusername As String) As List(Of String)
        Dim lstGroups As New List(Of String)
        Try
    
            Dim allDomains = Forest.GetCurrentForest().Domains.Cast(Of Domain)()
    
            Dim allSearcher = allDomains.[Select](Function(domain)
                                                      Dim searcher As New DirectorySearcher(New DirectoryEntry("LDAP://" + domain.Name))
    
                                                      searcher.Filter = [String].Format("(&(&(objectCategory=person)(objectClass=user)(userPrincipalName=*{0}*)))", theusername)
    
                                                      Return searcher
    
                                                  End Function)
    
            Dim directoryEntriesFound = allSearcher.SelectMany(Function(searcher) searcher.FindAll().Cast(Of SearchResult)().[Select](Function(result) result.GetDirectoryEntry()))
    
            Dim memberOf = directoryEntriesFound.[Select](Function(entry)
                                                              Using entry
                                                                  Return New With { _
                                                                   Key .Name = entry.Name, _
                                                                   Key .GroupName = DirectCast(entry.Properties("MemberOf").Value, Object()).[Select](Function(obj) obj.ToString()) _
                                                                  }
                                                              End Using
    
                                                          End Function)
    
    
    
            For Each user As Object In memberOf
                For Each groupName As Object In user.GroupName
                    lstGroups.Add(groupName)
                Next
            Next
    
            Return lstGroups
    
        Catch ex As Exception
            Throw
        End Try
    End Function
    
    Private Function isMemberofGroupNew(theusername As String, thegroupname As String) As Boolean
    
        Try
    
            Dim lstGroups As List(Of String) = getGroupsNew(theusername)
    
            For Each sGroup In lstGroups
                If sGroup.ToLower.Contains(thegroupname.ToLower) Then Return True
            Next
    
            Return False
    
    
        Catch ex As Exception
            Throw
        End Try
    
    End Function
    
    0 讨论(0)
  • 2020-12-29 21:57

    We experienced this issue when our infrastructure team brought a 2012 Domain Controller online. We also had pre-2012 DCs in place and so we experienced the issue intermittently. We came up with a fix which I wanted to share - it has 2 parts.

    First of all, install the hotfix mentioned by Gary Hill. This will resolve the following issue:

    An error (1301) occurred while enumerating the groups. The group's SID could not be resolved.

    We thought we were home free after installing this hotfix. However, after it was installed we got a different intermittent error. Certain groups that we were interrogating had a null sAMAccountName property. The actual property was populated in Active Directory but it was incorrectly being returned with a null value by the API. I presume this is a bug somewhere in the Active Directory API but I don't know any more than that.

    Fortunately we were able to work around the issue by switching to use the group Name property instead of the sAMAccountName property. This worked for us. I believe, that sAMAccountName is effectively deprecated and exists only for backwards compatibility reasons. That being the case it seemed a reasonable change to make.

    I enclose a cut down version of our GetRolesForUser code to demonstrate the change in place.

    using (var context = new PrincipalContext(ContextType.Domain, _domainName))
    {
        try
        {
            var p = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username);
            if (p == null) throw new NullReferenceException(string.Format("UserPrincipal.FindByIdentity returned null for user: {0}, this can indicate a problem with one or more of the AD controllers", username));
    
            var groups = p.GetAuthorizationGroups();
            var domain = username.Substring(0, username.IndexOf(@"\", StringComparison.InvariantCultureIgnoreCase)).ToLower();
    
            foreach (GroupPrincipal group in groups)
            {
                if (!string.IsNullOrEmpty(group.Name))
                {
                    var domainGroup = domain + @"\" + group.Name.ToLower();
    
                    if (_groupsToUse.Any(x => x.Equals(domainGroup, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        // Go through each application role defined and check if the AD domain group is part of it
                        foreach (string role in roleKeys)
                        {
                            string[] roleMembers = new [] { "role1", "role2" };
    
                            foreach (string member in roleMembers)
                            {
                                // Check if the domain group is part of the role
                                if (member.ToLower().Contains(domainGroup))
                                {
                                    // Cache the Application Role (NOT the AD role)
                                    results.Add(role);
                                }
                            }
                        }
                    }
                }
    
                group.Dispose();
            }
        }
        catch (Exception ex)
        {
            throw new ProviderException("Unable to query Active Directory.", ex);
        }
    }
    

    Hope that helps.

    0 讨论(0)
  • 2020-12-29 21:57

    I experienced error code 1301 with UserPrincipal.GetAuthorizationGroups while using a brand new virtual development domain which contained 2 workstations and 50 users/groups (many of which are the built in ones). We were running Windows Server 2012 R2 Essentials with two Windows 8.1 Enterprise workstations joined to the domain.

    I was able to recursively obtain a list of a user's group membership using the following code:

    class ADGroupSearch
    {
        List<String> groupNames;
    
        public ADGroupSearch()
        {
            this.groupNames = new List<String>();
        }
    
        public List<String> GetGroups()
        {
            return this.groupNames;
        }
    
        public void AddGroupName(String groupName)
        {
            this.groupNames.Add(groupName);
        }
    
        public List<String> GetListOfGroupsRecursively(String samAcctName)
        {
            PrincipalContext ctx = new PrincipalContext(ContextType.Domain, System.Environment.UserDomainName);
            Principal principal = Principal.FindByIdentity(ctx, IdentityType.SamAccountName, samAcctName);
            if (principal == null)
            {
                return GetGroups();
            }
            else
            {
                PrincipalSearchResult<Principal> searchResults = principal.GetGroups();
    
                if (searchResults != null)
                {
                    foreach (GroupPrincipal sr in searchResults)
                    {
                        if (!this.groupNames.Contains(sr.Name))
                        {
                            AddGroupName(sr.Name);
                        }
                        Principal p = Principal.FindByIdentity(ctx, IdentityType.SamAccountName, sr.SamAccountName);
    
                        try
                        {
                            GetMembersForGroup(p);
                        }
                        catch (Exception ex)
                        {
                            //ignore errors and continue
                        }
                    }
    
                }
                return GetGroups();
            }
    
        }
    
    
    
        private void GetMembersForGroup(Principal group)
        {
            if (group != null && typeof(GroupPrincipal) == group.GetType())
            {
                GetListOfGroupsRecursively(group.SamAccountName);
            } 
        }
    
        private bool IsGroup(Principal principal)
        {
            return principal.StructuralObjectClass.ToLower().Equals("group");
        }
    }
    
    0 讨论(0)
  • 2020-12-29 21:59

    I have just run into this same issue and the info I have managed to track down may be helpful; as above we have seen this problem where the domain controller is running Server 2012 - firstly with a customer deployment and then replicated on our own network.

    After some experimentation we found that our code would run fine on Server 2012, but hit the 1301 error code when the client system was running Server 2008. The key information about what was happening was found here:

    MS blog translated from German

    The hotfix referred to in the link below has fixed the problem on our test system

    SID S-1-18-1 and SID S-1-18-2 can't be mapped

    Hope this is helpful for someone! As many have noted this method call seems rather fragile and we will probably look at implementing some alternative approach before we hit other issues.

    Gary

    0 讨论(0)
  • 2020-12-29 22:02

    Here's my solution. It seems to work consistently well. Because the problem happens when iterating over the collection, I use a different approach when iterating in order to handle the exception without blocking the actual iterating:

    private string[] GetUserRoles(string Username)
    {    
        List<string> roles = new List<string>();
        try
        {
            string domain = Username.Contains("\\") ? Username.Substring(0, Username.IndexOf("\\")) : string.Empty;
            string username = Username.Contains("\\") ? Username.Substring(Username.LastIndexOf("\\") + 1) : Username;
            if (!string.IsNullOrEmpty(domain) && !string.IsNullOrEmpty(username))
            {
                PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domain);
                UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, username);
                if (user != null)
                {
                    PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
                    int count = groups.Count();
                    for (int i = 0; i < count; i++)
                    {
                        IEnumerable<Principal> principalCollection = groups.Skip(i).Take(1);
                        Principal principal = null;
                        try
                        {
                            principal = principalCollection.FirstOrDefault();
                        }
                        catch (Exception e)
                        {
                            //Error handling...
                            //Known exception - sometimes AD can't query a particular group, requires server hotfix?
                            //http://support.microsoft.com/kb/2830145
                        }
    
                        if (principal!=null && principal is GroupPrincipal)
                        {
                            GroupPrincipal groupPrincipal = (GroupPrincipal)principal;
                            if (groupPrincipal != null && !string.IsNullOrEmpty(groupPrincipal.Name))
                            {
                                roles.Add(groupPrincipal.Name.Trim());
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            //Error handling...
        }
        return roles.ToArray();
    }
    
    0 讨论(0)
  • 2020-12-29 22:06

    I had the problem that if i am connected over VPN and use groups=UserPrincipal.GetGroups() then the Exception occures when iterating over the groups.

    If someone want to read all groups of a user there is following possibility (which is faster than using GetGroups())

    private IList<string> GetUserGroupsLDAP(string samAccountName)
    {
        var groupList = new List<string>();
        var domainConnection = new DirectoryEntry("LDAP://" + serverName, serverUser, serverUserPassword); // probably you don't need username and password
    
        var samSearcher = new DirectorySearcher();
        samSearcher.SearchRoot = domainConnection;
        samSearcher.Filter = "(samAccountName=" + samAccountName + ")";
    
        var samResult = samSearcher.FindOne();
        if (samResult != null)
        {
            var theUser = samResult.GetDirectoryEntry();
            theUser.RefreshCache(new string[] { "tokenGroups" });
    
            var sidSearcher = new DirectorySearcher();
            sidSearcher.SearchRoot = domainConnection;
            sidSearcher.PropertiesToLoad.Add("name");
            sidSearcher.Filter = CreateFilter(theUser);
    
            foreach (SearchResult result in sidSearcher.FindAll())
            {
                groupList.Add((string)result.Properties["name"][0]);
            }
        }
        return groupList;
    }
    
    private string CreateFilter(DirectoryEntry theUser)
    {
        string filter = "(|";
        foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
        {
            var SID = new SecurityIdentifier(resultBytes, 0);
            filter += "(objectSid=" + SID.Value + ")";
        }
        filter += ")";
        return filter;
    }
    
    0 讨论(0)
提交回复
热议问题