I want to get the Groups of a User from the Active Directory by an User Principal. For this task, I wrote the following static function:
internal static List<ADGroup> GetGroupsByIdentity(UserPrincipal pUserPrincipal)
{
var lResult = new List<ADGroup>();
if (pUserPrincipal != null)
{
PrincipalSearchResult<Principal> lGroups = pUserPrincipal.GetAuthorizationGroups();
// iterate over all groups
foreach (Principal p in lGroups)
{
// make sure to add only group principals
if (p is GroupPrincipal)
{
var lGroupName = "";
var lGroupSid = "";
try
{
lGroupName = p.Name;
lGroupSid = p.Sid.Value;
if (!string.IsNullOrEmpty(lGroupName) && !string.IsNullOrEmpty(lGroupSid) &&
!lResult.Any(x => x.Sid == lGroupSid))
{
lResult.Add(new ADGroup(p));
}
}
catch (Exception e)
{
if (e is PrincipalOperationException || e is NoMatchingPrincipalException)
{
// perhaps the SID could not be resolved
// perhaps the SID does not exist in the AD any more
// ignore and proceed with next
p.Dispose();
continue;
}
else
{
throw;
}
}
finally
{
p.Dispose();
}
}
p.Dispose();
}
}
return lResult;
}
When the user executes this code, he gets an Exception. Here is a part of the stack:
System.DirectoryServices.AccountManagement.NoMatchingPrincipalException:
An error occurred while enumerating the groups. The group could not be found.
at System.DirectoryServices.AccountManagement.AuthZSet.get_CurrentAsPrincipal()
at System.DirectoryServices.AccountManagement.FindResultEnumerator`1.get_Current()
at xxx.xxxxxxxxx.Mvc.CustomSetup.ADHandler.GetGroupsByIdentity(UserPrincipal pUserPrincipal) // the function above
at ...
Where is the problem and how can I solve it?
It seems like the method GetAuthorizationGroups() have a few limitations. This is an old Exception that have existed since 2009. And Microsoft won't fix it because "there is a reasonable workaround". https://connect.microsoft.com/VisualStudio/feedback/details/522539/clr-forum-error-calling-principal-getauthorizationgroups-in-winxp-sp3
I got this error when using Principal.IsMemberOf(). I searched if a user existed in a custom list of groups. If a group didn't exist in the Domain, it threw this
System.DirectryServices.AccountManagement.NoMatchingPrincipalException
https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.nomatchingprincipalexception(v=vs.110).aspx
Error example 1 using .IsMemberOf()
List<string> groups = Constants.ADGroups(); // List of AD groups to test against
var context = new PrincipalContext(
ContextType.Domain,
"Domain");
var userPrincipal = UserPrincipal.FindByIdentity(
context,
IdentityType.SamAccountName,
httpContext.User.Identity.Name);
// Verify that the user is in the given AD group (if any)
foreach (var group in groups)
if (userPrincipal.IsMemberOf(context, IdentityType.Name, group))
return true;
Error example 2 using .GetAuthorizationGroups():
var context = new PrincipalContext(ContextType.Domain,"Domain");
var userPrincipal = UserPrincipal.FindByIdentity(
context,
IdentityType.SamAccountName,
httpContext.User.Identity.Name);
if (userPrincipal != null)
{
var principalGroups = userPrincipal.GetAuthorizationGroups();
foreach (var principalGroup in principalGroups)
{
foreach (var group in groups)
{
if (String.Equals(
principalGroup.Name,
group,
StringComparison.CurrentCultureIgnoreCase))
{
return true;
}
}
}
}
Solution 1: Proposed workaround is to iterate over AD Groups:
GetAuthorizationGroups() is throwing exception
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
var iterGroup = groups.GetEnumerator();
using (iterGroup)
{
while (iterGroup.MoveNext())
{
try
{
Principal p = iterGroup.Current;
Console.WriteLine(p.Name);
}
catch (NoMatchingPrincipalException pex)
{
continue;
}
}
}
Solution 2: What I instead ended up using (MVC app using Windows Authentication):
This is a lighter way to check auth, iterating over a large company's AD can be slow...
var wi = HttpContext.Current.User.Identity as WindowsIdentity;
if (wi != null)
{
var wp = new WindowsPrincipal(wi);
List<string> groups = Constants.ADGroups(); // List of AD groups to test against
foreach (var @group in groups)
{
Debug.WriteLine($"Searching for {@group}");
if (wp.IsInRole(@group))
{
return true;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With