When trying to find an User on a LDAP Server, I get the following error "Unknown error (0x8000500c)"
This is the code I'm using:
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "gandalf.intrafg");
UserPrincipal p = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, "Consultor1");
Indidentally, the following piece of code seems to work (no exception is generated), but the samAccountName comes through as a byte array. Anybody knows why?
DirectoryEntry entry = new DirectoryEntry("LDAP://gandalf.intrafg");
DirectorySearcher searcher = new DirectorySearcher(entry);
//searcher.PropertiesToLoad.Add("givenName");
//searcher.PropertiesToLoad.Add("sn");
searcher.PropertiesToLoad.Add("samAccountName");
searcher.Filter = "(&(objectCategory=person)(samAccountName=Consultor1))";
SearchResult result = searcher.FindOne();
Your second code block works just fine, I however did not pass the domain name in the DirectoryEntry initializer.
Directory entry = new DirectoryEntry();
//other code
result.Properties["samAccountName"][0].ToString();
The code you have should be fine - it works for me, no problem at all.
However: you're not telling us what you fill in for domain_name here:
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "domain_name");
or userId here:
UserPrincipal p = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, UserId);
The domain_name must be in the "old" NetBIOS style, e.g. FABRIKAM - no DNS-style like fabrikam.com or AD-style like dc=fabrikom,dc=com or even a full LDAP path.
The userId must be a valid SAM account name, e.g. max. of 20 chars, letters and numerics only (except for a few valid special chars).
Are you complying with these requirements??
Related
Using C# I would like to add a user from one domain to a local domain. The domains have a two way trust. Currently I get the error
'No principal matching the specified parameters was found.' on the .Save() line.
I have the DN of the user (e.g 'CN=Adams, Sam,OU=Beer, DC=Drinkers,DC=local').
The groups is something like CN=Drunks, OU=Groups,DC=Bars,DC=local.
This works when it is the same domain, but when it is cross domains is when I get the error. The user account that I am using has admin rights locally and read rights in the other domain.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, m_AD_connection.Domain, m_AD_connection.Path, ContextOptions.Negotiate, m_AD_connection.UserName, m_AD_connection.Password))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, GroupName);
if (group != null)
{
group.Members.Add(pc, IdentityType.DistinguishedName, DN);
group.Save();
return true;
}
else
return false;
}
Any suggestions on what I need to do?
Your issue is in this line:
group.Members.Add(pc, IdentityType.DistinguishedName, DN);
The context parameter should be the context required to look up the user, not the group. So you need to create a new PrincipalContext for the second domain and pass that to Add(). For example:
var drinkersPc = new PrincipalContext(ContextType.Domain, "drinkers.local");
group.Members.Add(drinkersPc, IdentityType.DistinguishedName, DN);
I am trying to get the manager's account for a user account in active directory.
Here's the code I have..
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
DirectoryContext directoryContext = new DirectoryContext(DirectoryContextType.Domain, "MyDomain");
Domain domain = Domain.GetDomain(directoryContext);
// Find MY directory Entry
DirectorySearcher search = new DirectorySearcher(domain.GetDirectoryEntry())
{
Filter = String.Format("(SAMAccountName={0})", "<my user id>")
};
search.PropertiesToLoad.Add("displayName");
search.PropertiesToLoad.Add("mail");
search.PropertiesToLoad.Add("manager");
DirectoryEntry userAccount = search.FindOne()?.GetDirectoryEntry();
As you can see, there's a property called manager that is requested and comes back as
CN=Manager Name,OU=Employee,OU=United Kingdom, OU=CompantUsers, DC=MyDomain, DC=xxx,DC=zzzzz
The CN=Manager Name is the full name, not the LoginID/SAMAccountName (as used when I searched for MY AD entry ... so how can I now find the AD entry for my manager
Ahhh ... When you know the right question to ask then Google knows the answer ... I did not know that the CN..... string was known as a distinguishedName
if (userAccount.Properties["manager"].Value != null)
{
DirectorySearcher search2 = new DirectorySearcher(domain.GetDirectoryEntry())
{
Filter = string.Format("(distinguishedName={0})", userAccount.Properties["manager"].Value)
};
search2.PropertiesToLoad.Add("displayName");
search2.PropertiesToLoad.Add("mail");
search2.PropertiesToLoad.Add("manager");
DirectoryEntry mgrAcc = search2.FindOne()?.GetDirectoryEntry();
}
I have some code that retrieves the Active Directory groups that a user is a member of. On localhost it returns the correct results, but when deployed to a another computer (web server on same network) it returns much less results.
I am specifying AD server and a special user name and password I was given by administrators to access.
DirectoryEntry de = new DirectoryEntry("LDAP://***:389", "***", "***");
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + search + "))";
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Add("*");
SearchResult rs = ds.FindOne();
if (rs != null)
{
if (rs.GetDirectoryEntry().Properties["memberof"].Value != null)
//rest of code removed
I also tried a different method and the results were also different...
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "***, "***", "***"))
{
UserPrincipal user = UserPrincipal.FindByIdentity(pc, name);
if (user != null)
{
List<string> groups = new List<string>();
PrincipalSearchResult<Principal> groups2 = user.GetAuthorizationGroups();
//rest of code removed
I would have thought that by specifying a user name and password that the result should be the same. Any idea why this is happening?
These are different because they're retrieving different datasets. The memberOf attribute is constructed on the fly and it will give you the groups the user is a /direct/ member of. The GetAuthorizationGroups() call, on the other hand, will give you all the security groups that the user is transitively a member of. It does this by looking at the tokenGroups attribute in AD.
I want to connect to our local Active Directory with C#.
I've found this good documentation.
But I really don't get how to connect via LDAP.
Can somebody of you explain how to use the asked parameters?
Sample Code:
static DirectoryEntry createDirectoryEntry()
{
// create and return new LDAP connection with desired settings
DirectoryEntry ldapConnection = new DirectoryEntry("rizzo.leeds-art.ac.uk");
ldapConnection.Path = "LDAP://OU=staffusers,DC=leeds-art,DC=ac,DC=uk";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
I just have the Hostname and the IP Address of our Active Directory Server. What does DC=xxx,DC=xx and so on mean?
DC is your domain. If you want to connect to the domain example.com than your dc's are: DC=example,DC=com
You actually don't need any hostname or ip address of your domain controller (There could be plenty of them).
Just imagine that you're connecting to the domain itself. So for connecting to the domain example.com you can simply write
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
And you're done.
You can also specify a user and a password used to connect:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com", "username", "password");
Also be sure to always write LDAP in upper case. I had some trouble and strange exceptions until I read somewhere that I should try to write it in upper case and that solved my problems.
The directoryEntry.Path Property allows you to dive deeper into your domain. So if you want to search a user in a specific OU (Organizational Unit) you can set it there.
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
directoryEntry.Path = "LDAP://OU=Specific Users,OU=All Users,OU=Users,DC=example,DC=com";
This would match the following AD hierarchy:
com
example
Users
All Users
Specific Users
Simply write the hierarchy from deepest to highest.
Now you can do plenty of things
For example search a user by account name and get the user's surname:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
DirectorySearcher searcher = new DirectorySearcher(directoryEntry) {
PageSize = int.MaxValue,
Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=AnAccountName))"
};
searcher.PropertiesToLoad.Add("sn");
var result = searcher.FindOne();
if (result == null) {
return; // Or whatever you need to do in this case
}
string surname;
if (result.Properties.Contains("sn")) {
surname = result.Properties["sn"][0].ToString();
}
ldapConnection is the server adres: ldap.example.com
Ldap.Connection.Path is the path inside the ADS that you like to use insert in LDAP format.
OU=Your_OU,OU=other_ou,dc=example,dc=com
You start at the deepest OU working back to the root of the AD, then add dc=X for every domain section until you have everything including the top level domain
Now i miss a parameter to authenticate, this works the same as the path for the username
CN=username,OU=users,DC=example,DC=com
Introduction to LDAP
If your email address is 'myname#mydomain.com', try changing the createDirectoryEntry() as below.
XYZ is an optional parameter if it exists in mydomain directory
static DirectoryEntry createDirectoryEntry()
{
// create and return new LDAP connection with desired settings
DirectoryEntry ldapConnection = new DirectoryEntry("myname.mydomain.com");
ldapConnection.Path = "LDAP://OU=Users, OU=XYZ,DC=mydomain,DC=com";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
This will basically check for com -> mydomain -> XYZ -> Users -> abcd
The main function looks as below:
try
{
username = "Firstname LastName"
DirectoryEntry myLdapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = "(cn=" + username + ")";
....
I built a test Active Directory server in Window 2008 and I also run the DNS server on it. On my client machine which runs the C# application, I can authenticate the user against the Active directory server using the function below:
public static UserPrincipal GetUserPrincipal(string usrName,string pswd,string domainName)
{
UserPrincipal usr;
PrincipalContext ad;
// Enter Active Directory settings
ad = new PrincipalContext(ContextType.Domain, domainName,usrName,pswd);
//search user
usr = new UserPrincipal(ad);
usr.SamAccountName = usrName;
PrincipalSearcher search = new PrincipalSearcher(usr);
usr = (UserPrincipal)search.FindOne();
search.Dispose();
return usr;
}
In a separate logic I tried to retrieve a user back from the server using a user name. I used the functions below:
public static DirectoryEntry CreateDirectoryEntry()
{
// create AD connection
DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=rootforest,DC=com","LDAP","password");
de.AuthenticationType = AuthenticationTypes.Secure;
return de;
}
public static ResultPropertyCollection GetUserProperty(string domainName, string usrName)
{
DirectoryEntry de = CreateDirectoryEntry();
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(SamAccountName=" + usrName + ")";
SearchResult results = deSearch.FindOne();
return null;
}
However, I got no response back from the LDAP server at all, not even an exception. Am I missing certain settings on LDAP server, any of you able to see a flaw in my code (pls don't mind the hard code values, I was testing with this code).
As part of my troubleshooting, I confirmed that I can ping to the rootforest.com from the client machine. I confirmed the user with property samaccountname "LDAP" exists. My path seems to be right because when I go onto the LDAP server and type :
dsquery user -name LDAP*
I got the following:
CN=LDAP L. LDAP,CN=Users,DC=rootforest,DC=com
Any help would be greatly appreciated, I've spent most of my day troubleshooting and researching this little bugger and I think it could be something small which I overlooked.
I don't understand why you're using the new PrincipalContext / UserPrincipal stuff in your first example, but fall back to the hard to use DirectoryEntry stuff in your second example.... doesn't really make sense... also: your second function GetUserProperty seems to return null always - typo or not??
Since you're on already using the System.DirectoryServices.AccountManagement (S.DS.AM) namespace - use it for your second task, too! Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
public static ????? GetUserProperty(string domainName, string usrName)
{
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, usrName);
if(user != null)
{
// return what you need to return from your user principal here
}
else
{
return null;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD:
I think your code have a few problems:
Why do you return null in your GetUserProperty() function? You should return results instead.
The attribute you are using in your search filter is misspelled. Use sSAMAccountName instead. Furthermore extend your query to search only for user accounts. Here is an example: (&(objectCategory=person)(objectClass=user)(sAMAccountName=usrName))
You could also use the UserPrincipal class to search for an identity in Active Directory. The UserPrincipal class provides a static method called FindByIdentity() to search for a user identity.
Hope, this helps.