i don't input any accounts but in still logs in - c#

private void btnLogin_Click(object sender, EventArgs e)
{
{
Connections.con.Open();
string login = "SELECT ID, Username, [Password] FROM Employee";
OleDbCommand command = new OleDbCommand(login, Connections.con);
command.Connection = Connections.con;
command.Parameters.AddWithValue("#?", txtLUser.Text.ToString());
command.Parameters.AddWithValue("#?", txtLPass.Text.ToString());
OleDbDataReader reader = command.ExecuteReader();
int count = 0;
while (reader.Read())
{
count = count + 1;
break;
}
if (count == 1)
{
MessageBox.Show("Login Successful.");
this.Close();
}
else
{
MessageBox.Show("Please enter a valid Username or Password");
}
Connections.con.Dispose();
Connections.con.Close();
MessageBox.Show("Thank you for using this Simple Login/Registration Form.");
}
It always Logs in whenever i click Login Button and i haven't even typed anything in the user/pass textbox and there is no blank registered in my access database
any advice?

You're not actually checking the username and password. Look at the database query:
"SELECT ID, Username, [Password] FROM Employee"
This will select every record from the Employee table. Then you check those records:
while (reader.Read())
{
count = count + 1;
break;
}
if (count == 1)
{
MessageBox.Show("Login Successful.");
this.Close();
}
According to this logic, as long as any record exists in the Employee table, the login is successful.
You probably want to check only for records which match the supplied credentials. Something like this:
"SELECT [ID], [Username], [Password] FROM [Employee] WHERE [Username] = #? AND [Password] = #?"
(I'm guessing on the parameter syntax based on how you add the parameters, since I'm not familiar with MS Access syntax. But hopefully you get the idea.)
Also, and this is important, you appear to be storing user passwords in plain text. This is an extremely terrible thing to do. Please hash passwords appropriately so that they can't be read as plain text.
Additionally, you appear to be using a shared connection object:
Connections.con.Open();
This is going to cause a whole host of problems. It's a lot simpler and more stable to create the connection object within the scope of the method which uses it. Basically, a connection object should be created, used, and disposed in a very tight scope and should not leak outside of that scope.

You missed where attribute
string login = "SELECT ID, Username, [Password] FROM Employee where Username=#? and [Password]= #? ";

Related

ADODB.Command, finding rows that satisfy a condition

The work is done in C#, with an Access database to connect to.
Currently, I want to retrieve the number of accounts from the table ACCOUNT_T that satisfy the user's inputted credentials (username, email, password).
The table has 3 attributes: acc_username VARCHAR(30), acc_email VARCHAR(50), and acc_password VARCHAR(30)
The table has only one entree: 'Tester', 'test#mail.com', 'TestPass'
I want to check number of rows/entrees in the database that match the user's inputted credentials (every account is unique, so assume no duplicates), and used the code shown below.
//Checks whether the user has entered the correct credentials
//If correct info is entered, redirect user to the Main Menu page
private void Login_Login_Button_Click(object sender, EventArgs e)
{
//Open connection
ADODB.Connection connection = new ADODB.Connection();
connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=main_db;Jet OLEDB:Engine Type=5;";
connection.Open();
//Create command and object
ADODB.Command command = new ADODB.Command();
object rowsAffected;
//Setting up command and parameters
command.ActiveConnection = connection;
command.CommandText = "SELECT COUNT(*) FROM ACCOUNT_T WHERE acc_username = \'#USERNAME\' AND acc_email = \'#EMAIL\' AND acc_password = \'#PASSWORD\'";
command.Parameters.Append(command.CreateParameter("#USERNAME", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Username_TextBox.Text));
command.Parameters.Append(command.CreateParameter("#EMAIL", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Email_TextBox.Text));
command.Parameters.Append(command.CreateParameter("#PASSWORD", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Password_TextBox.Text));
//Execute command and store into RecordSet
ADODB.Recordset recordSet = command.Execute(out rowsAffected);
//Output A
MessageBox.Show(recordSet.RecordCount.ToString());
//Output B
MessageBox.Show(((int)rowsAffected).ToString());
connection.Close();
if ((int)rowsAffected == 1)
{
MainMenu_User_Label.Text = "Logged In As: " + Login_Username_TextBox.Text;
SetupPanel(MainMenu_Panel);
}
else
{
MessageBox.Show("Wrong Credentials.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
However, as marked above, Output A gives the value -1 for "recordSet.RecordCount.ToString()" and Output B gives 0 for "((int)rowsAffected).ToString()". The output is the same regardless of what the user input is, right or wrong. (Meaning that the same output is given whether the user's inputted data is already in the database or not)
Is there something wrong with the code?
private string ConnectionString {get { return "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=main_db;Jet OLEDB:Engine Type=5;"; } };
private void Login_Login_Button_Click(object sender, EventArgs e)
{
string sql = "
SELECT COUNT(*)
FROM ACCOUNT_T
WHERE acc_username = ? AND acc_email = ? AND acc_password = ?";
int rowsAffected = 0;
using (var connection = new OleDbConnection(ConnectionString))
using (var command = new OleDbCommand(sql, connection))
{
// Use OleDbType enum values to match database column types and lengths.
// I have to guess, but you can get exact values from your database.
// Also, OleDb uses positional parameters, rather than names.
// You have to add the parameters in the order they appear in the query string.
command.Parameters.Add("acc_username", OleDbType.VarChar, 200).Value = Login_Username_TextBox.Text;
command.Parameters.Add("acc_email", OleDbType.VarChar, 200).Value = Login_Email_TextBox.Text;
command.Parameters.Add("acc_password", OleDbType.VarChar, 200).Value = Login_Password_TextBox.Text;
cn.Open();
rowsAffected = (int)command.ExecuteScalar();
} //leaving the using block will guarantee the connection is closed, even if an exception is thrown
MessageBox.Show(rowsAffected.ToString());
if (rowsAffected == 1)
{
MainMenu_User_Label.Text = "Logged In As: " + Login_Username_TextBox.Text;
SetupPanel(MainMenu_Panel);
}
else
{
MessageBox.Show("Wrong Credentials.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
While I'm here, I also need to mention this is exceptionally poor password handling. It is NEVER okay to store a password like this, even for a simple personal or testing app. This is one of those things that's too important to do wrong, even in learning code. The problem is people tend to re-use passwords, so a breach for your simple testing app might also provide an attacker with credentials which grant access to something far more important. Just don't do it.
Instead, you must create a unique salt (or nonce) value for each user. When a user sets the password, you prepend the salt to the new password. Then you create a cryptographic hash of the combined value using an algorithm like BCrypt and prepend the salt to final value again. Now you only store this altered information. Never store the actual password. When someone tries to login, you retrieve the stored information, extract the salt, and use the same procedure on the attempted password. Now you can compare the hash values rather than the raw passwords.

Invalid Object error while trying to perform a SQL query

I'm trying to make my first steps in databases used with WPF. The problem is that once I start the application, I get an error saying
Invalid Object - "tblUser"
where tblUser is the name of a table.
I made sure that table name is correct, tried creating another table to see whether it changes anything. All the permissions are granted to manipulate the table.
private void Submit_OnClick(object sender, RoutedEventArgs e)
{
SqlConnection sqlCon = new SqlConnection(#"Server=localhost\SQLEXPRESS;Database=master;Trusted_Connection=True;");
try
{
if (sqlCon.State == ConnectionState.Closed)
sqlCon.Open();
String query = "SELECT COUNT(1) FROM tblUser WHERE Username = #Username AND Password = #Password";
SqlCommand sqlCmd = new SqlCommand(query, sqlCon);
sqlCmd.Parameters.AddWithValue("#Username",txtUsername.Text);
sqlCmd.Parameters.AddWithValue("#Password", txtPassword.Text);
int count = Convert.ToInt32(sqlCmd.ExecuteScalar());
if (count == 1)
{
MainWindow dashboard = new MainWindow();
dashboard.Show();
this.Close();
}
else
{
MessageBox.Show("Username or password does not exist");
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
finally
{
sqlCon.Close();
}
}
First I create a connection to the database. Next step is I would like to check whether connection is closed, if it is I'm opening it. Then it looks like something went wrong with the SQL query because it seems not to recognise tblUser and sees it as an invalid one.
tblUser is certainly not in the master database. The asterisks are not part of SQL. I am surprised that the error message doesn't complain about that at first

asp.net MVC. How ho make redirect to .aspx page depending on user privilege [duplicate]

This question already has answers here:
ASP.NET Identity 2.0 check if current user is in role IsInRole
(4 answers)
Unable to configure AspNet.Identity using PostgreSQL
(2 answers)
Closed 4 years ago.
I have a little web application on asp.net MVC + PostgreSQL.
I have login page, where people enters their login/password. Right now I only have 1 user - admin. If login and pass are correct, I enter to mainForm.aspx page.
But I need to make a couple of users: user and director. When user logs in, he needs to be redirected to user.aspx page, when director logs in, he needs to be redirected to director.aspx page. All cases need to make login/pass check from PostgreSQL database.
How do I do that?
Here's my Login.aspx.cs code with only 1 user:
namespace User1.WebApp
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.None;
}
protected void Button_Login_Click(object sender, EventArgs e)
{
var connString = "Host=localhost;Username=postgres;Password=123;Database=postgres";
using (var conn = new NpgsqlConnection(connString))
{
conn.Open();
string checkuser = "select count(*) from Login where name= '" + TextBoxUserName.Text + "' ";
NpgsqlCommand com = new NpgsqlCommand(checkuser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
if (temp == 1)
{
string checkPasswordQuery = "select password from Login where name= '" + TextBoxUserName.Text + "'";
NpgsqlCommand passCom = new NpgsqlCommand(checkPasswordQuery, conn);
string password = passCom.ExecuteScalar().ToString().Replace(" ", "");
if (password == TextBoxPassword.Text)
{
Session["New"] = TextBoxUserName.Text;
Response.Redirect("MainForm.aspx");
}
else
{
Response.Write("Password is NOT correct !");
}
}
else
{
Response.Write("Username is NOT correct !");
}
}
}
}
}
You could do this just before
Response.Redirect("MainForm.aspx");
The way you can do it is to check the type of user and act accordingly.
Few comments regarding the current code:
Set the connection string in web.config and read it from there instead of having it hard coded in your code e.g. here.
The way you create your SQL statements makes your application vulnerable to SQL injection, one of the most common ways for someone to hack a site. Instead of doing this, prefer parameterized queries.
You make two round trips to the database, to check if the user exists and then to get her password. What about if you want to fetch one more information like the user type ? You would make one more round trip. You could eliminate all this to one round trip, provided that you can identify your users based on something unique like the username. Just fetch all the data for a specific username.
Let that someone can get access to the Login table of your database. How exposed are your application users ? 100%. All the passwords there are in clear text ! You should avoid this in any way. A naive solution is to hash the password and each time someone try to login to hash the password that the user provides and compare with the hash you have stored. A more professional approach of storing passwords is described at The right way to implement password hashing using PBKDF2 and C#. Look also for similar articles like the mentioned one. Security should be of paramount importance for your applications.
Are you able to store an extra field in the database to specify whether a login is Admin, User or Director?
You could use an Enum for this:
enum LoginRole
{
User = 0,
Director = 1,
Admin = 2
}
This Enum could be stored as an integer field in your Login table, called "role" or similar. You could then redirect to the appropriate page depending on this role.
I have updated your code with an example:
var connString = "Host=localhost;Username=postgres;Password=123;Database=postgres";
using (var conn = new NpgsqlConnection(connString))
{
conn.Open();
string checkuser = "select password, role from Login where name=#username";
using (var com = new NpgsqlCommand(checkuser, conn))
{
com.Parameters.AddWithValue("#username", TextBoxUserName.Text);
using (var reader = com.ExecuteReader())
{
if (reader.Read())
{
string password = reader["password"].ToString();
LoginRole role = (LoginRole)reader["role"];
if (password == TextBoxPassword.Text)
{
Session["New"] = TextBoxUserName.Text;
switch (role)
{
case LoginRole.User:
Response.Redirect("user.aspx");
break;
case LoginRole.Admin:
Response.Redirect("MainForm.aspx");
break;
case LoginRole.Director:
Response.Redirect("director.aspx");
break;
}
}
else
Response.Write("Password is NOT correct !");
}
else
Response.Write("Username is NOT correct !");
}
}
}
Please note, using parameters in your queries in this case would be preferred, as appending the string from the textbox straight into the SQL query is vulnerable to SQL injection.
You were also making two calls to the database per login - one to check the username and another to check the password. I have addressed this in my above sample to only make one call to the database.

Login Button to read sql database and confirm values entered into textboxes with values in said sql database throws error

I am a noob attempting to create a login page where the user enters their username and password that is already in the sqldatabase connected to the textboxes/button/form. The below code is my best attempt at doing so, but upon debugging it throws catch despite the textbox values entered being registered in the sql database. If any additional information is needed please ask.
private bool compareStoD(string teststring1, string teststring2)
{
return String.Compare(teststring1, teststring2, true, System.Globalization.CultureInfo.InvariantCulture) == 0 ? true : false;
}
private void button1_Click_1(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(#"Data Source=DESKTOP-P3JSE1C;Initial Catalog=logins;Integrated Security=True");
connection.Open();
SqlCommand checker = new SqlCommand("SELECT COUNT (*) from users WHERE username='" + textBox1.Text + "'AND pssword='" + textBox3.Text + "'", connection);
SqlDataReader reader = checker.ExecuteReader();
string usernameText = textBox1.Text;
string psswordText = textBox3.Text;
while (reader.Read())
{
if (this.compareStoD(reader["username"].ToString(), textBox1.Text) && // replace textbox1.Text with text string usernameText
this.compareStoD(reader["pssword"].ToString(), textBox3.Text)) //replace textbox3.Text with text string psswordText
{
main wen = new main();
wen.Show();
}
}
reader.Close();
connection.Close();
}
catch
{
MessageBox.Show("Incorrect password or username.");
}
}
It is most likely throwing an exception because your query is asking for the count but then you are reading columns username and password which do not exist in the reader. This is your query:
SELECT COUNT (*)
Change that to this:
SELECT username, password ...
Also, unless you want every savvy user to access your application, use SqlParameter to avoid SQL Injection
Another Suggestion
I am not sure what main is, my assumption it is some window, but I would not show it where you are showing right now. Try to close the reader as soon as possible and then show the window if the user is authenticated like this.
bool userIsAuthenticated = false;
if (reader.Read())
{
// if a row was returned, it must be the row for the user you queried
userIsAuthenticated = true;
}
reader.Close();
connection.Close();
// Now that the reader is closed, you can show the window so the reader does not stay
// open during the duration of the main window
if (userIsAuthenticated)
{
main wen = new main();
wen.Show();
}
Select count returns the count not the row, if you want the row itself change to select username, password instead of select count(*) . See this link
There is over work being done by your code. You are querying the database by comparing the username and password values from UI to the values in the table. And once and if values are retrieved from the database you are again comparing value from UI to the values coming from the database. This is unnecessary.
The query will return the values only if values match in the database so you don't need to compare them again. So method compareStoD is not required at all.
The button1_Click can be changed as following to make it simpler.
private void button1_Click_1(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(#"Data Source=DESKTOP-P3JSE1C;Initial Catalog=logins;Integrated Security=True");
connection.Open();
SqlCommand checker = new SqlCommand("SELECT COUNT (*) from users WHERE username=#userName AND pssword = #password", connection);
checker.Parameters.Add(new SqlParameter("#userName", textBox1.Text));
checker.Parameters.Add(new SqlParameter("#password", textBox3.Text));
var count = Convert.ToInt32(checker.ExecuteScalar());
connection.Close();
if(count > 0)
{
main wen = new main();
wen.Show();
}
else
{
MessageBox.Show("Incorrect password or username.");
}
}
catch
{
MessageBox.Show("Incorrect password or username.");
}
}
Also one good practice while supplying values from Textbox, you should use Textbox.Text.Trim() which helps in eliminating the spaces at the beginning and end. These spaces can create a problem in later stage.

Calling MySql Function in C# for validating username and password

Development Environment:
Microsoft Visual Studio 2010 Ultimate,
C#,
MySql
Hi, I've create a function in mysql which accept 3 parameter to validate username and password.
DELIMITER $$
USE `generalledger`$$
DROP FUNCTION IF EXISTS `fLogin_Check`$$
CREATE DEFINER=`root`#`localhost`
FUNCTION `fLogin_Check`
(mUserName VARCHAR(50),mUserPass VARCHAR(40),mUserKey VARCHAR(40)) RETURNS INT
BEGIN
DECLARE mCount INT;
SELECT COUNT(*) INTO mCount FROM userMaster
WHERE userName = mUserName
AND AES_DECRYPT(userPass, mUserKey) = UPPER( mUserPass);
IF mCount > 0 THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END$$
DELIMITER ;
As you can see I am using AES_DECRYPT function of MySql to check password, because I've use AES_ENCRYPT for password when INSERT username and password to mysql table.
Now I need to call the function fLogin_Check in C#, which I am doing by using following class method:
public int CheckUser(string mUserName, string mPass, string mKey)
{
oCn = da.GetConnection();
int res;
if (oCn == null)
{
oCn.Open();
}
sInsProcName = "fLogin_Check";
insertcommand = new MySqlCommand(sInsProcName, oCn);
insertcommand.CommandType = CommandType.StoredProcedure;
insertcommand.Parameters.Add(new MySqlParameter("mRes", MySqlDbType.Int32, 0));
insertcommand.Parameters["mRes"].Direction = ParameterDirection.ReturnValue;
insertcommand.Parameters.Add("mUserName", MySqlDbType.VarChar, 50, mUserName);
insertcommand.Parameters.Add("mUserPass", MySqlDbType.VarChar, 40, mPass);
insertcommand.Parameters.Add("mUserKey", MySqlDbType.VarChar, 40);
insertcommand.Parameters["mUserKey"].Value = mKey;
res = insertcommand.ExecuteNonQuery();
//res = int.Parse(insertcommand.Parameters["mRes"].Value.ToString());
return (res);
oCn.Close();
}
oCn is the connection abject which uses to call GetConnection method define in my DAL class and da is the object created from DAL class, use to opening and closing database connection.
Using following Global class I am storing username and password after user enter them, and then try to validating with fLogic_Check Mysql function:
public static class Globals
{
public static string userName;
public static string userPass;
public const string sKey = "AHMEDFINANCEICMAP1122";
}
sKey is the key I use to encrypt password when insert username. Now I am trying to use it in C# from Login Form when user enter Username and Password and click login button with following code:
private void btnCheck_Click(object sender, EventArgs e)
{
Globals.userName = txtUser.Text.ToString();
Globals.userPass = txtPass.Text.ToString();
if (fUser.CheckUser(Globals.userName, Globals.userPass, Globals.sKey) == 0)
{
MessageBox.Show("Invalid Username or Password.");
}
else
{
MessageBox.Show("Login Successfull");
}
}
It always return 0, means failed login. I've checked the Mysql function in MySql GUI and it works fine:
SELECT fLogin_Check("AHMED","AHMED1981","AHMEDFINANCEICMAP1122") FROM userMaster
which successfully return 1, however it fails when calling in C#. I've also tried to access Parameter which I've comment out after failure...What am I doing wrong?
Ahmed
Code has multiple issues.
First and most important: it's better to store passwords with hash functions instead of reversible cryptographyc methods, otherwise you loose the benefits of encrypting them. I'm not going to explain this more in deep because it's been widely discussed, even here on stackoverflow. Do some research.
Second, "ExecuteNonQuery" won't return you the query output. It is used with INSERT's and UPDATE queries. You need to use "ExecuteReader" and then use the object returned to extract the row data.
Finally, your "oCn.Close();" will never be executed since there is a "return" before that line (obiviously that's not the problem but hey!).
Now, since you need the first value of the first row, there is a better function that suits your needs: ExecuteScalar. You can find more information about it on MSDN.

Categories

Resources