Calling MySql Function in C# for validating username and password - c#

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.

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.

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.

i don't input any accounts but in still logs in

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]= #? ";

Login error in ASP.NET using MySQL

I try to create login function in ASP.NET using MySQL database and enterprise library.
First I create a database and store procedures.
spselectusertype sp
DELIMITER //
Create procedure spselectusertype(
UName varchar(50),
Pasword varchar(50)
)
BEGIN
Select UserType_ID FROM login
WHERE UName = UName AND UPasword = Pasword;
end;
splogin sp
create procedure splogin()
BEGIN
SELECT *
FROM login
WHERE UName = UName and UPasword=UPasword;
END
Then I create a class library and add these functions:
Database db = DatabaseFactory.CreateDatabase("abc");
public int UserType(string UName, string UPasword)
{
return Convert.ToInt32(db.ExecuteScalar("spselectusertype", new object[] {
UName, UPasword }).ToString());
}
public int SignInUsers(string UName, string Pasword)
{
return Convert.ToInt32(db.ExecuteScalar("splogin", new object[] { UName, Pasword }));
}
Login button code:
MySqlConnection conn = new
MySqlConnection(ConfigurationManager.ConnectionStrings["abc"].ConnectionString);
ClassLibrary1.Class1 LOGIN = new ClassLibrary1.Class1();
protected void Button1_Click1(object sender, EventArgs e)
{
//UsertpeTID sve in session
int users = LOGIN.UserType(TextBox1.Text, TextBox2.Text);
//UserID Save in Session
int user_id = Convert.ToInt16(LOGIN.SignInUsers(TextBox1.Text, TextBox2.Text));
Session["UserID"] = user_id;
if (Session["UserID"] != null)
{
user_id = Convert.ToInt32(Session["UserID"].ToString());
}
if (users == 1)
{
Session["Login2"] = TextBox1.Text;
Session["Login3"] = TextBox2.Text;
Session["UserTypeID"] = users;
Response.Redirect("alldocuments.aspx");
}
else if (users == 2)
{
Session["Login2"] = TextBox1.Text;
Session["Login3"] = TextBox2.Text;
Session["UserTypeID"] = users;
Response.Redirect("Home.aspx");
Label3.Visible = true;
Label3.Text = "Incorrect User Name or Password";
}
}
}
}
But when I debug my project and enter username and password, it shows me following error
Parameter discovery is not supported for connections using GenericDatabase. You must specify the parameters explicitly, or configure the connection to use a type deriving from Database that supports parameter discovery.
on this line:
return Convert.ToInt32(db.ExecuteScalar("spselectusertype", new object[] {
UserName, UserPassword }).ToString());
So where is the mistake?
PLEASE, if you're going to develop an ASP.NET website with login, DO NOT ROLL YOUR OWN SYSTEM (unless you know what you're doing).
What I see from your system, you have barely any seurity of any kind, including role management, folder access management, password hashing and password resets. If you use an ASP.NET membership system (just start a new asp.net web forms application using Visual Studio), you get all that, plus an easy way to manage it all through a local web portal, including the option to select your own database type through the web configuration tool.
Assuming, of course, you have the option to use this, I would start with using this system, because it's a really good basis to start from.
I realize this doesn't answer your question directly, but I still feel like I should suggest it.
Error involves in the
Database db = DatabaseFactory.CreateDatabase("abc");
Since It is only supposed to support SQLServers
Reference
Reference Link
Please consider other ways to connect with the database.

How to check if the username existed in the User table of the database or not?

I am trying to develop a simple user management system for the admin of the web application. I am using ASP.NET Wizard Control for this task.
I just put a TextBox for writing the username and when the admin clicks on the Next button, the system should check if the username existed in the database or not. If it is existed, the system should display his information in a placeholder for the admin.
I am struggling with this task. I did the following in the code-behind:
//For checking the user
if (Request.QueryString["Username"] != null)
{
String strUserName = Request.QueryString["Username"];
//Check userName Here
String strReturnStatus = "false";
if (CheckUsername(Request.QueryString["Username"]) == true)
{
strReturnStatus = "true";
}
Response.Clear();
Response.Write(strReturnStatus);
Response.End();
}
Now, I think to create a second method called CheckUsername which I don't know what I should put it inside it:
private bool CheckUsername(string p)
{
//throw new NotImplementedException();
}
It may seem that this question is simple or stupid, but I am a new developer and I could not be able to find a simple resource that could help me in this issue particularly.
I believe the following method is what you're after:
private bool CheckUsername(string username)
{
string connString = "";
string cmdText = "SELECT COUNT(*) FROM Users WHERE Username = #username";
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open(); // Open DB connection.
using(SqlCommand cmd = new SqlCommand(cmdText, conn))
{
cmd.Parameters.AddWithValue("#username", username)); // Add the SQL parameter.
int count = (int)cmd.ExecuteScalar();
// True (> 0) when the username exists, false (= 0) when the username does not exist.
return (count > 0);
}
}
}
You can fill in the blanks (e.g specify a connection string connString and modify cmdText). The SQL query I specified in cmdText is under the assumption of a typical user management system where you have common table names and columns; Users (table) and Username (column). It's hard to justify as you haven't specified the structure. Modify it to suit your applications needs.
The method of counting how many records exist is quite common in most cases. I frequently use that method of checking/validating things as I see fit.
Further information about the code (classes) I used in my example above:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.aspx
I also advise you read about data access (not that link). I'll leave you to that.
I adjust some point in your code:
if (!string.IsNullOrEmpty(Request.QueryString["Username"]))
{
---
---
if (CheckUsername(Request.QueryString["Username"]))
{
---
---
}
Refer to this link as tutorial for your task: http://www.codeproject.com/KB/database/sql_in_csharp.aspx

Categories

Resources