Log in through active directory - c#

I want to create LogIn button through Active Directory.
So i have an idea to take Name logged user(Windows) from his Domain:
string Name = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
and then take Group for Login above:
string Group = System.Security.Principal.WindowsIdentity.GetCurrent().Groups.ToString(); // <---I think this is wrong ?
string allowedGroup = "Admins";
then something like:
if(Name == string.Empty)
{
MessageBox.Show("Your Name in domain doesn't exist");
}
if(Group.ToString() != allowedGroup)
{
MessageBox.Show("You don't have permissions to log in");
}
else
{
MessageBox.Show("Hello");
}
I think my 'getting group' is wrong. How can I do it? I don't know how to exactly search for one or two groups where User is assigned.
What about when user is assigned to many Groups?

Here is the point to use windows identity to authorize login.
1) Get the windows identity of user.
2) Use Windows identity object to get the other information like name and group.
use group name to validate user request.
Hope this will help you. Please write in comment in you have any questions.
System.Security.Principal.WindowsIdentity WI = System.Security.Principal.WindowsIdentity.GetCurrent();
string sUserName = WI.Name;
bool bAuthorized = false;
string allowedGroup = "Admins";
IdentityReferenceCollection irc = WI.Groups;
foreach (IdentityReference ir in irc)
{
if(ir.Translate(typeof(NTAccount)).Value == allowedGroup)
{
bAuthorized = true;
break;
}
}
if(string.IsNullOrEmpty(sUserName))
{
MessageBox.Show("Your Name in domain doesn't exist");
}
if(bAuthorized == false)
{
MessageBox.Show("You don't have permissions to log in");
}
else
{
MessageBox.Show("Hello");
}

Ok, i got this. Thanks for Pankaj.
System.Security.Principal.WindowsIdentity WI = System.Security.Principal.WindowsIdentity.GetCurrent();
string sUserName = WI.Name;
bool bAuthorized = false;
string allowedGroup = "Admins";
IdentityReferenceCollection irc = WI.Groups;
foreach (IdentityReference ir in irc)
{
NTAccount accInfo = (NTAccount)ir.Translate(typeof(NTAccount));
if (accInfo.Value == allowedGroup)
{
bAuthorized = true;
break;
}
}
if(string.IsNullOrEmpty(sUserName))
{
MessageBox.Show("Your Name in domain doesn't exist");
}
if(bAuthorized == false)
{
MessageBox.Show("You don't have permissions to log in");
}
else
{
MessageBox.Show("Hello");
}

Related

Validation for the data input c#

I am trying to make a login window for users and admin using XML files, so my issue is how to validate that the username and pwd field if the password is incorrect, my code only validate for admin but for the user, the form shows and it gives error as well.
It will be better if I can make it up with errorProvider.
Thank you in advance.
private void btnlogin_Click(object sender, EventArgs e)
{
XmlDocument doc = new XmlDocument();
string file = #"../../../data/UsersDatabase.Xml";
doc.Load(file);
foreach (XmlNode node in doc.SelectNodes("//User"))
{
username = node.SelectSingleNode("id").InnerText;
pwd = node.SelectSingleNode("pass").InnerText;
}
if (username.Equals(txtusername.Text) && pwd.Equals(txtpwd.Text))
{
purchase fpur = new purchase();
fpur.Show();
}
foreach (XmlNode node in doc.SelectNodes("//Admin"))
{
username = node.SelectSingleNode("id").InnerText;
pwd = node.SelectSingleNode("pass").InnerText;
}
if (username.Equals(txtusername.Text) && pwd.Equals(txtpwd.Text))
{
Adminpanel fadmin = new Adminpanel();
fadmin.Show();
}
else
{
MessageBox.Show("Sorry, username and password are incorrect",
"Login Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
According your xml and your description, you would like to show different forms when we
input the correct userid and password.
I make the following code and it works well.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
User user = new User();
Admin admin = new Admin();
string path = "D:\\test.xml";
XDocument doc = XDocument.Load(path);
var user1 = doc.Descendants("User");
foreach (XElement item in user1)
{
if (txtUserName.Text==item.Element("id").Value&& txtPWD.Text == item.Element("pass").Value)
{
user.Show();
}
}
var admin1= doc.Descendants("Admin");
foreach (XElement item in admin1)
{
if (txtUserName.Text == item.Element("id").Value && txtPWD.Text == item.Element("pass").Value)
{
admin.Show();
}
}
}
}
Besides, you need to use using System.Xml.Linq;;
The next is the tested xml.
<?xml version="1.0" encoding="utf-8"?>
<Loginlist>
<Admin>
<FirstName>Administrator</FirstName>
<LastName>A</LastName>
<EmailAddress>admin#ge.com</EmailAddress>
<PhoneNumber>1</PhoneNumber>
<id>admin</id>
<pass>admin</pass>
</Admin>
<User>
<FirstName>Ab</FirstName>
<LastName>Mo</LastName>
<EmailAddress>ab#ge.com</EmailAddress>
<PhoneNumber>1</PhoneNumber>
<id>user</id>
<pass>user</pass>
</User>
</Loginlist>
The tested result:
Couple of points -
Your code is not making differentation between the admin and the user validation - For istance - once the user code is validated as mentioned below -
if (username.Equals(txtusername.Text) && pwd.Equals(txtpwd.Text))
{
purchase fpur = new purchase();
fpur.Show();
}
The admin code is still running in the background and as the XML wont validate the admin
at that time it is giving error as you mentioned -
When you pass admin related XML it will only validate the admin code as it is at the end of code so admin related code is working fine.
If you want validate both then you may have differentiate them whether the input is
admin or user in that way your conditional statements will run accordingly. Aso I
removed couple of duplicate code and the code below is one way of doing it and place this code in your btnlogin_Click event code-
XmlDocument doc = new XmlDocument();
string file = #"../../../data/UsersDatabase.Xml";
doc.Load(file);
bool isUser = false;
bool isAdmin = false;
//User
foreach (XmlNode node in doc.SelectNodes("//User"))
{
isUser = true;
username = node.SelectSingleNode("id").InnerText;
pwd = node.SelectSingleNode("pass").InnerText;
}
//Admin
foreach (XmlNode node in doc.SelectNodes("//Admin"))
{
isAdmin = true;
username = node.SelectSingleNode("id").InnerText;
pwd = node.SelectSingleNode("pass").InnerText;
}
if (username.Equals(txtusername.Text) && pwd.Equals(txtpwd.Text))
{
if (isAdmin)
{
Adminpanel fadmin = new Adminpanel();
fadmin.Show();
}
else if(isUser)
{
purchase fpur = new purchase();
fpur.Show();
}
}
else
{
MessageBox.Show("Sorry, username and password are incorrect",
"Login Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Find if user belongs to group

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();
}

C# Issue with manipulating ActiveDirectory users

I'm writing some kind of a mini AD tool (with VS-C#) to our organization and got into an issue.
I have a main function that searches the user (when I click on it in a listview) and some functions that manipulate the user's object.
public DirectoryEntry GetUser(string username)
{
try
{
Forest currentForest = Forest.GetCurrentForest();
GlobalCatalog gc = currentForest.FindGlobalCatalog();
using (DirectorySearcher searcher = gc.GetDirectorySearcher())
{
searcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + username + "*))";
SearchResult results = searcher.FindOne();
if (!(results == null))
{
DirectoryEntry de = new DirectoryEntry(results.Path, strAdminUser, strAdminPass, AuthenticationTypes.Secure);
de.RefreshCache(new string[] { "canonicalName" });
de.Path = de.Properties["canonicalName"].Value.ToString();
de.CommitChanges();
return de;
}
else
{
return null;
}
}
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
}
and here's an example of a function that checks if the user is locked:
public bool IsUserLocked(string username)
{
try
{
DirectoryEntry de = GetUser(username);
string attName = "msDS-User-Account-Control-Computed";
de.RefreshCache(new string[] { attName });
const int UF_LOCKOUT = 0x0010;
int userFlags = /*(int)*/Convert.ToInt32(de.Properties[attName].Value);
if ((userFlags & UF_LOCKOUT) == UF_LOCKOUT)
{
return true;
}
de.Dispose();
return false;
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return false;
}
}
The function that checks the locked status of a user always fails with an error: "Unspecified error", but if I'm not changing the Directory Entry's path in the first function I get "The server is unwilling to process the request" error (I'm using proper service username and password with all the permissions needed) but still it happens.
Can someone spot the issue?
How about using System.DirectoryServices.AccountManagement namespace? If you have no issue using the new namespace, there's a simpler way to check if user account is locked and unlock if needed.
public bool IsUserLocked (string username)
{
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "yourdomain.com")
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username)
{
if (user != null) return user.IsAccountLockedOut();
}
}
return null;
}
And similarly, you can unlock the user account if needed.
...
if (user != null)
{
user.UnlockAccount();
user.Save();
}
Got it...
This has solved my issue:
de.Path = results.Path.Replace("GC://DCNAME.", "LDAP://");
Since I'm searcing on the Global Catalog, I had to replace a portion in the path to match it to the correct path:
public DirectoryEntry GetUser(string username)
{
try
{
Forest currentForest = Forest.GetCurrentForest();
GlobalCatalog gc = currentForest.FindGlobalCatalog();
using (DirectorySearcher searcher = gc.GetDirectorySearcher())
{
searcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + username + "*))";
SearchResult results = searcher.FindOne();
if (!(results == null))
{
DirectoryEntry de = new DirectoryEntry(results.Path, strAdminUser, strAdminPass, AuthenticationTypes.Secure);
de = new DirectoryEntry(results.Path);
de.Path = results.Path.Replace("GC://DCNAME.", "LDAP://");
de.CommitChanges();
//System.Windows.Forms.MessageBox.Show(de.Path);
return de;
}
else
{
return null;
}
}
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
}
Now the path returns to the function called GetUser in the correct format :)

Why do I have 2 ASPXAUTH cookie instead of 1?

i am creating an asp.net application, it's already working by now, but the problem is when i use "Live HTTP Headers" i found that my site have 2 ASPXAUTH cookie, and the one being used is the bottom one.
here i give a screen shoot what i found:
btw here is some of my code in login page :
string email = tbEmail.Text;
string pass = tbPass.Text;
bool remember = cbRemember.Checked;
var res = (from user in ctx.users
where user.password == ctx.ConvertPassword(pass)
&& user.email == email
select user).FirstOrDefault(); // Remark : 0 = active, 1 = Inactive, 2 = Suspend, 3 = Unconfirmed
if (res != null && res.email.ToLower() == email.ToLower())
{
if (res.userstatus == 0 || res.userstatus == 3)
{
FormsAuthentication.SetAuthCookie(email, remember);
FormsAuthentication.RedirectFromLoginPage(email, remember);
var arr = Request.Cookies.AllKeys;
}
else if (res.userstatus == (int)UserStatus.Inactive)
{
lblMessage.Text = "You have deleted your account, if you wish to restore it, please click ";
btRecover.Visible = true;
}
else if (res.userstatus == (int)UserStatus.Suspended)
{
lblMessage.Text = "Your account has been suspended, for more information, please contact our support";
}
else
{
lblMessage.Text = "Invalid username or password";
}
}
else
{
lblMessage.Text = "Invalid username or password";
}
what i do wrong?
The
FormsAuthentication.SetAuthCookie(email, remember);
sets the cookie. But also does
FormsAuthentication.RedirectFromLoginPage(email, remember);
which is a higher level facade - not only sets the cookie but also redirects from the login page to the redirecturi pointing page.

How do I show a message box if the username is not in a database? C#

Hi all I have a University project and I am coding a login screen, my text book is far too vague and I can't figure out how to show a message box if the user name is not inside the database. Here is my code:
public void login()
{
//try
//{
var tbl = from s in this.database1DataSet.employee
where s.Username == userNameBox.Text
select s;
foreach (var s in tbl)
{
if (s.Username == userNameBox.Text && s.Password == passwordBox.Text)
{
MessageBox.Show("Access granted welcome " + s.fName);
this.Close();
}
else
{
MessageBox.Show("Access denied invalid login details");
}
}
//}
/*catch (SyntaxErrorException)
{
MessageBox.Show("User Does not exist");
}*/`enter code here`
If your where clause doesn't match any users, there won't be any rows in the results.
Therefore, your loop will never execute.
Instead, you can call FirstOrDefault() to get the first result row, or null if there aren't any.
You can check for existance of a user like:
if(!database1DataSet.employee.Any(r=> r.Username == userNameBox.Text))
{
MesasgeBox.Show("User does not exist");
}
Also IMO, its better if you check the user name and password together, and show a message like "Invalid Username/password" instead of multiple messages.
var user = database1DataSet
.employee
.FirstOrDefault(r=> r.Username == userNameBox.Text &&
r.Password == passwordBox.Text)
if(user != null)
{
MessageBox.Show("Access granted welcome " + user.fName);
this.Close();
}
else
{
MessageBox.Show("Invalid username/password");
}
Also see: Why encrypt user passwords?
I believe you want:
var user = (from s in this.database1DataSet.employee
where s.Username == userNameBox.Text &&
s.Password == passwordBox.Text
select s).FirstOrDefault();
if(user != null{
MessageBox.Show("Access granted welcome " + s.fName);
this.Close();
}
else{
MessageBox.Show("Access denied invalid login details");
}
void login()
{
var tbl = from s in this.database1DataSet.employee
where s.Username == userNameBox.Text
select s;
if(tbl.Count() == 0)
{
MessageBox.Show("User Does not exist");
return; // or this.Close(); if it's what you want
}
foreach (var s in tbl)
{
if (s.Username == userNameBox.Text && s.Password == passwordBox.Text)
{
MessageBox.Show("Access granted welcome " + s.fName);
this.Close();
}
else
{
MessageBox.Show("Access denied invalid login details");
}
}
First of all, assuming your usernames are unique, you will only ever have 0 or 1 values in tbl. That's fine, but be aware of it. Second, you're wanting to have different functionality of the size of tbl is 0, or 1. This is easily done with an if statement. If there is an entry, check credentials. Otherwise, show an error message for invalid username. Since this is a course project, I won't actually write sample code for you, but that should be enough to get it working. Good luck!

Categories

Resources