Secure website from SQL Injection ' using ASP.net and an Access database - asp.net

I currently have a website with a normal registration and login, coded with ASP.net.
I am using an Access database, while using a C# class my friend wrote for handling most of the database actions (executeQuery, executeRead, isExits...).
Now that I've almost finished building my website, I want to start adding security - mostly to my database. I have searched for a while now for a tutorial on the subject, but I could not find anything good exept an old microsoft msdn article which I couldn't realy get its code to work.
The furthest I've got now is just no allowing any dangerous characters in the username and password, (such as ',--,;), but it kind of feels as if it is the worse solution that i can use (why shouldn't my users use this characters?).
I think that the best solution I've found is somehow insertion the variables into the query string after declaring it (something to do with "WHERE username=#user" or something like that), but i couldn't get it to work with Access and with my oleDBManager.
here is my current registration code. handle() is removing all ' from the string, and Validate() checks for dangerous parts in the string.
string username = user.Text;
string password = pass.Text;
bool isThingy = false;
if (handle(ref password)) isThingy = true;
if (handle(ref username)) isThingy = true;
if (username != "" && username != null)
{
if (password != "" && password != null)
{
if (Validate(username, password))
{
if ((db.IsExist("SELECT * FROM Table1 WHERE username='" + username + "'") == false))
{
int a = db.ExecuteQuery("INSERT INTO `Table1`(`username`, `password`, `logins`, `email`, `fname`, `lname`, `country`, `city`, `birthday`, `userid`) VALUES ('" + username + "', '" + password + "', '0', '', '', '', '', '', '', '" + Convert.ToString(Convert.ToInt32(db.ExecuteCellRead("SELECT MAX(userid) FROM Table1")) + 1) + "');");
if (!isThingy) errorLabel.Text = "Your user has been successfully registered";
else errorLabel.Text = "The ' token is invalid. your user was registered absence the '.";
}
else
errorLabel.Text = "This username is already taken";
}
else errorLabel.Text = "Invalid name format";
}
else errorLabel.Text = "Please enter a password";
}
else errorLabel.Text = "Please enter a user name";
as for the oleDBManager (named db in my code):
private OleDbConnection link; // The link instance
private OleDbCommand command; // The command object
private OleDbDataReader dataReader; // The data reader object
private OleDbDataAdapter dataAdapter; // the data adapter object
private DataTable dataTable; // the data table object
private string dbName; // the Database filename
private int version; // the usersTableG office version
private string connectionString; // the connection string for the database connection
private string provider; // the matching driver string for the connection string
private string path; // the path to the database file
...
public int ExecuteQuery(string query)
{
this.link.Open();
int rowsAffected;
// ---
this.command = new OleDbCommand(query, this.link);
try
{
rowsAffected = this.command.ExecuteNonQuery();
}
catch (InvalidOperationException e)
{
if (e.Data == null)
throw;
else
rowsAffected = -1;
}
finally
{
this.command.Dispose();
this.link.Close();
}
// ---
return rowsAffected;
}
public bool IsExist(string query)
{
this.link.Open();
// ---
this.command = new OleDbCommand(query, this.link);
this.dataReader = this.command.ExecuteReader();
bool a = this.dataReader.Read();
// ---
this.command.Dispose();
this.link.Close();
// ---
return a;
}
public string ExecuteCellRead(string query)
{
string output = "";
this.dataTable = this.ExcecuteRead(query);
foreach (DataRow row in this.dataTable.Rows)
{
foreach (object obj in row.ItemArray)
{
output += obj.ToString();
}
}
return output;
}
So, as you might see, the main problem is that the user now can not use characters as '.
It suppose the best solution would be using the # variables in the SQL queries, but I have no idea how.
[thanks for your help]
PS. i HAVE changed my tables' name ;)
edit: most of you are telling me to use these parameterized queries, but it would be great if you could give me an example of how to use them, since i've never done that
So, thanks to #Remou, my FINAL code is:
db.DoWeirdStackOverFlowStuff(
"INSERT INTO `Table1`(`username`, `password`, `logins`) VALUES (#username, #password, '0');"
, new string[] { "#username", "#password" }
, new string[] { username, password });
and
public int DoWeirdStackOverFlowStuff(string query, string[] vars, string[] reps)
{
this.link.Open();
int rowsAffected;
// ---
this.command = new OleDbCommand();
this.command.CommandText = query;
this.command.CommandType = System.Data.CommandType.Text;
this.command.Connection = this.link;
//Parameters in the order in which they appear in the query
for (int i = 0; i < vars.Length; i++)
this.command.Parameters.AddWithValue(vars[i], reps[i]);
try
{
rowsAffected = this.command.ExecuteNonQuery();
}
catch (InvalidOperationException e)
{
if (e.Data == null)
throw;
else
rowsAffected = -1;
}
finally
{
this.command.Dispose();
this.link.Close();
}
// ---
return rowsAffected;
}
for whoever needs this =]

Some notes
In MS Access, I have a saved query called UpdateUser, it looks like this:
UPDATE INTERNETSETTINGS
SET url = [#url],
databasename = [#databasename],
port = [#port],
username = [#username],
[password] = [#password]
I can refer to this query by name in my code, using a command object:
OleDbCommand Command = new OleDbCommand();
Command.CommandText = "UpdateUser"; //saved query
Command.CommandType = System.Data.CommandType.StoredProcedure;
Command.Connection = cn; //a connection to the database
//Parameters in the order in which they appear in the query
Command.Parameters.AddWithValue("#url", "a"); //a,b,c etc for my test run
Command.Parameters.AddWithValue("#databasename", "b");
Command.Parameters.AddWithValue("#port","c");
Command.Parameters.AddWithValue("#username", "d");
Command.Parameters.AddWithValue("#password", "e");
Command.ExecuteNonQuery();

I don't remember whether Access does the same thing as SQL Server here, but in SQL Server you can escape the single quote mark by doubling it:
username = username.Replace("'", "''");
So you can include single-quote marks in the string, you can store them in the database, and they can't be used as malicious string terminators.

Related

Asp.net Active Directory LDAP: Trying to filter down into a group level

I have created a login page in asp.net using c# but I am having difficulty trying to only allow a certain group to have access. Right now I am accessing everyone but I can't seem to just filter the group that I need so only those person(s) can have access to my application.
Any help would be great so I can just permission this application out to that one group within Active Directory.
Here is my class that I am using to pass the groups:
public class LdapAuthentication
{
private string _path;
private string _filterAttribute;
public LdapAuthentication(string path)
{
_path = path;
}
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry( _path, domainAndUsername, pwd);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if(null == result)
{
return false;
}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
public string GetGroups()
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
String dn;
int equalsIndex, commaIndex;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
dn = (String)result.Properties["memberOf"][propertyCounter];
equalsIndex = dn.IndexOf("=", 1);
commaIndex = dn.IndexOf(",", 1);
if (-1 == equalsIndex)
{
return null;
}
groupNames.Append(dn.Substring((equalsIndex + 1),
(commaIndex - equalsIndex) - 1));
groupNames.Append("|");
}
}
catch (Exception ex)
{
throw new Exception("Error obtaining group names. " +
ex.Message);
}
return groupNames.ToString();
}
public bool isMember( String groupname )
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
String dn = (String)result.Properties["memberOf"][propertyCounter];
// The comma in the regex is important to prevent accidental matches
if ( Regex.IsMatch( dn, #"cn="+groupname+",.*", RegexOptions.IgnoreCase))
return true;
}
}
catch (Exception ex)
{
// Some logging here probably
}
return false;
}
}
It has to be in the Get groups function but I am not sure how to pass the group I am looking for. If anyone can help that would be greatly appreciated. Thanks in advance.
Here is my button click event:
protected void btnLogin_Click(object sender, EventArgs e)
{
// Path to you LDAP directory server.
// Contact your network administrator to obtain a valid path.
string adPath = "LDAP://domain.com";
LdapAuthentication adAuth = new LdapAuthentication(adPath);
String myGroupName = "Some_Group";
try
{
if (true == adAuth.IsAuthenticated(txtDomainName.Text, txtLoginID.Text, txtPassword.Text))
{
if( adAuth.isMember( myGroupName ) )
{
// User is authenticated and a member of the group.
// Create your auth ticket, cookie, and whatnot
// Retrieve the user's groups
string groups = adAuth.GetGroups();
// Create the authetication ticket
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, // version
txtLoginID.Text,
DateTime.Now,
DateTime.Now.AddMinutes(60),
false, groups);
// Now encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
// Create a cookie and add the encrypted ticket to the
// cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
// Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
// Redirect the user to the originally requested page
//Response.Redirect(FormsAuthentication.GetRedirectUrl(txtLoginID.Text, false));
Response.Redirect("LookupEdit.aspx");
}
else
{
lblError.Text = "Authorization failed. You are not a member of the "+myGroupName+" group";
}
}
else
{
lblError.Text = "Authentication did not succeed. Check user name and password.";
}
}
catch(Exception ex)
{
lblError.Text = "Error authenticating. " + ex.Message;
}
}
OK so after your comments, here's what you should do:
Create an isMember(String) function in your LdapAuthentication class:
public boolean isMember( String groupname )
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
String dn = (String)result.Properties["memberOf"][propertyCounter];
// The comma in the regex is important to prevent accidental matches
if ( Regex.IsMatch( dn, #"cn="+groupname+",.*", RegexOptions.IgnoreCase)
return true;
}
}
catch (Exception ex)
{ // Some logging here probably
}
return false;
}
Next, add this as your btnlogin_Click code:
<script runat=server>
void btnlogin_Click(Object sender, EventArgs e)
{
String adPath = "LDAP://your.domain.com"; //Enter your domain name here
LdapAuthentication adAuth = new LdapAuthentication(adPath);
String myGroupName = "auth-group-name"; //Enter your group's name (cn) here
try
{
if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
{
if( adAuth.isMember( myGroupName ) )
{
// User is authenticated and a member of the group.
// Create your auth ticket, cookie, and whatnot
}
else
{
errorLabel.Text = "Authorization failed. You are not a member of the "+myGroupName+" group";
}
}
else
{
errorLabel.Text = "Authentication did not succeed. Check user name and password.";
}
}
catch(Exception ex)
{
errorLabel.Text = "Error authenticating. " + ex.Message;
}
}
</script>
This should do the trick for you. Obviously you should create some code after the isMember() check to create a secure cookie that allows other pages to check the authenticated state of the user.
Good luck.
I was also having issues with this. I use pretty much the same class as you do to do the AD authentication. I was using a different way to connect to AD but was having some strange problems. I implemented a Role Provider before I changed to this code and I'm still using that Role provider to deny and grant access. This is how I basically did it. Follow this link as it will help you set up the roles.
The only thing I changed up was the "GetRolesForUser" with..
public override string[] GetRolesForUser(string username)
{
var allRoles = new List();
var ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if (user != null)
{
var groups = user.GetGroups();
allRoles.AddRange(groups.Select(x => x.Name));
}
return allRoles.ToArray();
}
This way, you can deny and grant groups within the web.config.
I do it like this..
<location path="TestPage.aspx">
<system.web>
<authorization>
<allow roles="SoftwareDevelopers" />
<deny users="*" />
</authorization>
</system.web>
</location>
So I'm denying everyone access to the TestPage.aspx besides the AD group SoftwareDevelopers.
I hope this helps.
EDIT: If you are using the link that is in the comment to do this active directory, one way to get the group is using the authentication ticket that's created when you login.
if (Request.Cookies["ADAuthCookie"] != null)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
string cookiePath = ticket.CookiePath;
DateTime expiration = ticket.Expiration;
bool expired = ticket.Expired;
bool isPersistent = ticket.IsPersistent;
DateTime issueDate = ticket.IssueDate;
string name = ticket.Name;
string userData = ticket.UserData;
int version = ticket.Version;
System.Diagnostics.Debug.WriteLine(cookiePath);
System.Diagnostics.Debug.WriteLine(expiration);
System.Diagnostics.Debug.WriteLine(expired);
System.Diagnostics.Debug.WriteLine(isPersistent);
System.Diagnostics.Debug.WriteLine(issueDate);
System.Diagnostics.Debug.WriteLine(name);
System.Diagnostics.Debug.WriteLine(userData);
System.Diagnostics.Debug.WriteLine(version);
if (userData.Contains("SoftwareDevelopers"))
{
lblMessage.Text = "You're a software developer.";
}
}
You will have to decrypt the ticket to be able to read the information. I have provided how to write it to the console so you could see how it works. If you wanted to, the if statement provided above is one way you can restrict/show parts of a page.
However, I'm finding that the link in this answer on how to set up the ADRoleProvider is probably going to be your best route.
You want to check if the user is a member of the correct group, right?
Why not create a function that accepts a group name and returns boolean, like this:
public boolean isMember( String username, String groupname )
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + username + ")";
search.PropertiesToLoad.Add("memberOf");
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
String dn = (String)result.Properties["memberOf"][propertyCounter];
// The comma in the regex is important to prevent accidental matches
if ( Regex.IsMatch( dn, #"cn="+groupname+",.*", RegexOptions.IgnoreCase)
return true;
}
}
catch (Exception ex)
{ // Some logging here probably
}
return false;
}
The best way is to let LDAP do the membership iteration, by specifying the groupname in your search. However that requires the groupname to be the complete group DN (e.g. cn=mygroup,ou=groups,dc=xxx,dc=xxx) so this might not be feasible for you:
public boolean isMember( String username, String groupdn )
{
DirectorySearcher search = new DirectorySearcher(_path);
// Escaping the input strings is advisable from a security standpoint!
search.Filter = "(&(cn=" + username + ")(memberOf=" + groupdn + "))";
search.PropertiesToLoad.Add("cn");
try
{
SearchResult result = search.FindOne();
// The LDAP server has done the matching for us
if ( result != null )
return true;
}
catch (Exception ex)
{ // Some logging here probably
}
return false;
}
Good luck!

Get Specific data from access database

I have a login form which require two fields. One is for email and other is password. I want to get email and password from database and then match it with user entered email and password.
So far I have done this.
public int checkLogin(String email,String pass)
{
try
{
conn = new OleDbConnection();
cmd = new OleDbCommand();
da = new OleDbDataAdapter();
ds = new DataSet();
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=E:\\Users\\He Man\\Documents\\Project.accdb";
conn.Open();
cmd.CommandText = "SELECT Email, [Password] FROM UserProfile"
+" where Email='"+email+"' and Password='"+pass+"';";
int checkPoint=0;
da.SelectCommand = cmd;
da.Fill(ds);
for (int i = 0; i < ds.Tables["UserProfile"].Rows.Count; i++)
{
if (ds.Tables["UserProfile"].Rows[i]["Email"].ToString() == email && ds.Tables["UserProfile"].Rows[i]["[Password]"].ToString() == pass)
{
checkPoint = 1;
}
else
{
checkPoint =0;
}
}
conn.Close();
return checkPoint;
}
catch(Exception)
{
return 0;
}
}
It returns 1 if data match and 0 if didn't match kindly help. I just wanted to match my data to each data value in the dataset.
You are doing too many things wrong.
you absolutely don't need to do this
if (ds.Tables["UserProfile"].Rows[i]["Email"].ToString() == email ...
because, your query has a where condition, i.e. if the Username and password won't match, your DataSet is going to be empty, so you should better check, whether your ds is empty or not.
You are prone to SQL Injection. A 7th Grade kid can drop your entire database. Do NOT USE Concatenated string as your command query, use parameterized one, i.e.
query = "Select Count(*) From UserProfile Where Username= #username and
Password=#password";
OleDbCommand cmd = new OleDbCommand(query, conn);
cmd.Parameters.AddWithValue("#username", txtUsername.Text);
cmd.Parameters.AddWithValue("#password", txtPassword.Text);
int result = (int)cmd.ExecuteScalar();
if(result.Equals(1))
{
//successful login
}
else
{
//login failed
}
you should'nt be creating Connection and Command object everywhere, you can create class wrapping all these db-details and exposing functions accepting only querystring and parameters as arguments and returning dataset or scalar result, something like:
public DataTable GetSelectQueryResult(string query, OleDbParameter[] parameters)
{
var con = GetConnection();
//rest of the logic
}
replace this:
for (int i = 0; i < ds.Tables["UserProfile"].Rows.Count; i++)
{
if (ds.Tables["UserProfile"].Rows[i]["Email"].ToString() == email && ds.Tables["UserProfile"].Rows[i]["[Password]"].ToString() == pass)
{
checkPoint = 1;
}
else
{
checkPoint = 0;
}
}
with:
checkPoint = ds.Tables["UserProfile"].Rows.Count>0 ? 1 : 0;

change password in asp.net,c#,ms-access database

i am desiging a change password screen in asp.net,c#,MS-access database
i m having 4 fields
userid,
oldpassword,
newpassword
confirm password
NOW I M NOT GETTING RESULT THE COUNT RETURNS 0 I HAVE UPDATED MY CODE
my code is as follows
try
{
OleDbConnection myCon = new OleDbConnection(ConfigurationManager.ConnectionStrings["vhgroupconnection"]
.ConnectionString);
myCon.Open();
string userid = txtuserid.Text;
string oldpass = txtoldpass.Text;
string newPass = txtnewpass.Text;
string conPass = txtconfirmpass.Text;
string q = "select user_id,passwd from register where user_id = #userid and passwd = #oldpass";
OleDbCommand cmd = new OleDbCommand(q, myCon);
cmd.Parameters.AddWithValue("#userid", txtuserid.Text);
cmd.Parameters.AddWithValue("#oldpass", txtoldpass.Text);
OleDbDataReader re = cmd.ExecuteReader();
re.Read();
if (re["user_id"].ToString() != String.Empty && re["passwd"].ToString() != String.Empty)
{
if (newPass.Trim() != conPass.Trim())
{
lblmsg.Text = "New Password and old password does not match";
}
else
{
q = "UPDATE register SET passwd = #newPass WHERE user_id =#userid";
cmd = new OleDbCommand(q, myCon);
cmd.Parameters.AddWithValue("#userid", txtuserid.Text);
cmd.Parameters.AddWithValue("#newPasss", txtnewpass.Text);
int count = cmd.ExecuteNonQuery();
if (count > 0)
{
lblmsg.Text = "Password changed successfully";
}
else
{
lblmsg.Text = "password not changed";
}
}
}
}
catch(Exception ex)
{
throw ex;
}
plz help me to solve the error
You're getting the error, No constructor is defined, because you can't directly instantiate this object. As stated on MSDN:
To create an OleDbDataReader, you must call the ExecuteReader method
of the OleDbCommand object, instead of directly using a constructor.
Essentially, you'd do something like the following after creating your connection and specifying your query:
OleDbDataReader re = cmd.ExecuteReader();

Object reference not set to an instance of an object ERROR

I have few textboxes whose values are to be inserted into SQl table on Submit button click. But it gives me "Object reference not set to an instance of an object" Exception. Below is the code I have written for this. Please do help me in this.
contact_new.aspx.cs
protected void btnSubmit_Click(object sender, EventArgs e)
{
DateTime dtime;
dtime = DateTime.Now;
string ocode = offercode.Text;
string firstname = firstnamepreapp.Text;
string lastname = lastnamepreapp.Text;
string email = emailpreapp.Text;
string phoneno = phonepreapp.Text;
string timetocall = besttimepreapp.SelectedItem.Value;
string time = dtime.ToString();
//Insert the data into autoprequal table
<--- GIVES ME AN ERROR ON THIS LINE --->
Insert.insertINTOautoprequal(ocode, time, firstname, lastname, email, phoneno, timetocall);
}
Insert.cs (App_code class)
namespace InsertDataAccess
{
public class Insert
{
public Insert()
{
//
// TODO: Add constructor logic here
//
}
public static bool insertINTOautoprequal(string code, string time, string first, string last, string email, string phoneno, string timetocall)
{
bool success = false;
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connstring"].ConnectionString);
conn.Open();
string query = "Insert INTO autoprequal(offercode, timeofday, firstname, lastname, emailID, phone, besttimetocall) Values(#offercode, #time, #first, #last, #email, #phoneno, #timetocall);";
SqlCommand cmd = new SqlCommand(query, conn);
try
{
cmd.Parameters.AddWithValue("#offercode", code);
cmd.Parameters.AddWithValue("#time", time);
cmd.Parameters.AddWithValue("#first", first);
cmd.Parameters.AddWithValue("#last", last);
cmd.Parameters.AddWithValue("#email", email);
cmd.Parameters.AddWithValue("#phoneno", phoneno);
cmd.Parameters.AddWithValue("#timetocall", timetocall);
if (cmd.ExecuteNonQuery() == 1) success = true;
else success = false;
return success;
}
catch
{
throw;
}
finally
{
conn.Close();
}
}
}
}
Step through the code, as the error is most likely bubbling up from the SQL insert routine. I woulud guess the connection string is not being pulled from the configuration file, but without stepping through that is a wild guess. I would take time to learn how to debug in Visual Studio, as it will help you easily spot what cannot be a problem so you can focus on what is likely to be the problem.

The distinguished name contains invalid syntax error

I'm trying using LDAP to authenticate user, but I have a problem with LDAP.
This is my code:
string hostOrDomainName = "MrHand-PC";
string targetOu = "cn=Huy Pham,ou=people,dc=example,dc=com";
// create a search filter to find all objects
string ldapSearchFilter = "uid=pdhuy";
// establish a connection to the directory
LdapConnection connection = new LdapConnection(hostOrDomainName);
Console.WriteLine("\r\nPerforming a simple search ...");
SearchRequest searchRequest = new SearchRequest(targetOu, ldapSearchFilter,
System.DirectoryServices.Protocols.SearchScope.OneLevel, null);
// cast the returned directory response as a SearchResponse object
SearchResponse searchResponse =
(SearchResponse)connection.SendRequest(searchRequest);
The last line throws an exception: The distinguished name contains invalid syntax.
Can anyone help my solve this problem?
To authenticate against LDAP, you can try the following (domain, username and password are arguments):
bool IsAuthenticated = false;
string domainAndUsername = domain + #"\" + username;
string dirContext = GetAuthenticatingDirectory(domain);
using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + dirContext, domainAndUsername, password))
{
try
{
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (result != null)
{
IsAuthenticated = true;
}
}
catch (Exception e)
{
//handle appropriately according to your requirements
}
}
return IsAuthenticated;
where GetAuthenticatingDirectory() is defined as
private string GetAuthenticatingDirectory(string domain)
{
string authenticatingDirectory = string.Empty;
string dotComDomain = domain + #".com";
// Connect to RootDSE
using (DirectoryEntry RootDSE = new DirectoryEntry("LDAP://rootDSE"))
{
// Retrieve the Configuration Naming Context from RootDSE
string configNC = RootDSE.Properties["configurationNamingContext"].Value.ToString();
// Connect to the Configuration Naming Context
using (DirectoryEntry configSearchRoot = new DirectoryEntry("LDAP://" + configNC))
{
// Search for all partitions where the NetBIOSName is set.
using (DirectorySearcher configSearch = new DirectorySearcher(configSearchRoot))
{
configSearch.Filter = ("(NETBIOSName=*)");
// Configure search to return dnsroot and ncname attributes
configSearch.PropertiesToLoad.Add("dnsroot");
configSearch.PropertiesToLoad.Add("ncname");
using (SearchResultCollection forestPartitionList = configSearch.FindAll())
{
// Loop through each returned domain in the result collection
foreach (SearchResult domainPartition in forestPartitionList)
{
// domainName like "domain.com". ncName like "DC=domain,DC=com"
string domainName = domainPartition.Properties["dnsroot"][0].ToString();
string ncName = domainPartition.Properties["ncname"][0].ToString();
if (dotComDomain.Equals(domainName, StringComparison.OrdinalIgnoreCase))
{
authenticatingDirectory = ncName;
break;
}
}
}
}
}
}
return authenticatingDirectory;
}

Resources