Reputation: 1484
I'm having an issue where if I try extend the UserPrincipal class the PrincipalContextSearcher does not return the correct results when using the extended class as the query filter.
So, for example, If I create the following minimal extension of UserPrincipal
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")]
public class UserPrincipalExtended : UserPrincipal
{
public UserPrincipalExtended(PrincipalContext context) : base(context) { }
public UserPrincipalExtended(PrincipalContext context, string samAccountName, string password, bool enabled) : base(context, samAccountName, password, enabled) { }
}
If I search using a (non-extended) UserPrincipal, like follows:
using (var searchCritera = new UserPrincipal(context))
{
searchCritera.SamAccountName = searchTerm;
using (var searcher = new PrincipalSearcher(searchCritera))
{
foreach (var principal in searcher.FindAll())
{
... do stuff
}
}
}
It will correctly return only user accounts. But if I use UserPrincipalExtended instead of the UserPrincipal, it returns matches to computers and all kinds of other things which is not the behavior I want. All I want to do is be able to add a few additional properties to retrieve in the UserPrincipal but simply extending the class before adding anything into it seems to change the filtering behavior.
What am I missing and how do I get PrincipalSearcher using an extended UserPrincipal ?
Upvotes: 1
Views: 317
Reputation: 353
It's possible to replace the AdvancedSearchFilter
property (using new
not override
, because the original property is read-only) and add your very own CustomAdvancedFilter
with any custom filter you want using AdvancedFilterSet
.
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")]
public class UserPrincipalExtended : UserPrincipal
{
public UserPrincipalExtended(PrincipalContext context) : base(context) {
AdvancedSearchFilter = new CustomAdvancedFilter(this);
}
public UserPrincipalExtended(PrincipalContext context, string samAccountName, string password, bool enabled) : base(context, samAccountName, password, enabled)
{
AdvancedSearchFilter = new CustomAdvancedFilter(this);
}
public new AdvancedFilters AdvancedSearchFilter { get; set; }
}
public class CustomAdvancedFilter : AdvancedFilters
{
public CustomAdvancedFilter(Principal principal) : base(principal)
{
AdvancedFilterSet("objectCategory", "user", typeof(string), MatchType.Equals);
}
}
Upvotes: 1
Reputation: 1484
Digging a bit as to what was going on I looked at the DirectorySearcher used under the covers of PrincipalSearcher to see what the difference was.
((System.DirectoryServices.DirectorySearcher)(principalSearcher.GetUnderlyingSearcher())).Filter
when using UserPrincipal as the queryfilter the filter looks like:
Filter: "(&(objectCategory=user)(objectClass=user)(sAMAccountName=*searchTermWithWildcards*))" string
when using UserPrincipalExtended as the queryfilter the filter looks like:
Filter: "(&(objectClass=user)(sAMAccountName=*searchTermWithWildcards*))" string
It's missing the objectCategory
I resorted to the following deplorable hack to get it working but I would prefer a better way to specify the objectCategory
[DirectoryRdnPrefix("CN")]
#region *UGLY CODE WARNING* Don't look in here....
// When building the underlying DirectorySearcher filter the DirectoryObjectClass value is inserted in as: (objectClass={value})
// The following injection will result in : (objectClass=user)(objectCategory=user)
[DirectoryObjectClass("user)(objectCategory=user")]
#endregion
public class UserPrincipalExtended : UserPrincipal
{
public UserPrincipalExtended(PrincipalContext context) : base(context) { }
public UserPrincipalExtended(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled) { }
}
Upvotes: 2