I want to find if the user belongs to an AD group. Can you advise how I can add that functionality using the following code?
I ask the user to enter their username and password (through a form), so not using the windows credentials. With the below code I am able to validate the user, by passing the username, and password. How can I build on the code to check if user exists in the AD Group. Is there another way to do this? Please advice
DirectoryEntry adsEntry = new DirectoryEntry("domain", userid, password);
DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry);
try {
SearchResult adsSearchResult = adsSearcher.FindOne();
context.Session.Timeout = 2;
context.Session["ValidatedLoginID"] = userid;
user.Verified = true;
adsEntry.Close();
} catch ( Exception ex ) {
// Failed to authenticate. Most likely it is caused by unknown user
// id or bad strPassword.
user.error = ex.Message;
adsEntry.Close();
}
You can use the below code:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DOMAINNAME");
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
if(user != null)
{
// check if user is member of that group
if (user.IsMemberOf(group))
{
// do something.....
}
}
Also look at: How to check if a user belongs to an AD group?
Here is how I solved this :
DirectoryEntry adsEntry = new DirectoryEntry("domain", userid, password);
DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry);
adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName=" + userid + "))";
try
{
SearchResult adsSearchResult = adsSearcher.FindOne();
string propertyName = "memberOf";
ResultPropertyValueCollection rpvcResult = adsSearchResult.Properties[propertyName];
foreach (Object PropertyValue in rpvcResult)
{
if (PropertyValue.ToString() == "Group Name")
{
user.Verified = true;
user.FullName = GetFullName(userid);
adsEntry.Close();
} else
{
user.Verified = false;
user.error = "You do not belong to the Group so you cannot do this function";
}
}
} catch (Exception ex)
{
user.error = "Please check your username and password credentials";
adsEntry.Close();
}
Related
I tried to change/reset password to user that has to change his password after first login using c#
My code:
var domain = WebConfigurationManager.AppSettings["ONLINE-AD"];
directoryEntry.Username = userName;
directoryEntry.Password = password;
var directorySearcher = new DirectorySearcher(directoryEntry);
SearchResult result = directorySearcher.FindOne();
if (result != null)
{
DirectoryEntry userEntry = result.GetDirectoryEntry();
if (userEntry != null)
{
userEntry.Invoke("SetPassword", model.Resetpassword);
userEntry.CommitChanges();
}
}
But when I tried to do FindOne() i got an error 773 (means that the user has to change password for first time)
here is the error :
How to access user using LDAP ?(I successed to do login with
proper user)
I created Admin user that can manage all users then I got all users using the admin and find the wanted user and set password to this user:
public string ResetPassword(LoginDTO model) {
try {
//get context by admin user
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, WebConfigurationManager.AppSettings["ONLINE-AD"], WebConfigurationManager.AppSettings["AdminName"], WebConfigurationManager.AppSettings["AdminPassword"]);
//find the wanted user
var user = UserPrincipal.FindByIdentity(ctx, model.UserName);
if (user != null) {
try {
user.ChangePassword(model.Password, model.NewPassword);
} catch {
return "-1";
}
}
} catch (Exception ex) {
return "-1";
}
return "1"
}
Currently, I am validating the credentials of an Active Directory user with the help of this code:
string _groups = "";
bool _isAuthSuccess=true;
List<string> user_groups = new List<string>();
try
{
using (PrincipalContext _loginContext = new PrincipalContext(ContextType.Domain, "domainname"))
{
_message += "calling ValidateCredentials";
_isAuthSuccess = _loginContext.ValidateCredentials(model.Email, model.Password);
if(_isAuthSuccess)
{
_message += "calling FindByIdentity";
var user = UserPrincipal.FindByIdentity(_loginContext, model.Email);
if (user != null)
{
// get the user's groups
_message += "calling GetAuthorizationGroups";
var groups = user.GetAuthorizationGroups();
foreach (GroupPrincipal group in groups)
{
// save those groups to session for further processing after login
if ((bool)group.IsSecurityGroup)
{
user_groups.Add(group.Name);
}
}
}
_groups = string.Join(",", user_groups);
}
else
{
_message += "_isAuthSuccess is false";
}
}
}
catch (PrincipalServerDownException)
{
_message += "Error at logon validatyion as server is down ";
}
catch(Exception ex)
{
_message += "Exception : "+ex.Message;
}
The bool flag is returning the status the user credentials are valid or not. Now i wanted to fetch the list of Active Directory UserGroups the user is a member of. I found that the method GetAuthorizationGroups will return the list of user groups. But I am struggling to relate these 2 methods as there is no way to call _loginCOntext.GetAuthorizationGroups()
So how can efficiently handle these 2 cases together
validate credentials and
get the list of user groups together.
The GetAuthorizationGroups() method can only be called on a UserPricipal, so you need to get one for the user. That's easy to do with the UserPrincipal.FindByIdentity method (while reusing the _loginContext object you already have):
var user = UserPrincipal.FindByIdentity(_loginContext, user_name);
var groups = user.GetAuthorizationGroups();
Update: To avoid the "Multiple connections" error, try using different instances of PrincipalContext for each operation. At the end of the using, it should disconnect the connection with the server and allow you to start a new one with different credentials without problem.
using (PrincipalContext _loginContext = new PrincipalContext(ContextType.Domain, "domainname"))
{
_message += "calling ValidateCredentials";
_isAuthSuccess = _loginContext.ValidateCredentials(model.Email, model.Password);
}
using (PrincipalContext _loginContext = new PrincipalContext(ContextType.Domain, "domainname", "username", "password"))
{
if(_isAuthSuccess)
{
...
}
else
{
_message += "_isAuthSuccess is false";
}
}
My C# application communicates with the active directory and is able to provide me when i select a user i can see the groups he is a member of and if i select the group i am able to see the users in the group. Now the new requirement i want to see the computers each user is associated with.
private void FillComputers()
{
computers.Items.Clear();
PrincipalContext PrincipalContext1 = new PrincipalContext(ContextType.Domain);
ComputerPrincipal cp = new ComputerPrincipal(PrincipalContext1);
PrincipalSearcher search = new PrincipalSearcher(cp);
foreach (var cpn in search.FindAll())
{
computers.Items.Add(cpn.SamAccountName);
}
}
Gives me all the computers how do i pass the selected user as a parameter to the FillComputers above??? Thanks in Advance for all your suggestions.
For example when i have users and i had to find out the groups they were memebers of i did this
The below fills the listbox with all users:
private void filluser()
{
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for any UserPrincipal
UserPrincipal qbeUser = new UserPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach (var found in srch.FindAll())
{
try
{
// do whatever here
UserPrincipal foundUser = found as UserPrincipal;
if (foundUser != null)
{
foundUser.IsAccountLockedOut();
user.Items.Add(foundUser.GivenName + " " + foundUser.Surname + " " + "[" + foundUser.SamAccountName + "]");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
To Fill another list box with the groups the users were members of I did this
private void fillmembersof()
{
Groups.Items.Clear();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
String input = user.Text;
string username = input.Split(new char[] { '[', ']' })[1];
// define a "query-by-example" principal - here, we search for any UserPrincipal
UserPrincipal usr = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username);
if (usr != null)
{
foreach (var group in usr.GetGroups())
{
Groups.Items.Add(group.Name);
}
usr.Dispose();
}
ctx.Dispose();
}
Than to fill the above text box based on users selected i did this:
private void user_SelectedIndexChanged(Object sender, EventArgs e)
{
fillmembersof();
**FillComputers();** -> i want to be able to do the same for computers the user has access to?????
Thanks you in advance for all your valuable suggestions!!!!
I need to let users bind there accounts to the Active Directory. This means that admin needs a GUI where he/she can write a Active Directory account like this : MyDomain\MyName and then get a validation if the users exists before save.
Im using this code to validate the name :
public static bool CheckActiveDirectoryAccount(string account)
{
string ADServer = null;
string ADDomain = null;
string ADUserName = null;
string ADUserPassword = null;
SetADSettings(out ADServer, out ADDomain, out ADUserName, out ADUserPassword);
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, ADServer, ADUserName, ADUserPassword))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, account))
{
if(user != null)
return true;
else
return false;
}
}
}
The problem with this code is that there seems to be no way to check the user for a specific domain? Instead I have to input the server, if I try to input the domain instead there will be exception(Server not found).
How do I let the admin enter domain and username of a AD account and then check it against the AD?
I am able to pass the domain into the principalcontext without issue, I'm not passing in the server. I would expect this to work for you.
public static bool CheckActiveDirectoryAccount(string account, string domain)
{
using (var pc = new PrincipalContext(ContextType.Domain, domain))
{
// Find a user
UserPrincipal user = UserPrincipal.FindByIdentity(pc, account);
if (user == null)
return false;
return true;
}
}
I have noticed poor performance when passing in the NetBIOS domain name, though it does work. As a result I pass in the DNS domain name whenever possible.
I ended up with this :
public static string CheckActiveDirectoryAccount(string account)
{
UserPrincipal user;
PrincipalContext context;
List<string> userPrincipalNameList;
string ADServer = null;
string ADUserName = null;
string ADUserPassword = null;
string userAccount;
account = account.ToLower();
GetADSettings(out ADServer, out ADUserName, out ADUserPassword);
if (ADUserName.Length > 0)
context = new PrincipalContext(ContextType.Domain, ADServer, null, ADUserName, ADUserPassword);
else
context = new PrincipalContext(ContextType.Domain, ADServer);
using (context)
{
if((user = UserPrincipal.FindByIdentity(context, account)) == null)
{
if(account.Contains("\\"))
{
userPrincipalNameList = user.UserPrincipalName.Split('\\').ToList();
if (userPrincipalNameList.Count > 0)
user = UserPrincipal.FindByIdentity(context, userPrincipalNameList[0]);
}
}
if (user != null)
{
using (user)
{
userPrincipalNameList = user.UserPrincipalName.Split('#').ToList();
userAccount = userPrincipalNameList.First();
if (userPrincipalNameList.Count > 1)
userAccount = userPrincipalNameList.Last() + "\\" + userAccount;
if (user != null)
return userAccount.ToLower();
}
}
}
return string.Empty;
}
i have a code to get the groups a user belongs to.
try
{
DirectoryEntry adRoot = new DirectoryEntry(string.Format("WinNT://{0}", Environment.UserDomainName));
DirectoryEntry user = adRoot.Children.Find(completeUserName, "User");
object obGroups = user.Invoke("Groups");
foreach (object ob in (IEnumerable)obGroups)
{
// Create object for each group.
DirectoryEntry obGpEntry = new DirectoryEntry(ob);
listOfMyWindowsGroups.Add(obGpEntry.Name);
}
return true;
}
catch (Exception ex)
{
new GUIUtility().LogMessageToFile("Error in getting User MachineGroups = " + ex);
return false;
}
the above code works fine when i have to find the groups of a local user but
for a domain user it returns a value "Domain User" which is kind of wierd as it is a part of 2 local groups.
Please can some1 help in solving this mystery. thanks
Research
I did some finding and got that i am being returned the primary group of the domain user
called "Domain User" group
but what i actually want is the groups of the local machines the domain user is a part of... i cannot get that.. any suggestions
another code using LDAP
string domain = Environment.UserDomainName;
DirectoryEntry DE = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.Secure);
DirectorySearcher search = new DirectorySearcher();
search.SearchRoot = DE;
search.Filter = "(SAMAccountName=" + completeUserName + ")"; //Searches active directory for the login name
search.PropertiesToLoad.Add("displayName"); // Once found, get a list of Groups
try
{
SearchResult result = search.FindOne(); // Grab the records and assign them to result
if (result != null)
{
DirectoryEntry theUser = result.GetDirectoryEntry();
theUser.RefreshCache(new string[] { "tokenGroups" });
foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
{
System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0);
DirectorySearcher sidSearcher = new DirectorySearcher();
sidSearcher.SearchRoot = DE;
sidSearcher.Filter = "(objectSid=" + mySID.Value + ")";
sidSearcher.PropertiesToLoad.Add("distinguishedName");
SearchResult sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
listOfMyWindowsGroups.Add((string)sidResult.Properties["distinguishedName"][0]);
}
}
}
else
{
new GUIUtility().LogMessageToFile("no user found");
}
return true;
}
catch (Exception ex)
{
new GUIUtility().LogMessageToFile("Error obtaining group names: " + ex.Message + " Please contact your administrator."); // If an error occurs report it to the user.
return false;
}
this works too but i get the same result "Domain Users" . Please can some1 tell me how to get the local machine groups...????
If you are using .NET 3.5, you can use System.DirectoryService.AccountManagement to do all the user and group management. In particular, UserPrincipal.GetAuthorizationGroups is exactly what you are looking for. It retrieves both local group and machine group for a particular users. If the group is a local group, GroupPrincipal.Context.Name is showing the machine name where the group come from. If the group is a domain group, GroupPrincipal.Context.Domain is showing the domain name where the group comes from.
PrincipalContext context = new PrincipalContext(ContextType.Domain, "yourdomain.com");
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "youruser");
foreach (GroupPrincipal group in userPrincipal.GetAuthorizationGroups())
{
Console.Out.WriteLine("{0}\\{1}", group.Context.Name, group.SamAccountName);
}
I would say the problem is that you're search is starting in the domain. You want to change the location of the search to the local machine.
Something like this would do it;
DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");