I am trying to access "msDS-ResultantPSO" attribute value of AD user using C#,I applied the Password Policy on a user, and its showing the value in "msDS-ResultantPSO" attribute.Now, I am trying to get this value using C# in the same way to get Normal attributes of AD user such as "FirstName, LastName,Email...".I added ResulantPSO attribute along with other normal attributes to load.My code bringing all normal attributes values except "msDS-ResultantPSO".
Please can anyone help me in this regard.
I had to make sure the user running my program had the appropriate AD read permissions other than that this should get you close:
var ad = new PrincipalContext(ContextType.Domain, _domain, _ldapPathOu);
UserPrincipal user = UserPrincipal.FindByIdentity(ad, username);
DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;
DirectorySearcher mySearcher = new DirectorySearcher(entry);
SearchResultCollection results;
mySearcher.PropertiesToLoad.Add("msDS-ResultantPSO");
results = mySearcher.FindAll();
if (results.Count >= 1)
{
string pso = results[0].Properties["msDS-ResultantPSO"][0].ToString();
//do something with the pso..
DirectoryEntry d = new DirectoryEntry(#"LDAP://corp.example.com/"+ pso);
var searchForPassPolicy = new DirectorySearcher(d);
searchForPassPolicy.Filter = #"(objectClass=msDS-PasswordSettings)";
searchForPassPolicy.SearchScope = System.DirectoryServices.SearchScope.Subtree;
searchForPassPolicy.PropertiesToLoad.AddRange(new string[] {"msDS-MaximumPasswordAge"});
var x = searchForPassPolicy.FindAll();
var maxAge = (Int64)x[0].Properties["msDS-MaximumPasswordAge"][0];
var maxPwdAgeInDays = ConvertTimeToDays(maxAge);
}
Related
What would be the best way in C# to use directory entry to find all users with the attribute wWWHomePage filled in.
I am able to see if a specific user has it but I have not used Directory Entry to search all users for something like this.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, myDomain, Login.authUserName, Login.authPassword);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if (user != null) {
DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);
if (de != null) {
string whatIWant = de.Properties["wWWHomePage"].Value.ToString();
}
}
use DirectoryEntry with DirectorySearcher and specify the search Filter to get what you want.
the Filter template you want is :
(&(objectClass=user)(objectCategory=person)(PROPERTY_NAME=SEARCH_TERM))
where PROPERTY_NAME is the property you want to search in, and SEARCH_TERM is the value. you could use the * as a wildcard search, it would give you all objects that has this property.
here is a quick example :
// set the properties you need.
var propertiesToLoad = new string[] { "sAMAccountName", "wWWHomePage" };
using(var searcher = new DirectorySearcher(new DirectoryEntry(ldap), "(&(objectClass=user)(objectCategory=person)(wWWHomePage=*))", propertiesToLoad))
{
foreach (SearchResult result in searcher.FindAll())
{
if(result == null) continue;
var samAccount = result.Properties["sAMAccountName"][0];
var wWWHomePage = result.Properties["wWWHomePage"][0];
// complete the code with your logic
}
}
The Question
I am looking for a way to filter users from active directory based upon the current logged in users Active Directory Company name (found with the AD profile).
To search AD i am currently using the following code, which returns all users including system accounts -
PrincipalContext context = new PrincipalContext(ContextType.Domain, "mydomain");
var domainUsers = new List<string>();
var userPrincipal = new UserPrincipal(context);
using (var search = new PrincipalSearcher(userPrincipal))
{
foreach (var user in search.FindAll())
{
if (user.DisplayName != null)
{
domainUsers.Add(user.DisplayName);
}
}
}
I am looking for a way to only return users that match the Company name of the current AD logged in user. ie if the company name was Test123 the search results would only include all other users that belong to the Test123 company.
Background
I am developing an asp.net MVC 2.1 web app that requires a dropdown list of users from active directory.
Search All users in Active Directory and match against company field.
While iterating through a list of all users found based on the query, you can convert the Principal to DirectoryEntry since Principal doesnt have the information you need. DirectoryEntry has the properties that you can look up and work with, in terms of filtering. Only "company" is used in this example.
PrincipalContext context = new PrincipalContext(ContextType.Domain, "mydomain");
var domainUsers = new List<string>();
var userPrincipal = new UserPrincipal(context);
string myCompany = "Test123";
using (var search = new PrincipalSearcher(userPrincipal))
{
foreach (Principal user in search.FindAll())
{
string usersCompany = ((DirectoryEntry)user.GetUnderlyingObject())?.Properties["company"]?.Value?.ToString();
if (user.DisplayName != null && usersCompany != null && usersCompany.Equals(myCompany))
{
domainUsers.Add(user.DisplayName);
}
}
}
EDIT
For performance reason, I would recommend using DirectorySearcher instead of using PrincipalSearcher. Here is the other version. Search is done before the FindAll() is executed.
string myCompany = "Test123";
string searchQuery = $"(&(objectCategory=user)(objectClass=user)(company={myCompany}))";
// You can define the fields you want retrieved from AD (Noted by #GabrielLuci)
DirectorySearcher ds = new DirectorySearcher(searchQuery,
new string[] { "DisplayName" });
foreach(SearchResult user in ds.FindAll())
{
domainUsers.Add(user.Properties["DisplayName"][0].ToString());
}
I'm trying to write security permissions to an Group in ActiveDirectory using C#.
my code looks like this:
DirectoryEntry rootEntry = new DirectoryEntry("LDAP://dudu.test.com/CN=2222,OU=Test,DC=dudu,DC=test,DC=com",adminUserName,adminUserPass);
DirectorySearcher dsFindOUs = new DirectorySearcher(rootEntry);
// dsFindOUs.Filter = "(objectClass=group)";
// dsFindOUs.SearchScope = SearchScope.Subtree;
SearchResult oResults = dsFindOUs.FindOne();
DirectoryEntry myOU = oResults.GetDirectoryEntry();
System.Security.Principal.IdentityReference newOwner = new System.Security.Principal.NTAccount("dudug").Translate(typeof(System.Security.Principal.SecurityIdentifier));
ActiveDirectoryAccessRule newRule = new ActiveDirectoryAccessRule(newOwner, ActiveDirectoryRights.GenericAll, System.Security.AccessControl.AccessControlType.Allow);
myOU.ObjectSecurity.SetAccessRule(newRule); myOU.CommitChanges();
when i use this code, i GET a new rule added to the group, but it is called:
"Account Unknown(S-1-5-21-1665235001-242389448-1116685.......)"
if i change my code to this:
System.Security.Principal.IdentityReference newOwner = new System.Security.Principal.NTAccount("dudu.test.com","dudug").Translate(typeof(System.Security.Principal.SecurityIdentifier));
i get the error message:
**System.Security.Principal.IdentityNotMappedException: Some or all identity references could not be translated**
i'm new to ActiveDirectory Code, and this is very frustrating to me,
at the moment I am trying to write some code to help our support and having some problems. I am creating a user in the OU, setting all needed attributes and having trouble setting the flags.
string ADPath1 = "LDAP://127.0.0.1/OU=TEST,DC=abc,DC=def,DC=local";
string ADUser = "admin";
string ADPassword = "somepw";
DirectoryEntry de = new DirectoryEntry(ADPath1, ADUser, ADPassword, AuthenticationTypes.Secure);
I am connecting, and setting everything up
DirectoryEntries users = de.Children;
DirectoryEntry newuser = users.Add("CN=" + "Artemij Voskobojnikov", "user");
newuser.Properties["property"].Add("XXX");
Now I'd like to setup the userAccountControl-propery and am trying to do the following:
const int UF_PASSWD_CANT_CHANGE = 0x0040;
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
int user_flags = UF_PASSWD_CANT_CHANGE + UF_DONT_EXPIRE_PASSWD;
newuser.Properties["userAccountControl"].Value = user_flags
I am getting an error, something like "Server cannot execute the operation". Is there any way to do this or do I have to use UserPrincipal?
Kind regards
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. 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:
// set up domain context and bind to the OU=Test container
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=TEST"))
{
// create a new user
UserPrincipal user = new UserPrincipal(ctx);
// set first name, last name, display name, SAM Account Name and other properties easily
user.DisplayName = "Artemij Voskobojnikov";
user.GivenName = "Artemij";
user.Surname = "Voskobojnikov";
user.SamAccountName = "AVoskobojnikov";
// set some flags as appropriate for your use
user.UserCannotChangePassword = true;
user.PasswordNeverExpires = true;
// save user
user.Save();
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
I am very new to C# and I'm using LDAP to 1) validate a user's login credentials and 2) obtain additional information about the user for my app. Our LDAP server doesn't allow some of the data I'm requesting to be given out anonymously, so I have to wait until I bind with the user's full credentials to pull the data. However, even then I have not been able to obtain simple fields like sn, and givenName. Using JXplorer I can see where these values are hidden during an anonymous connection, but with a full user/SSL/password combination I can see everytning in JXplorer. I just can't seem to do the same via my code.
If I loop through the properties after my first FindOne(), there are 9 properties found (none of which are the ones I'm looking for). If I loop through the properties after my second FindOne(), there are only 4 properties available. Neither results seems to be impacted by PropertiesToAdd.Add("...").
Any suggestions would be appreciated.
public string[] Authenticate(string user, string password)
{
string[] results = new string [2];
//Concatenate serverpath + username + container
//I.e. "LDAP://ldap.disney.com:636/CN=donaldDuck,ou=people,dc=la,dc=disney,dc=com"
DirectoryEntry de = new DirectoryEntry(_ldapserver + "cn=" + user + "," + _topContainer);
//User's password for initial verification
de.Password = password;
//initate anonymous bind
de.AuthenticationType = System.DirectoryServices.AuthenticationTypes.SecureSocketsLayer;
DirectorySearcher searcher = new DirectorySearcher(de);
searcher.SearchScope = System.DirectoryServices.SearchScope.Base;
//Search for first record
SearchResult result = searcher.FindOne();
//Check results
if (result == null) throw new Exception(ERR_NOT_FOUND);
de = result.GetDirectoryEntry();
//Return search results
//results[0] = (string)de.Properties["mail"].Value;
// results[1] = (string)de.Properties["givenName"].Value + " " + (string)de.Properties["sn"].Value;
// Distingushed Name of the found account
string DN = de.Path.Substring(de.Path.ToUpper().IndexOf("CN="));
// Close search connection
de.Close();
// now bind and verify the user's password,
de = new DirectoryEntry(_ldapserver + _topContainer);
de.Username = DN;
de.Password = password;
de.AuthenticationType = System.DirectoryServices.AuthenticationTypes.SecureSocketsLayer;
//Obtain additional information
searcher = new DirectorySearcher(de);
searcher.PropertiesToLoad.Add("sn");
searcher.PropertiesToLoad.Add("givenName");
SearchResult r = searcher.FindOne();
de = r.GetDirectoryEntry();
foreach (string property in de.Properties.PropertyNames)
{
Console.WriteLine("\t{0} : {1} ", property, de.Properties[property][0]);
}
//End obtain additional information
//Validate password
Object obj = de.NativeObject;
de.Close();
//if we made it here, we successfully authenticated
return results;
}
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. 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:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// validate given user credentials
bool isValid = ctx.ValidateCredentials(user, password);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
string surname = user.Surname;
string givenName = user.GivenName;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!