private static bool IsUserInGroup(UserPrincipal user, GroupPrincipal group)
{
if (user == null || group == null) return false;
// This may seem a convoluted and strange way to check group membership.
// Especially because I could just call user.IsMemberOf(group).
// The reason for all of this is that IsMemberOf will throw an exception
// if there is an unresolvable SID in the list of group members. Unfortunately,
// even looping over the members with a standard foreach loop doesn't allow
// for catching the exception and continuing. Therefore, we need to use the
// IEnumerator object and iterate through the members carefully, catching the
// exception if it is thrown. I throw in a sanity check because there's no
// guarantee that MoveNext will actually move the enumerator forward when an
// exception occurs, although it has done so in my tests.
//
// For additional details, see the following bug:
// https://connect.microsoft.com/VisualStudio/feedback/details/453812/principaloperationexception-when-enumerating-the-collection-groupprincipal-members
PrincipalCollection members = group.Members;
bool ok = true;
int errorCount = 0; // This is a sanity check in case the loop gets out of control
IEnumerator<Principal> membersEnum = members.GetEnumerator();
while (ok)
{
try { ok = membersEnum.MoveNext(); }
catch (PrincipalOperationException)
{
m_logger.ErrorFormat("PrincipalOperationException when checking group membership for user {0} in group {1}." +
" This usually means that you have an unresolvable SID as a group member." +
" I strongly recommend that you fix this problem as soon as possible by removing the SID from the group. " +
" Ignoring the exception and continuing.",
user.Name, group.Name);
// Sanity check to avoid infinite loops
errorCount++;
if (errorCount > 1000) return false;
continue;
}
if (ok)
{
Principal principal = membersEnum.Current;
if (principal is UserPrincipal && principal.Sid == user.Sid)
return true;
}
}
return false;
}