Hello everyone (this is my first post)
I have some simple AD code that i pulled from Codeplex http://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C) and i am able to get all of our end user's information from said code. Now, I have been searching and searching and have found some interesting code snippets from here, and around the web regarding "Is the user locked out?"
I would like to use my code that I have been using for 2 years now, and just add a little bit more to it to add in the locked out part... I would be happy if there was a text box that gave me my info, or a check box, or something that just said "user locked" and then I would notify my Exchange team and have the user unlocked...
The code that I have is the following:
string eid = this.tbEID.Text;
string user = this.tbUserName.Text.ToString();
string path = "PP://dc=ds,dc=SorryCantTellYou,dc=com";
DirectoryEntry de = new DirectoryEntry(path);
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&(objectCategory=person)(sAMAccountName=" + eid + "))";
SearchResultCollection src = ds.FindAll();
//AD results
if (src.Count > 0)
{
if (src[0].Properties.Contains("displayName"))
{
this.tbUserName.Text = src[0].Properties["displayName"][0].ToString();
}
}
So, if I can figure out how to use the same directory entry, and searcher to show me the account lockout status that would be amazing.. please assist
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
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SamAccountName");
if(user != null)
{
string displayName = user.DisplayName;
if(user.IsAccountLockedOut())
{
// do something here....
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Related
I have looked at many search results but I am struggling to find a way to programmatically (using C#) create a custom permission and a custom group in Active Directory.
I have an application that will need to have about 50 individual permissions, such as: can encrypt data, can decrypt data, can export private key, can delete keypair, etc. These permissions will be assigned to a custom group. For instance, the group may be called: standard user, security manager, etc.
Users will be assigned one or more of these groups. I need all of this to be managed through Active Directory. The software that is being written is in C#. The users will be in Active Directory.
The software will check that the user has a particular permission when a function on the application is to be executed. If the user does not have permission then they will be required to enter an override. This override is simply a prompt for the credentials of another user who DOES have the relevant permissions.
I want to emphasise that this needs to be managed through Active Directory because the software is running on a domain and the permissions will be managed by the Domain Administrator.
As such, I believe the ASP.Net Roles functionality is not sufficient? In addition, I am not sure if Azure AD is the same as Windows AD.
I would very much appreciate any guidance as to which .NET assembly/namespace will provide the following capability:
Create permission
Create group
Assign permission to group
Assign user to group
Remove user from group
Remove permission from group
I need to to do this programatically because the software will have an installer and will be responsible for adding the application-specific custom permissions and groups during installation if they do not already exist.
It may be possible that I am approaching this wrong so I am open to suggestions otherwise. As long as I am able to perform the above then great!
Thank you!
As I understood,
Here you can try below code
Try once
1) Create Group
PrincipalContext principalContext =
new PrincipalContext(ContextType.Domain, LDAPDomain, LDAPContainer,
LDAPAdmin, LDAPPassword);
GroupPrincipal group = GroupPrincipal.FindByIdentity(principalContext, "groupName");
if (group == null)
{
GroupPrincipal groupPrincipal = new GroupPrincipal(principalContext);
groupPrincipal.Name = "groupName";
groupPrincipal.SamAccountName = "samAccountName";
groupPrincipal.UserPrincipalName = "userPrincipleName";
groupPrincipal.GroupScope = GroupScope.Global;
groupPrincipal.Description = "groupNameDescription";
groupPrincipal.DisplayName = "groupNameDisplayName";
groupPrincipal.Save();
}
2) Add User To Group
GroupPrincipal group = GroupPrincipal.FindByIdentity(principalContext, "groupName");
UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, "userName");
bool isUserAdded = false;
if (user != null & group != null)
{
if (user.IsMemberOf(group))
{
//Do Code
}
else
{
group.Members.Add(user);
group.Save();
isUserAdded = user.IsMemberOf(group);
}
}
if (isUserAdded)
{
//Do Code
}
3) Remove User From Group
GroupPrincipal group = GroupPrincipal.FindByIdentity(principalContext, "groupName");
UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, "userName");
bool isUserRemoved = false;
if (user != null & group != null)
{
if (user.IsMemberOf(group))
{
group.Members.Remove(user);
group.Save();
isUserRemoved = user.IsMemberOf(group);
}
else
{
//Do Code
}
}
if (!isUserRemoved)
{
//Do Code
}
4) Add or Remove AccessRule(Permission) to Group
From my side, I have no clear idea about what actually your logic or implementation,
But Here I tried to give a solution for adding or remving access rule to group
//DirectoryEntry for OU Level
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://OU=MYOU,DC=MYDC,DC=COM");
NTAccount account = new NTAccount("MYDC", "groupName");
ActiveDirectoryAccessRule ruleRead = new ActiveDirectoryAccessRule(
account,
ActiveDirectoryRights.ReadProperty,
AccessControlType.Allow,
ActiveDirectorySecurityInheritance.None);
ActiveDirectoryAccessRule ruleWrite = new ActiveDirectoryAccessRule(
account,
ActiveDirectoryRights.WriteProperty,
AccessControlType.Deny,
ActiveDirectorySecurityInheritance.None);
if (Permission == "User shall be able to export private key from an RSA keypair")
{
directoryEntry.ObjectSecurity.AddAccessRule(ruleRead);
directoryEntry.ObjectSecurity.AddAccessRule(ruleWrite);
directoryEntry.Options.SecurityMasks = SecurityMasks.Dacl;
directoryEntry.CommitChanges();
Console.WriteLine("Added Deny Access to Read & Write.");
}
if (Permission == "User is able to decrypt imported data")
{
directoryEntry.ObjectSecurity.RemoveAccessRule(ruleRead);
directoryEntry.ObjectSecurity.RemoveAccessRule(ruleWrite);
directoryEntry.Options.SecurityMasks = SecurityMasks.Dacl;
directoryEntry.CommitChanges();
Console.WriteLine("Removed Deny Access to Read & Write.");
}
directoryEntry.Close();
directoryEntry.Dispose();
Note: Please test all above code in your test environment first.
You're trying to use AD as both your AuthZ store and your AuthZ engine if I follow the question correctly. The former (using it as a data store) makes perfect sense, but, I don't think it's the right tool to evaluate access for your app.
What I would do is layer your groups in two levels:
Level 1 - permission groups (e.g. can encrypt, can decrypt, etc.)
Level 2 - roles - these are members of various permission groups, and in turn users are added to these groups to grant them the roles. They will inherit the permissions the roles have when their logon token is built by Windows.
Assuming your app uses Windows Authentication, the WindowsTokenRoleProvider (https://msdn.microsoft.com/en-us/library/system.web.security.windowstokenroleprovider(v=vs.110).aspx) will surface all of the group memberships up into your app and you can then check if someone is in a permission group and let them do something (or not)...
Hello I'm stuck trying to add a function to my Windows forms program that allows a user to type in a textbox what computer or computers they would like to search for in Active Directory. The user would input the search string in a textbox then hit a button and the computers that match that search result would appear in a separate search box. Here is my code so far.
I would also like each computer name to be on a separate line such as:
computername1
computername2
computername3
Thanks!
This is what inside the button looks like:
List<string> hosts = new List<string>();
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://servername";
try
{
string adser = txtAd.Text; //textbox user inputs computer to search for
DirectorySearcher ser = new DirectorySearcher(de);
ser.Filter = "(&(ObjectCategory=computer)(cn=" + adser + "))";
ser.PropertiesToLoad.Add("name");
SearchResultCollection results = ser.FindAll();
foreach (SearchResult res in results)
//"CN=SGSVG007DC"
{
string computername = res.GetDirectoryEntry().Properties["Name"].Value.ToString();
hosts.Add(computername);
//string[] temp = res.Path.Split(','); //temp[0] would contain the computer name ex: cn=computerName,..
//string adcomp = (temp[0].Substring(10));
//txtcomputers.Text = adcomp.ToString();
}
txtcomputers.Text = hosts.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
de.Dispose();//Clean up resources
}
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 the System.DirectoryServices.AccountManagement namespace
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))
{
// find a computer
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(ctx, "SomeComputerName");
if (computer != null)
{
// do something here....
}
}
If you don't need to find a single computer, but search for a whole list of computers, you can use the new PrincipalSearcher interface, which basically allows you to set up a "QBE" (query-by-example) object you're looking for, defining the search criteria, and then search for matches for those criteria.
The new S.DS.AM namespace makes it really easy to play around with users and groups in AD!
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.
I am using a WCF service to expose certain Active Directory management functions to our help desk staff without giving them the group membership required to manipulate AD directly. Adding users to and removing users from groups is working like a champ with existing users, but every time I create a new user it throws back this fun code:
The server is unwilling to process the request. (Exception from HRESULT: 0x80072035)
The code I use to add the user to the group is
public bool AddGroupToUser(string userDn, string groupDn)
{
try
{
DirectoryEntry groupEntry = LdapTools.GetDirectoryEntry(groupDn);
groupEntry.Properties["member"].Add(userDn);
groupEntry.CommitChanges();
groupEntry.Close();
return true;
}
catch (DirectoryServicesCOMException)
{
return false;
}
}
Everything I've read on the subject is rather vague and I can't seem to find out WHY the exception is being triggered. Any ideas?
UPDATE
This is the code I use to create the user in AD:
try
{
DirectoryEntry container = GetDirectoryEntry(storageOu);
DirectoryEntry newUser = container.Children.Add("CN=" + employee.FullName, "user");
newUser.Properties["sAMAccountName"].Value = employee.Username;
newUser.Properties["displayName"].Value = employee.FullName;
newUser.Properties["givenName"].Value = employee.FirstName;
newUser.Properties["sn"].Value = employee.LastName;
newUser.Properties["department"].Value = departmentName;
newUser.Properties["userPrincipalName"].Value = employee.Username + "#APEX.Local";
newUser.CommitChanges();
newUser.Invoke("SetPassword", new object[] { employee.Password });
newUser.CommitChanges();
AdsUserFlags userSettings = AdsUserFlags.NormalAccount;
newUser.Properties["userAccountControl"].Value = userSettings;
newUser.CommitChanges();
ldapPath = newUser.Path;
newUser.Close();
container.Close();
}
catch (DirectoryServicesCOMException e)
{
// Something went wrong... what???
}
catch (Exception e)
{
// Something else went wrong
}
The new user can login, and can be manipulated using the standard MS tools.
Apparently, unless I'm missing an important step here, the issue is time. When forcing the system to sleep for 8 seconds before attempting to add groups to the new user the process works. If I do it any sooner than the 8 second mark it fails.
I'm marking this answer as correct unless anybody can provide me a better solution.
Try:
public bool AddUserToGroup(string userName, string groupName)
{
bool done = false;
GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);
if (group == null)
{
group = new GroupPrincipal(context, groupName);
}
UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);
if (user != null & group != null)
{
group.Members.Add(user);
group.Save();
done = (user.IsMemberOf(group));
}
return done;
}
Reference:
http://www.c-sharpcorner.com/UploadFile/dhananjaycoder/activedirectoryoperations11132009113015AM/activedirectoryoperations.aspx
As it mentioned in here, can you tell us that you set the password of the newly created users? In the reference, it says that you should SetPassword of the user before doing anything with it.
Time issue could occur from a Active Directory replication issue.
Once, I gave a product to my customer which creates user over Active Directory, which has over 10.000 records in it, with the given informations on a SharePoint form and then program adds the user to a SharePoint group. The problem was, SharePoint throws an error about the newly created user, it says user does not exist in AD.
So, one of out system engineer told us about the replication opearation on the Active Directory that it could be the source of the problem and it was true.
For the solution, program tries to do the job for 10 times with 1 second sleeps. No problem occurred so far. So as a solution, I would suggest you to check out the AD for the existence of replication method.
P.S: When I asked questions to my customers system engineers about the replication operation, they all rejected the existence of AD replication operation and told me that the program has the problem. They believed me when we created a new user in AD from a computer, we couldn't see the user for 5 seconds on an another computer.
I posted a question re LDAP account management, but after exploring this, it's not what i'm after. I've managed to find two ways of creating users on a machine, and i find one is much neater than the other, however, i am uncertain how to convert the first option over to the second option entirely.
This was my first solution:
Process MyProc = new Process();
MyProc.StartInfo.WorkingDirectory = System.Environment.SystemDirectory;
MyProc.StartInfo.FileName = "net.exe";
MyProc.StartInfo.UseShellExecute = false;
MyProc.StartInfo.RedirectStandardError = true;
MyProc.StartInfo.RedirectStandardInput = true;
MyProc.StartInfo.RedirectStandardOutput = true;
MyProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
MyProc.StartInfo.Arguments = string.Format(#" user {0} {1} /ADD /ACTIVE:YES /EXPIRES:NEVER /FULLNAME:{0}"" /PASSWORDCHG:NO /PASSWORDREQ:YES", username, password);
MyProc.Start();
MyProc.WaitForExit();
int exit = MyProc.ExitCode;
MyProc.Close();
return exit == 0;
And this was my second (preffered) solution:
DirectoryEntry root = GetDELocalRoot();
DirectoryEntry user = root.Children.Add(username, "user");
//TODO: Always Active
//TODO: Never Expires
//TODO: No Password Change
//TODO: Password Required
user.Properties["description"].Value = "Account for running the MicaService and handling updates.";
user.Invoke("SetPassword", new object[] { password });
user.CommitChanges();
user.Close();
I would like to map all the settings in my TODO: from the first solution into my second neater solution.
I have tried the following line as well:
user.Properties["userAccountControl"].Value = ADS_USER_FLAG.ADS_UF_NORMAL_ACCOUNT | ADS_USER_FLAG.ADS_UF_PASSWD_CANT_CHANGE | ADS_USER_FLAG.ADS_UF_DONT_EXPIRE_PASSWD;
But this does not work as the property does not exist in cache.
NOTE: the GetDELocalRoot() = return new DirectoryEntry("WinNT://" + Environment.MachineName);
Thanks for any input!
Regards
Tris
Check out my friend Richard Mueller's web site which has lots of useful information and reference material on what those two providers - WinNT for local machine accounts vs. LDAP for network accounts - have to offer.
There's also a Excel sheeet with all attributes that the WinNT provider exposes - it's a lot less than what the LDAP provider has, so I'm not sure if you'll be able to set all the properties you're looking for.
Marc