Create Login and Validating Users in Asp.net - c#

I have created login page and i want to verify the users if they have access or not. I have done most of the work but just need couple of things here:
1) if user is validated, then i want to redirect to Home.aspx page
2) After the user is validated i want to be able to save the user id in a session so they don't have to login every time if they are redirected to another page.
Basically, once they login successfully they should be able to navigate other pages in the application. thanks.
here is the code behind:
protected void ValidateUser3(object sender, EventArgs e)
{
int userId = 0;
string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("Validate_User"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Username", txtUID.Text.Trim());
cmd.Parameters.AddWithValue("#Password", txtPWD.Text.Trim());
cmd.Connection = con;
con.Open();
userId = Convert.ToInt32(cmd.ExecuteScalar());
con.Close();
}
switch (userId)
{
case -1:
logLbl.Text = "Username and/or password is incorrect.";
break;
case -2:
logLbl.Text = "Account has not been activated.";
break;
}
}
}
Here is my stored proc:
ALTER PROCEDURE [dbo].[Validate_User]
#Username NVARCHAR(20),
#Password NVARCHAR(20)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #UserId INT, #LastLoginDate DATETIME
SELECT #UserId = UserId, #LastLoginDate = LastLoginDate
FROM myTable WHERE Username = #Username AND [Password] = #Password
IF #UserId IS NOT NULL
BEGIN
IF NOT EXISTS(SELECT UserId FROM [Main].[UserActivation] WHERE UserId = #UserId)
BEGIN
UPDATE myTable.[dbo].[UserProfile]
SET LastLoginDate = GETDATE()
WHERE UserId = #UserId
SELECT #UserId [UserId] -- User Valid
END
ELSE
BEGIN
SELECT -2 -- User not activated.
END
END
ELSE
BEGIN
SELECT -1 -- User invalid.
END
END

First up I'd look at tightening that security. Don't save passwords in your database, not even hashed ones. And follow krillgar's advice in the comments to your question :)
What you want to do with each user account is create a unique salt code - a random value, with a minimum of 8 in length (the more the better naturally): See here for creating a salt code. You want to save that in your database in the users table. So you'll have something like a table structure like: UserId, UserName, PassString, SaltCode, Active
Pick a Hashing method; MD5 or SHA1 are typical examples. When the password is created you take the username, merge it into the password, add your salt code then Hash it. This will create a unique string - that's what you save into your database in the PassString field.
So when someone logs in you take the username and password, look up the user record, get the salt code. Hash it all together then compare the two hashed strings.
Check out this section on Stack Overflow: How to hash a password
This makes your passwords irreversible without all segments of the data in other words; the password the user enters to login is the missing key to the puzzle. If someone is somehow able to get the data out of your table they'll have to a ton of work to crack a user's account.
so to now answer your actual question :)
Just like you have with your Stored Procedure, when the user is successfully matched return a value such as 1. I would suggest you keep your return codes and userid value separate so there's less ambiguity in your code. You got a choice with your SP, you can either return the userid back in with the return code on a Select statement ie Select 1, #UserId or you can use an OUTPUT parameter, here's a fairly decent example: Using stored procedure output parameters in C# (I'd favour the latter).
Now working with what you've got (and by that I mean, not telling you to go off an use System.IdentityModel.Service, UserPrinciple and the likes)...
Once that successful login has been acknowledged by your SP, use a session variable in the following manner, Session variables are kept server side so unless your server is compromised you'll be ok:
Session["UserId"] = userId;
Response.Redirect("Home.aspx");
Now on pages like Home.aspx you just need some code along the lines of;
bool userLoggedIn = false;
if (Session["User"] != null) //check the session variable is actually valid
{
if (!String.IsNullOrEmpty(Session["User"]))
{
userLoggedIn = true;
}
}
if (!userLoggedIn)
{
Response.Redirect("login.aspx");
}
Though it would be a lot wiser to create a class in the App_Code folder to handle this, last thing you want is duplicated code all over your site.
The issue you'll run into is giving user's rights. I'm not clear from your question but I got the impression you wanted a binary login, ie: if a user is authenticated they have access, plain and simple. If you're after segmented security; controlling what each user can or cannot do then you need to be looking down the route of Claims based security, here's an example of that to get you thinking: http://www.codeproject.com/Articles/2905/Role-based-Security-with-Forms-Authentication
I hope that helps and wasn't too long a read :)

Related

ASP.NET Core 2 all users password reset as admin

I'm looking for a possibility to reset the password for all users in a database. Is it anyhow possible? All I have found so far, was about enabling password reset for the user himself, but it's not that I need.
I need to force old user to recreate a password for our app. Maybe there are some better solutions?
If you need to do a global password reset, what you should do is create a function that generates random cryptographically secure passwords and simply change each user's password to those random ones (not just one, generate a password for each user). This essentially causes a global lockout, since no user will then be able to login, since they won't know this password.
Afterwards, you should send an mass email indicating that passwords have been reset and directing users to your password reset page. They'll essentially just act as if they've forgotten their password, and go through the normal process of submitting their email, clicking the link with a token in the email that gets sent, and then setting a new password.
You should also update your sign in failure message temporarily to indicate that all users must reset their password, so if someone misses the email, they'll know why their password isn't working and what they need to do to fix it.
If you are trying to reset the password to something specific for all users, then you'd need to update the asnetUsers table with a hashed password and password salt for the new password.
From experience, the easiest way to do do this is the change the password using the app for a specific user, grab the PasswordHash and PasswordSalt from that changed user, and then run a SQL UPDATE on all other users with the same combination.
It's not exactly secure, but it will do the job.
More or less:
-- Update User using App, and get the ID
DECLARE #Id INT = XX -- Your app userid here
DECLARE #PasswordHash NVARCHAR(MAX), #PasswordSalt NVARCHAR(MAX)
-- get the password hash and salt for the changed user
SELECT #PasswordHash = PasswordHash, #PasswordSalt = PasswordSalt
FROM aspnetUsers
WHERE Id = #Id
-- Update the other users with the same password and salt
UPDATE aspnetUsers SET
PasswordHash = #PasswordHash,
PasswordSalt = #PasswordSalt
WHERE
Id IN (---whatever you need to filter by)

Trouble creating an sql connection string

I have an example of a login page that runs off of sql in which I am trying to customize it to my server.
I'm running into issues with the sql string.
Here is the original (with my table info). This appears to be pulling the username and password from the login control with #user and #password; I think. If not what is it doing? what exactly is #user and #password?
string sql = "select count(*) from ResidentUserDatabase where users = #user and passwords = #password";
Here is where I hard coded a username and password in. This works and I was able to login just fine. Obvioulsy not useable, but confirms i am connecting to the database and pulling user info
string sql = "select count(*) from ResidentUserDatabase where users = 'user' and passwords = 'pass'";
Now, here is where i have issues (since the first version doesn't work...). I tried to bypass the #user and #password and am apparently not doing it right.
string sql = "select count(*) from ResidentUserDatabase where users = '" + LoginControl.UserName.ToString() + "' and passwords = '" + LoginControl.UserName.ToString() + "'";
I'm not really sure where to go from here, or why the example doesnt work.
thanks
The #user and #password are parameters of a "parameterized sql query". What you have created in your 3rd code sample is a real security problem. Google the term "Sql Injection attack". If you are unfamiliar with this kind of security concerns, then I would strongly urge you not to be building the login forms for your application. "Here be dragons"
You have a few things going bad for you here.
First of all, you should not concatenate strings as this leaves you open to SQL injection. Google it and you will see why.
Second, the #user and #password tokens are parameters of a SQL query. What you want to do is add parameters to whatever object you are using to execute the SQL (e.g. SqlCommand). How to do that in detail is beyond the scope of the question.
Third, your string-concatenating query is using the same field for username and password. That is why it doesn't work.

Sending authentication information to SQL Server isn't working (C#)

I already asked about a similar issue to this one but I've narrowed it down to my problem and I've been working on this for hours and unable to figure this out.
Basically, I have a visual studio wep application and I'm trying to use a login page and sql server database to validate user credentials. The user enters a string for username and password on the log-in screen which gets sent here on the code behind:
private bool ValidateUser(string userName, string passWord)
{
SqlConnection conn;
SqlCommand cmd;
string lookupPassword = null;
// Consult with your SQL Server administrator for an appropriate connection
// string to use to connect to your local SQL Server.
conn = new SqlConnection(ConfigurationManager.ConnectionStrings["databaseConnect"].ConnectionString);
conn.Open();
// Create SqlCommand to select pwd field from users table given supplied userName.
cmd = new SqlCommand("Select Password from Users where User=#userName;", conn);
cmd.Parameters.Add("#userName", System.Data.SqlDbType.VarChar, 25);
cmd.Parameters["#userName"].Value = userName;
lookupPassword = (string)cmd.ExecuteScalar();
// If no password found, return false.
if (null == lookupPassword)
{
return false;
}
private void cmdLogin_ServerClick(object sender, System.EventArgs e)
{
if (ValidateUser(txtUserName.Value,txtUserPass.Value) )
(logs in)
}
The application is connected a table in a database, which currently holds one test item, as shown here: http://i.imgur.com/YFOQYKm.jpg
However, when I enter "test" as username and "password" as password, it doesn't accept the log-in.
I tried to include only the relevant parts of my code to make it more clear for anybody trying to answer the question but here's a few comments about my problem:
-When I set if (null == lookupPassword) to "return true" instead of "return false" the application allows logins. Which means lookupPassword is still null after "lookupPassword = (string)cmd.ExecuteScalar();"
-The application works fine when I change if(ValidateUser(txtUserName.Value,txtUserPass.Value)) to if(userName=test and passWord=password). So the problem is not with the actual act of logging into the application, it just isn't finding the SQL Server credentials to be true.
-"databaseConnect" is working elsewhere on the application, so that is not the issue.
-The application is not breaking when I submit the login credentials, it is simply not accepting them as correct.
Going off that, it seems to me that the problem comes from these four lines:
cmd = new SqlCommand("Select Password from Users where User=#userName;", conn);
cmd.Parameters.Add("#userName", System.Data.SqlDbType.VarChar, 25);
cmd.Parameters["#userName"].Value = userName;
lookupPassword = (string)cmd.ExecuteScalar();
Does anybody see where the problem might be for me? I'm very new to programming so please keep the answers as simple as possible please. Thank you in advance for any help. :)
This table design is using several reserved words in SQL Server. If you cannot modify this schema, you can update your query as follows:
SELECT [Password] FROM [Users] WHERE [User] = #Username
That being said, storing passwords in plaintext is a horrible security practice. Passwords should never be stored encrypted or as plaintext, they should be hashed using a salt to help avoid rainbow tables from cracking your password. I would look into the suggestion from #Richard regarding Rfc2898DeriveBytes. You can also search Google or Bing for using salt and SHA256.

Confirm Delete with Password in ASP.NET MVC

I have a need to have my users enter their passwords when confirming a delete action. However I do not know how to compare their input to their passwords.
My algorithm is something like:
read passwordFieldText
if userpassword == passwordFieldText
{
execute delete action
}
else return "incorrect password"
I know of course that there is no way to retrieve a user's password as a variable, so how do I go about achieving this?
You don't compare their input to their password yourself. You pass their username and what they are now saying their password is into Membership.ValidateUser.
if (Membership.ValidateUser(username, password))
// Do Delete
else
// Don't do Delete
Documentation can be found at here.
You are going wrong. because if same password have two different user, then delete action is call unrelated :p . It's tooo bad
So you need
read passwordFieldText
if userid=currentuserId && userpassword == passwordFieldText
{
execute delete action
//delete action look like
delete from user where userid=currentuserId and userpassword == passwordFieldText
}
else return "incorrect password"
and how can check your password
see this samples
http://www.codeproject.com/Articles/689801/Understanding-and-Using-Simple-Membership-Provider
http://www.codeproject.com/Articles/664294/ASP-NET-MVC-Configuring-ASP-NET-MVC-4-Membership-w
Update
You can get, how to check the password mach or email mach in membership table by this link
http://www.itorian.com/2013/03/PasswordResetting.html

How to implement a password change functionality with Oracle and a .Net client?

I'm using Oracle users to authenticate username and password for a .Net application. Right now I'm working on the password change function. The database has a custom password validation, so if you try to change a users password and you provide an invalid password, Oracle returns multiple errors.
The first error is always "ORA-28003: password verification for the specified password failed", and then it rises one error for each failed validation. This is shown correctly when I try to change a user's password from the Toad client.
However, when I do this from my application, the OracleException that is raised only returns the first error, and therefore I'm not able to show the user what's invalid about the new password he provided, which is a requirement for the application. So how should I aproach this?
For starters, don't use the OpenWithNewPassword method. Not only does it have known issues with with various versions of ODP.net and the DB, but it forces you to have two different branches of code when you only need one - IIRC it doesn't work if the user's password has already expired.
Instead the basic logic works like this:
Make sure you can authenticate with the user's old account and password
If you're successful, close that connection and open a separate account that has no access other than exec privs on a ChangePassword stored procedure.
Here's the code:
protected void BtnChangePassword_Click(object sender, EventArgs e)
{
String connectionStringFormat = "Data Source={0};User Id={1};Password={2};pooling=false;";
if (Page.IsValid)
{
Boolean hasHasError = false;
String connectionString = String.Format(
connectionStringFormat,
IptDatabase.Text,
IptUserName.Text,
IptOldPassword.Text);
OracleCommand cmd = new OracleCommand();
using (cmd.Connection = new OracleConnection(connectionString))
{
try
{
cmd.Connection.Open();
}
catch (OracleException ex)
{
//allow to continue if the password is simply expired, otherwise just show the message
if (ex.Number != 28001)
{
ShowErrorMessage(ex.Message);
hasHasError = true;
}
}
if (!hasHasError)
{
//successful authentication, open as password change account
cmd.Connection.Close();
cmd.Connection.ConnectionString = ConfigurationManager.ConnectionStrings[IptDatabase.Text].ConnectionString;
cmd.Connection.Open();
cmd.CommandText = "SysChangePassword";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("username", IptUserName.Text);
cmd.Parameters.Add("newpassword", IptPassword.Text);
try
{
cmd.ExecuteNonQuery();
ShowInfoMessage("Password Changed");
}
catch (OracleException ex)
{
ShowErrorMessage(ex.Message);
}
}
}
}
In it's simplest form, the proc executes 'alter user identified by and would be similar to the one documented here: http://www.adp-gmbh.ch/ora/plsql/change_password.html. However the dbms_output lines don't do you much good so you could throw custom exceptions instead:
create or replace procedure SysChangePassword(
pUserName in varchar2,
pPassWord in Varchar2) as
begin
-- Check for system users here and reject
if upper(pUserName) in ('SYS','SYSTEM') then
raise_application_error(-20012, 'not allowed');
else
execute immediate 'alter user '||pUserName||' identified by ' ||
pPassWord;
end if;
exception --this isn't necessary if you'd rather examine and handle the specific exceptions on the .net side
when others then
raise_application_error(-20012, sqlerrm);
end;
/
The schema that owns this procedure needs 'alter any user' privleges. For safety's sake, your app should connect as a separate user that only has execute privs on this proc. Rather
Why don't you wrap the logic in a stored procedure? It would call the Oracle password validation functions, then you parse the results as needed, and return whatever messages you want back to the .net client?
Why don't you use a Regular Expression Validator control if writing for ASP.NET, Or Regex.IsMatch(...) Function if writing desktop applications? Why you have to go to the server first to get the error generated. you have strong password policy, and you can restrict the user on client side.

Categories