DirectoryEntries.Find: "An invalid dn syntax has been specified" - c#

I'm trying to find a user in the current domain. The code is this:
DirectoryEntry domain = new DirectoryEntry("LDAP://CN-Users, DC=" + Environment.UserDomainName);
DirectoryEntries entries = domain.Children;
try
{
// The following line causes the exception
DirectoryEntry user = entries.Find("(&(objectCategory=user)(cn=" + userName + "))", ActiveDirectoryEntryType.User.TypeName);
user.DeleteTree();
user.CommitChanges();
}
catch
{}
I'm getting an error:
An invalid dn syntax has been specified.
I also tried the following code and got the same error:
DirectoryEntry user = entries.Find(userName, ActiveDirectoryEntryType.User.TypeName);
I could not find information about the proper syntax in the help files. Does anyone know how this is done?

You have an error in this statemet:
DirectoryEntry domain = new DirectoryEntry("LDAP://CN-Users, DC=" + Environment.UserDomainName);
I almost sure that it should be: LDAP://CN=Users, instaed of LDAP://CN-Users,
Second thing is DC=" + Environment.UserDomainName which maybe wrong, because ususally it is something like this: LDAP://OU=Finance,dc=fabrikam,dc=com (there is more than one DC)
You can find all DC using powershell. Run following command:
New-Object DirectoryServices.DirectoryEntry

Related

c#, DirectoryEntry fails to read "labeledUri" from openLDAP

Im using c#, DirectoryEntry (System.DirectoryServices) to read and write a users of objectClass "inetOrgPerson".
This works well, until i want to write the Attributes "labeledURI" or "displayName".
Actually, i can write them once, but the second time it fails. I think that DirectoryEntry has trouble to read them from the Ldap.
I can provide more Code, but i hope this little example gives an idea.
PseudoCode here:
DirectoryEntry deFound = null;
DirectoryEntry de = new DirectoryEntry(a_strLdapServer + "/" + a_strLdapBasePath, m_strLdapUser, m_strLdapPw, AuthenticationTypes.None);
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(&(objectClass=person) (uid=" + a_strUserName + "))";
//deSearch.PropertiesToLoad.Add("labeledURI");
SearchResultCollection results = deSearch.FindAll();
if (results.Count == 1)
{
deFound = results[0].GetDirectoryEntry();
}
//WORKS ONCE:
deFound.Properties["labeledURI"].Value = "http://www.google.com";
Throwed Exception:
deFound.Properties["labeledURI"].Value 'm_deFound.Properties["labeledURI"]' threw an exception of type 'System.Runtime.InteropServices.COMException' object
Do you know i'm doing wrong?
Figured it out!
Forget about changing ldap:// to LDAP:// or other snake oil.
The problem is hidden in Windows8 (and Server2012 as well).
when you can't access
deFound.Properties["labeledURI"]
or
deFound.Properties["displayName"]
and you're using windows8., then here is a Hotfix:
http://support.microsoft.com/kb/2802148

OpenLdap C# bind with escaped characters in Distinguished Name

I have some working LDAP code in which we rebind to the found user in order to validate the user, using his distinguished name. Effectively this is what is happening:
string userDn = #"cn=Feat Studentl+umanroleid=302432,ou=Faculty of Engineering & Physical Sciences Administration,ou=Faculty of Engineering & Physical Sciences,ou=People,o=University of TestSite,c=GB";
string fullPath = #"LDAP://surinam.testsite.ac.uk:636/" + userDn;
DirectoryEntry authUser = new DirectoryEntry(fullPath, userDn, "mypassword", AuthenticationTypes.None);
authUser.RefreshCache();
However this causes error unknown error 80005000 at DirectoryEntry.Bind()
I suspected the problem might be that the DN has a '+' and a '=' in the CN attribute. Therefore after finding that the way to escape this should be with a \ and the hex value of the character I tried this:
string userDn = #"cn=Feat Studentl\2Bumanroleid\3D302432,ou=Faculty of Engineering & Physical Sciences Administration,ou=Faculty of Engineering & Physical Sciences,ou=People,o=University of TestSite,c=GB";
However I get the error:
Login failure: unknown user name or bad password
I assume this is because that now it is happy with the request but it is failing to match the users DN, for some reason.
Is there anyway around this?
In my experience developing LDAP services, whenever you get a login failure due to invalid credentials, that does tend to be the issue with the bind attempt. You're getting that error because DirectoryEntry does not parse the escaped characters in the DN... however, you shouldn't have to do that in the first place.
In your code - setting the AuthenticationTypes to "None" forces the entry to make a Simple bind based on the DN you're providing. Since your including the server name as part of the path, I would try using the ServerBind auth type instead, like this :
string LdapPath = ("LDAP://" + ldapUrl + "/" + Domain);
//Build the user and issue the Refresh bind
var dirEntry = new DirectoryEntry
{
Path = LdapPath,
Username = _usernameToVerify,
Password = _passwordToVerify,
AuthenticationType = AuthenticationTypes.ServerBind
};
//This will load any available properties for the user
dirEntry.RefreshCache();
Also, it looks like you're making this call to the secure LDAP port (636), so make sure you also include AuthenticationTypes.SecureSocketsLayer along with the ServerBind mechansim :
AuthenticationType = AuthenticationTypes.ServerBind | AuthenticationTypes.SecureSocketsLayer
Hope this helps!
I had to resort to digging through an old DLL project that was customised for one customer.
I managed to get it to work. It appears you have to refer to these low level Directory Services routines if you have a DN with escape characters. (Note in real life the DN is obtained by an initial felxible user search by setting up a DirectorySearcher and doing FindOne first)
string userDn = #"cn=Feat Studentl+umanroleid=302432,ou=Faculty of Engineering & Physical Sciences Administration,ou=Faculty of Engineering & Physical Sciences,ou=People,o=University of TestSite,c=GB";
string basicUrl = #"surinam.testsite.ac.uk:636";
var ldapConnection = new LdapConnection(basicUrl);
ldapConnection.AuthType = AuthType.Basic;
LdapSessionOptions options = ldapConnection.SessionOptions;
options.ProtocolVersion = 3;
options.SecureSocketLayer = true;
NetworkCredential credential = new NetworkCredential(userDn, password);
ldapConnection.Credential = credential;
try
{
ldapConnection.Bind();
Console.WriteLine("bind succeeded ");
}
catch (LdapException e)
{
if (e.ErrorCode == 49)
{
Console.WriteLine("bind failed ");
}
else
{
Console.WriteLine("unexpected result " + e.ErrorCode);
}
}
catch (DirectoryOperationException e)
{
Console.WriteLine("unexpected error " + e.Message);
}

UserPrincipal SamAccountName throws DirectoryServicesCOMException unhandled "A local error has occured"

I'm writing a piece of code that is supposed to search the active directory for a specific users GivenName (forename) and Surname based upon their SamAccountName as the search parameter, and then return a string containing their given name and surname.
The code I have written so far is as follows:
public static string GetName(string uName)
{
StringBuilder builder = new StringBuilder();
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "serverName"))
{
UserPrincipal user = new UserPrincipal(context);
user.SamAccountName = uName;
PrincipalSearcher srch = new PrincipalSearcher(user);
srch.QueryFilter = user;
PrincipalSearchResult<Principal> res = srch.FindAll();
foreach (UserPrincipal u in res)
{
builder.Append(u.GivenName);
builder.Append(" ");
builder.Append(u.Surname);
}
return builder.ToString();
}
}
The problem I'm having with the above code is that during run-time the line
user.SamAccountName = uName;
throws the following error: DirectoryServicesCOMException unhandled "A local error has occured"
The principal context object is created just fine, as is the user principal object, it only throws the error when executing the line mentioned above. What's even more bizarre is that this code seemed to work a couple of days ago. If anyone reading this has any ideas as to why I'm getting this error I'd be greatly appreciative!
P.S.
I resorted to asking about this as the bloody error message is a bit too cryptic to actually figure out, or at least for me anyway (a local error occured) really? Whichever developer thought that was a useful error message is an idiot.
Possible causes:
There is an issue with the computer's domain membership or authentication. For example, is the clock on the computer running the code synchronized (within 5 minutes) of the DCs in the target domain?
The user name is invalid. For example, it contains invalid characters.

Can't query AD (get a DirectoryServicesCOMException)

I'm attempting to query AD in an ASP.Net (4.0) application that is running on Windows Server 2008 R2 (IIS7 installed). (It also fails when running as a 2.0 application as well)
This is nothing new for me, as I've done this many times before. I wrote a small ASP.Net program that runs fine on my own machine (Windows XP with IIS6), but fails when run on the 2008 box.
(The result is that you see a list of groups the user is a member of in a textbox)
(on button_click)
var userName = txtUserName.Text;
if (userName.Trim().Length == 0)
{
txtResults.Text = "-- MISSING USER NAME --";
return;
}
var entry = new DirectoryEntry("LDAP://blah.blah/DC=blah,DC=blah",
"cn=acct, dc=blah, dc=blah",
"pass");
var search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + userName + ")";
search.PropertiesToLoad.Add("memberOf");
var groupsList = new StringBuilder();
var result = search.FindOne();
if (result != null)
{
int groupCount = result.Properties["memberOf"].Count;
for (int counter = 0; counter < groupCount; counter++)
{
groupsList.Append((string)result.Properties["memberOf"][counter]);
groupsList.Append("\r\n");
}
}
txtResults.Text = groupsList.ToString();
When I run this code I get the following error on search.FindOne():
System.DirectoryServices.DirectoryServicesCOMException (0x8007203B): A local error has occurred.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at WebApplication1._Default.btnSearch_Click(Object sender, EventArgs e)
We've done a lot of research with this and twiddled every IIS7 setting we can think of, but no go so far. Any clues?
Change the username parameter from "cn=xxx, dc=yyy, dc=zzz" to "Domain\Username"
You can also change the IIS Application Pool to run a domain account with the query priveleges you are searching for.
I have a few other comments as well:
Make sure the first entry for the DirectoryEntry constructor includes the container for the users as well. This should help the DirectorySearcher to work more reliably.
I believe the second parameter in the DirectoryEntry constructor should be the user name, not the AD query path.
You should set the AuthenticationType property as well. With Server 2008, by default, this needs to be set to AuthenticationTypes.Secure | AuthenticationTypes.ServerBind | AuthenticationTypes.Sealing. I'd guess that 2008R2 has a simliar requirement.
I see that the question is rather old, but after struggling with this I thought to mention that it is indeed possible to use the LDAP-style of the username (in opposite to the DNS style). This works well for me:
string connString = "LDAP://MyDomain/CN=blah,DC=blah,DC=blah";
string username = "CN=MyAdmin,CN=Users,CN=blah,DC=blah,DC=blah";
string password = "myLittleSecret";
DirectoryEntry root = new DirectoryEntry(
connString,
username,
password,
AuthenticationTypes.None);
Where MyAdmin is a member in the Administrators role.
One little thing that took me a while to find is the AuthenticationTypes.None parameter that is needed if you do not want to communicate over SSL. Surely, you want to do this in production, but for development purposes it may be OK to skip the encryption.
Environment: Windows 7
I was also getting this exception when tried to query the active directory:
SearchResult result = srch.FindOne();
To resolve this, just put the above code inside Security.RunWithElevatedPrivileges().
Final Solution:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
result = srch.FindOne();
});

Error 0x80005000 and DirectoryServices

I'm trying to run a simple LDAP query using directory services in .Net.
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://someserver.contoso.com/DC=contoso,DC=com");
directoryEntry.AuthenticationType = AuthenticationTypes.Secure;
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = string.Format("(&(objectClass=user)(objectCategory=user) (sAMAccountName={0}))", username);
var result = directorySearcher.FindOne();
var resultDirectoryEntry = result.GetDirectoryEntry();
return resultDirectoryEntry.Properties["msRTCSIP-PrimaryUserAddress"].Value.ToString();
And I'm getting the following exception:
System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
As a snippet in a Console app, this works. But when I run it as part of a WCF service (run under the same credentials), it throws the above exception.
Any suggestions?
Thanks
I had the same again and again and nothing seemed to help.
Changing the path from ldap:// to LDAP:// did the trick.
It's a permission problem.
When you run the console app, that app runs with your credentials, e.g. as "you".
The WCF service runs where? In IIS? Most likely, it runs under a separate account, which is not permissioned to query Active Directory.
You can either try to get the WCF impersonation thingie working, so that your own credentials get passed on, or you can specify a username/password on creating your DirectoryEntry:
DirectoryEntry directoryEntry =
new DirectoryEntry("LDAP://someserver.contoso.com/DC=contoso,DC=com",
userName, password);
OK, so it might not be the credentials after all (that's usually the case in over 80% of the cases I see).
What about changing your code a little bit?
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = string.Format("(&(objectClass=user)(objectCategory=user) (sAMAccountName={0}))", username);
directorySearcher.PropertiesToLoad.Add("msRTCSIP-PrimaryUserAddress");
var result = directorySearcher.FindOne();
if(result != null)
{
if(result.Properties["msRTCSIP-PrimaryUserAddress"] != null)
{
var resultValue = result.Properties["msRTCSIP-PrimaryUserAddress"][0];
}
}
My idea is: why not tell the DirectorySearcher right off the bat what attribute you're interested in? Then you don't need to do another extra step to get the full DirectoryEntry from the search result (should be faster), and since you told the directory searcher to find that property, it's certainly going to be loaded in the search result - so unless it's null (no value set), then you should be able to retrieve it easily.
Marc
In the context of Ektron, this issue is resolved by installing the "IIS6 Metabase compatibility" feature in Windows:
Check 'Windows features' or 'Role Services' for IIS6 Metabase
compatibility, add if missing:
Ref: https://portal.ektron.com/KB/1088/
On IIS hosted sites, try recycling the app pool. It fixed my issue.
Thanks
I had the same error - in my case it was extra slash in path argument that made the difference.
BAD:
DirectoryEntry directoryEntry =
new DirectoryEntry("LDAP://someserver.contoso.com/DC=contoso,DC=com/",
userName, password);
GOOD:
DirectoryEntry directoryEntry =
new DirectoryEntry("LDAP://someserver.contoso.com/DC=contoso,DC=com",
userName, password);
I had this error as well and for me it was an OU with a forward slash in the name: "File/Folder Access Groups".
This forum thread pointed me in the right direction. In the end, calling .Replace("/","\\/") on each path value before use solved the problem for me.
Just FYI, I had the same error and was using the correct credentials but my LDAP url was wrong :(
I got the exact same error message and code
Just had that problem in a production system in the company where I live... A webpage that made a LDAP bind stopped working after an IP changed.
The solution...
... I installed Basic Authentication to perform the troubleshooting indicated here: https://support.microsoft.com/en-us/kb/329986
And after that, things just started to work. Even after I re-disabled Basic Authentication in the page I was testing, all other pages started working again with Windows Authentication.
Regards,
Acácio
I encounter this error when I'm querying an entry of another domain of the forrest and this entry have some custom attribut of the other domain.
To solve this error, I only need to specify the server in the url LDAP :
Path with error = LDAP://CN=MyObj,DC=DOMAIN,DC=COM
Path without error : LDAP://domain.com:389/CN=MyObj,DC=Domain,DC=COM
This Error can occur if the physical machine has run out of memory.
In my case i was hosting a site on IIS trying to access the AD, but the server had run out of memory.
I had to change my code from this:
DirectoryEntry entry = new DirectoryEntry(path, ldapUser, ldapPassword);
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchRoot = entry;
searcher.SearchScope = SearchScope.Subtree;
To this:
DirectoryEntry entry = new DirectoryEntry(path, ldapUser, ldapPassword);
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchScope = SearchScope.OneLevel;
SearchResult searchResult = searcher.FindOne();
The same error occurs if in DirectoryEntry.Patch is nothing after the symbols "LDAP//:". It is necessary to check the directoryEntry.Path before directorySearcher.FindOne(). Unless explicitly specified domain, and do not need to "LDAP://".
private void GetUser(string userName, string domainName)
{
DirectoryEntry dirEntry = new DirectoryEntry();
if (domainName.Length > 0)
{
dirEntry.Path = "LDAP://" + domainName;
}
DirectorySearcher dirSearcher = new DirectorySearcher(dirEntry);
dirSearcher.SearchScope = SearchScope.Subtree;
dirSearcher.Filter = string.Format("(&(objectClass=user)(|(cn={0})(sn={0}*)(givenName={0})(sAMAccountName={0}*)))", userName);
var searchResults = dirSearcher.FindAll();
//var searchResults = dirSearcher.FindOne();
if (searchResults.Count == 0)
{
MessageBox.Show("User not found");
}
else
{
foreach (SearchResult sr in searchResults)
{
var de = sr.GetDirectoryEntry();
string user = de.Properties["SAMAccountName"][0].ToString();
MessageBox.Show(user);
}
}
}
Spent a day on my similar issue, but all these answers didn't help.
Turned out in my case, I didn't enable Windows Authentication in IIS setting...
In my case, the problem was that I was trying to reference a DirectoryEntry's property value, even though that DirectoryEntry did not have that property at all.
If you for example, have:
var myGroup = new DirectoryEntry("LDAP://CN=mygroup,OU=mydomain....", myUsername, myPassword);
var groupManager = myGroup.Properties["managedBy"].Value.ToString();
If myGroup has no managedBy attribute set in the AD, this will result in Unknown error (0x80005000)

Categories

Resources