Getting an exception “The specified directory service attribute or value does not exist”, when you try to search a user in an AD container using System.DirectoryServices.AccountManagement.UserPrincipal::FindByIdentity
This happens because If there is no container specified, the principal context class will create a System.DirectoryServices.DirectoryEntry object by binding to builtin CN=Users container to start searching for users. System.DirectoryServices is built on top of ADSI. ADSI by default does an objectclass=* search as part of its normal bind process unless the fastbind flag is specified. if the user performing the search does not have permission to read the attributes of default users contain, the search operation will fail, thus causing “The specified directory service attribute or value does not exist”, exception.
This is also true when searching computer objects using ComputerPrincipal::FindByIdentity and you don’t have read permission on CN=Computer container and have not specified a container in the constructor of System.DirectoryServices.AccountManagemnt.PrincipalContext. The remarks section of the documentation at msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.principalcontext.principalcontext.aspx explains the rules followed by the PrincipalContext class in selecting a container when one has not been explicitly specified in the constructor.
The right approach is to specify the container where the object resides if you know the name of the container. Alternatively, you can simply specify the domain naming context as the container. The performance in this case will be inferior to specifying the name of the container explicitly, since the search will encompass the entire domain.
The issue can be reproduced by using the following code (Change the name of the domain and searched user to values appropriate for your environment):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices;
namespace TestInvalidCreds
{
class Program
{
static void Main(string[] args)
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "dc163608.local");
UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, "InnerUser");
}
}
}
To reproduce the issue deny read permission for a user on CN=Users container for the user that is running the search, and the run the above code in Visual Studio or the compiled program under the above user account. The searched (in this example InnerUser) user can be in any OU.
You will get an exception “The specified directory service attribute or value does not exist”.
Modify the code as below (Change the name of the domain and searched user to values appropriate for your environment):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices;
namespace TestInvalidCreds
{
class Program
{
static void Main(string[] args)
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "dc163608.local","dc=dc163608,dc=Local");
UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, "InnerUser");
}
}
}
It should now return the object.
Comments
- Anonymous
November 15, 2010
Hi, I have same kind of issue when I have removed the All(GenericAll) rights(permission) from OU. When I search for that OU,then it throws exception as "the specified directory service attribute or value does not exist" To remove GenericAll access permission to OU I have written code as below: DirectoryEntry rootEntry = new DirectoryEntry("LDAP://OU=Test OU,DC=test,DC=com"); DirectorySearcher dsFindOUs = new DirectorySearcher(rootEntry); dsFindOUs.Filter = "(objectClass=organizationalUnit)"; dsFindOUs.SearchScope = SearchScope.Subtree; SearchResult oResults = dsFindOUs.FindOne(); DirectoryEntry myOU = oResults.GetDirectoryEntry(); System.Security.Principal.IdentityReference newOwner = new System.Security.Principal.NTAccount("YourDomain", "YourUserName").Translate(typeof(System.Security.Principal.SecurityIdentifier)); ActiveDirectoryAccessRule newRule = new ActiveDirectoryAccessRule(newOwner, ActiveDirectoryRights.GenericAll, System.Security.AccessControl.AccessControlType.Deny); myOU.ObjectSecurity.SetAccessRule(newRule); myOU.Commitchanges(); Can you please let me know How I can Alllow all the permissions to OU? Thanks