I have some Contained DB users in SQL Server 2017. In C# I am trying to execute a SQL command to change the password of a particular one of these users. The DB connection has permission to do this and does not require me to know the current password of the user in order to do so.
var sqlStatement = $"ALTER USER {userName} WITH PASSWORD = '#Password';";
using (var cmd = new SqlCommand(sql, sqlConnection))
{
cmd.CommandType = CommandType.Text;
//cmd.Parameters.Add("#UserName", SqlDbType.NVarChar).Value = userName;
cmd.Parameters.Add("#Password", SqlDbType.NVarChar).Value = password;
var rowsAffected = cmd.ExecuteNonQuery();
}
Above is the code I had been using. Running a trace on what was produced shows the command to be:
exec sp_executesql N'ALTER USER UserName1 WITH PASSWORD = ''#Password'';',N'#Password nvarchar(18)',#Password=N'Hqc5w7m98s4J!9'
This does not error at all, in fact it seems to work. But when I attempt to login (before the password change I could log in fine) I cannot do so. It appears to have changed the password but not to the one I specified. If I run the following command instead (no parameters in C#, just string building):
ALTER USER [UserName1] WITH PASSWORD = 'Hqc5w7m98s4J!291'
Then I am now able to login again with the new password. I cannot seem to find out what is happening in the first case? Why is it not changing the password as I expect? I've tried a few variations of it to try and get it to work using parameters but no luck. I don't want to just use the parameterless version of course but have spent around 5 hours looking at this already.
Alter User may not work with traditional parameterization.
string sqlStatement = #"
DECLARE #sql NVARCHAR(500)
SET #sql = 'ALTER USER UserName1 WITH PASSWORD= ' + QuoteName(#Password, '''')
EXEC(#sql)";
using (var cmd = new SqlCommand(sqlStatement , sqlConnection))
{
cmd.Parameters.Add("#Password", SqlDbType.NVarChar).Value = password;
// execute...
}
Related
I am trying to make a user register page that uploads the user data to a sql server database. I want to have the capability to check if a username already exists and prevent it from being made. I am able to create a new user with first name, last name, username, etc and it updates the database, but it doesn't stop me from creating a user with a username that already exists in the database. Here is my code:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
//connect registration form to database
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["sandboxConnectionStringUserData"].ConnectionString);
conn.Open(); //open connection
//SQL Query
string checkUserName = "select count(*) from UserData where UserName='"+TextBoxUserName.Text+"'";//checks if username is already there
SqlCommand command = new SqlCommand(checkUserName, conn);
int temp = Convert.ToInt32(command.ExecuteScalar().ToString());
if(temp == 1)
{
Response.Write("User name already exists");
}
conn.Close(); //close the database
}
}
I tried debugging and temp's value never changes to 1.
Thanks!
Just add a UNIQUE constraint to the username column and handle the sql exception in your app. Additionally you can/should write an SP that takes username as an argument and checks for existence in the table, and use that in your server-side validation after the form is sorted but before the insert (save()) occurs. That way you reduce the probability of encountering a sql exception but can still deal with it if it occurs.
Your current method of appending the form data to a raw sql query is going to open you up to sql injection. Use a parameterized query instead.
Creating a UNIQUE constraint on the UserName column is a good start. I would also create a stored procedure that checks the existence of the user and inserts or updates as well structure your code a bit more efficiently. The username should be passed in as a parameter and you should properly dispose of the connection object.
As an example your stored procedure may look like:
CREATE PROCEDURE dbo.uspUserData #userName VARCHAR(50)
AS
BEGIN
IF EXISTS(SELECT 1 FROM dbo.UserData WITH(NOLOCK)
WHERE UserName = #userName)
BEGIN
-- update
END
ELSE
BEGIN
-- insert
END
END
And your .NET code may look like:
using (
SqlConnection conn =
new SqlConnection(
ConfigurationManager.ConnectionStrings["sandboxConnectionStringUserData"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("uspUserData", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#UserName", SqlDbType.VarChar).Value = TextBoxUserName.Text;
conn.Open();
cmd.ExecuteNonQuery();
}
}
My update query
update tbl_Clients set Username=#Username, Password=#Password where Id=#Id
When I am updating this code in giving error Syntax error in update statement
The reason might because Passowrd is a reserved keyword in MS Access. You should use it with square brackets like [Password]
update tbl_Clients set Username = #Username, [Password] = #Password where Id = #Id
As a best practice, change it to non-reserved word.
By the way, if you using OleDb provider, it doesn't care about the named parameters. It only care about their orders. Since you didn't show your code, I hope you provided your parameters in a same order that you defined in your command. Like;
var cmd = OleDbCommand("update tbl_Clients set Username = #Username, [Password] = #Password where Id = #Id");
cmd.Parameters.Add("#Username", OleDbType.VarChar, 255).Value = Username;
cmd.Parameters.Add("#Password", OleDbType.VarChar, 255).Value = Password;
cmd.Parameters.Add("#Id", OleDbType.Integer).Value = Id;
For MS Access you use a question mark ("?") in order to reference parameters in a query, so:
update tbl_Clients set Username=?, Password=? where Id=?
Of course you must be careful to add the parameters to the command object in the same order as they appear in the query. See this blog post for some examples.
I have a table that has a list of user names and passwords and I want to match the the user name and password the user enter with the one saved in the DB. The code I am using only retrieves the login information of the first record in the users table, how can I change that so the code would work for all user.
I am a beginners at VS and I am trying to learn the basics so later on I will be implementing more complex login page with encryption.. Thank you
private void btnLogin_Click(object sender, EventArgs e)
{
SqlConnection cn = new SqlConnection();
SqlCommand cmd = new SqlCommand();
SqlDataReader dr;
cn.ConnectionString = "Server=;Database=;User Id=naljalid;Password=";
cmd.Connection = cn;
string username = tbxUserName.Text;
cmd.CommandText = "SELECT UserPassword FROM tblLoginProject WHERE UserName=username";
// open a connection to DB
cn.Open();
//read the table
dr = cmd.ExecuteReader();
//read a record from te data reader
dr.Read();
// compare the passwords
if (tbxPassword.Text == dr.GetString(0))
{
MessageBox.Show("Hello");
}
else
{
MessageBox.Show("Login failed, please re-enter your password");
}
}
The key to this is the SQL query, specifically the WHERE clause:
SELECT UserPassword FROM tblLoginProject
This query will return all the passwords from the database. But you want to retrieve the password of only one user, so you need to implement a WHERE clause
SELECT UserPassword FROM tblLoginProject WHERE UserName = #username
This query will retrieve the password for only a certain user where the value of the field UserName equals the value passed in the parameter #username. So now we need to make sure to pass that value. You can't just include it in the SQL query like you're doing right now. We do it like this:
cmd.Paramateres.AddWithValue("#username", username);
This should work fine, but for best practices you should check for both username and password at the same time:
SELECT count(*) FROM tblLoginProject WHERE UserName = #username AND UserPassword = #password
Then of course we pass both values:
cmd.Paramateres.AddWithValue("#username", username);
cmd.Paramateres.AddWithValue("#password", password);
This will return 0 if no users are found with that combination of username and password (invalid login), or more than 0 if such a user was found (valid login).
Next stop you should research hashing passwords. After that would be salting these hashes. Good luck!
Change the query a tidge to this:
cmd.CommandText = "SELECT UserPassword FROM tblLoginProject WHERE UserName = #username";
and then set that parameter value:
cmd.Parameters.AddWithValue("#username", tbxUserName.Text);
That will get you the row for the user you're looking for. Now on to a few more recommendations. The ADO.NET classes implement the IDispoable interface. That interface identifies that the class uses some unmanaged resources. You want to make sure those get disposed. Consider the following rewrite of your current code:
using (SqlConnection cn = new SqlConnection("Server=;Database=;User Id=naljalid;Password="))
using (SqlCommand cmd = new SqlCommand("SELECT UserName FROM tblLoginProject WHERE UserName = #username AND Password = #password", cn))
{
cn.Open();
cmd.Parameters.AddWithValue("#username", tbxUserName.Text);
cmd.Parameters.AddWithValue("#password", tbxPassword.Text);
var result = cmd.ExecuteScalar() as string;
if (string.IsNullOrEmpty(result))
{
// user was not found
}
else
{
// user was found
}
}
It leverages the using statement to ensure that the objects get disposed.
I am using MS access 2010 and try to connect it using C# windows application and use this code to update the data,
com.CommandText = "UPDATE Admin SET UserName = #UN, Password = #Pass, ValidID = #VID WHERE ID = #ID";
com.Parameters.AddWithValue("#UN", TBUserName.Text);
com.Parameters.AddWithValue("#Pass", TBPassword.Text);
com.Parameters.AddWithValue("#VID", CBvalidation.SelectedValue);
com.Parameters.AddWithValue("#ID", CBEmpName.SelectedValue);
ds.Tables.Add("Admin");
da.Fill(ds, "Admin");
in run time the error that appears is
"Syntax error in UPDATE statement"
So please could u tell me where is the error?
PASSWORD is a reserved keyword in Access JET/SQL.
You need to encapsulate it with square brackets
com.CommandText = "UPDATE Admin SET UserName = #UN, " +
"[Password] = #Pass, ValidID = #VID WHERE ID = #ID";
If it is possible, I suggest you to change the name of this field.
You will have always this problem for every future query on this table.
Try this
com.CommandText =
"UPDATE Admin SET UserName = #UN, [Password] = #Pass, ValidID = #VID WHERE ID = #ID";
You can't use Password as it is reserved instead used [Password]
PASSWORD is a reserved keyword on Access.
Use it with square brackets like [PASSWORD]
com.CommandText = "UPDATE Admin SET UserName = #UN, [Password] = #Pass, ValidID = #VID WHERE ID = #ID";
As a general recomendation, don't use reserved keywords for your identifiers and object names in your database.
I have the following update query in C# using a JET OLEDB connection, connecting to a ms access DB file. The query fails to change the fields, it runs correctly but just 0 rows changed.
I think the problem is how parameters are processed and compared against the DB but have no idea how to fix it.
The "User" column is set as text. I have an insert statement that works perfectly set up in the same fashion with the parameters.
com.CommandText = "UPDATE [ExamMaster] SET [User] = (DLookup('LName', 'Users', 'ID' = '#correctUser') WHERE [User] = '#user'";
com.Parameters.AddWithValue("#correctUser", correctUser);
com.Parameters.AddWithValue("#user", userName);
If I do not use a parameter for the where clause and just insert it into the command string like so:
WHERE [User] = '"+userName+"'";</code>
it will update the DB just fine. What am I missing here?
UPDATE:
With or with single quotes makes no difference and rearranging the order of the parameters does not work either.
The order matters. I "think" in your query user is being called first before the correctUser due to the DLOOKUP function.
com.Parameters.AddWithValue("#user", userName);
com.Parameters.AddWithValue("#correctUser", correctUser);
You don't need to single quote parameters:
WHERE [User] = #user";
and I'll guess that the DLOOKUP doesn't need the single quotes either, just [brackets] if the field name has a space or is a reserved word (which [User] might be).
You will need to change that a bit, try:
OleDbConnection cn = new OleDbConnection(aconnectionstring);
cn.Open();
//testing
int correctUser = 1;
string userName = "1";
OleDbCommand com = new OleDbCommand();
com.Connection = cn;
//You cannot have a parameter in DLookUp
com.CommandText = "UPDATE [ExamMaster] SET [User] = " +
"DLookup('LName', 'Users', 'ID = " + correctUser + "') WHERE [User] = #user";
com.Parameters.AddWithValue("#user", userName);
//You must execute the query
com.ExecuteNonQuery();