We use LDAP (Samba) for authentication and now I want to make user able to change their password. I'm using this script:
$username = $request->request->get('username');
$oldpasswd = $request->request->get('oldpasswd');
$newpasswd = $request->request->get('newpasswd');
$userPassword = mb_convert_encoding('"'.$newpasswd.'"', 'utf-16le');
$ldapPasswd = $this->getParameter('LDAP_PASSWD');
$ldap->bind("CN=LDAPADMIN,CN=Users,DC=DOMAIN,DC=net", $ldapPasswd);
$query = $ldap->query('CN=users,DC=DOMAIN,DC=net', "(&(objectclass=person)(sAMAccountName=$username))");
$result = $query->execute()->toArray();
$entry = $result[0];
$newEntry = new Entry($entry->getDn(), [
'unicodePwd' => [$userPassword],
]);
$ldap->getEntryManager()->update($newEntry);
It is working ok but with this, all security settings are not valid: Don't repeat password, password length > 6 characters etc etc... And, the script uses an Adminstrator account to change password.Is there any other way to update the user password using user account for that and validating password security configs?
Based on your code, it seems you're using Symfony and you have an Active Directory server.
Your code is doing a "password reset", which is something an administrator would do if a user forgets their password. It requires administrative rights and does not require knowing the previous password, and thus it does not enforce previous history.
What you want to do is a "password change". The documentation for unicodePwd explains how to do this:
If the Modify request contains a delete operation containing a value Vdel for unicodePwd followed by an add operation containing a value Vadd for unicodePwd, the server considers the request to be a request to change the password. The server decodes Vadd and Vdel using the password decoding procedure documented later in this section. Vdel is the old password, while Vadd is the new password.
In LDAP, this is called a "batch request", which contains both a delete instruction and an add instruction, all in the same single request to the server. The Symfony documentation includes a section on how to do Batch Updating. In your case, it should look something like this:
$username = $request->request->get('username');
$oldpasswd = $request->request->get('oldpasswd');
$newpasswd = $request->request->get('newpasswd');
$oldUserPassword = mb_convert_encoding('"'.$oldpasswd.'"', 'utf-16le');
$userPassword = mb_convert_encoding('"'.$newpasswd.'"', 'utf-16le');
$ldapPasswd = $this->getParameter('LDAP_PASSWD');
$ldap->bind("CN=LDAPADMIN,CN=Users,DC=DOMAIN,DC=net", $ldapPasswd);
$query = $ldap->query('CN=users,DC=DOMAIN,DC=net', "(&(objectclass=person)(sAMAccountName=$username))");
$result = $query->execute()->toArray();
$entry = $result[0];
$entryManager->applyOperations($entry->getDn(), [
new UpdateOperation(LDAP_MODIFY_BATCH_REMOVE, 'unicodePwd', $oldUserPassword),
new UpdateOperation(LDAP_MODIFY_BATCH_ADD, 'unicodePwd', $userPassword),
]);
Notice that you have to encode the old password the same way you encoded the new password.
Related
This question already has answers here:
How to use PHP's password_hash to hash and verify passwords
(5 answers)
Closed 1 year ago.
Here's my code:
function login() {
//Declare variables
$username = $_POST["login"];
$password = $_POST["password"];
$client = $_POST["clients"];
//QueryDB
$servername = "localhost";
$SQLUsername = "XXXX";
$SQLPassword = "XXXX";
$dbname = "XXXX";
$conn = new mysqli($servername, $SQLUsername, $SQLPassword, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//Set query then run it
$sql = "SELECT * FROM Users WHERE Username ='$username'";
$result = $conn->query($sql);
$row = $result->fetch_array(MYSQLI_ASSOC);
//Verify Password
if ($result->num_rows === 1) {
if (password_verify($password, $row['Password'])) {
//Build XML request
$XMLRequest = "<?xml version='1.0'?><Login><Client>".$client."</Client><LoginDetails><Username>".$username."</Username><Password>".$newhash."</Password></LoginDetails></Login>";
//Build URL
$ReplacedValues = array("NewType" => "login", "NewHash" => $XMLRequest);
$NewString = strtr($GLOBALS["params"], $ReplacedValues);
$NewUrl = $GLOBALS["link"].$NewString;
//Post to Server
header('Location: '.$NewUrl);
}
else {
echo "Password is wrong"."<br>";
echo $password."<br>";
echo $row['Password'];
}
} else {
echo "more then 1 row";
}
mysqli_close($conn);
}
My issue is that even if I hard code my password variable and Hash variable to their respective values the if condition returns false. Any idea why? The page does when it loads, loads the else condition to show me the user input password and the correct hash value from the DB. My DB is set to CHAR(255) for the password.
UPDATE**
Here is my C# discussed in the comments. This is not the complete code just up to the part of the insert statement for the DB. I am able to insert into the SQL server DB just fine.
public static string WebsiteRegister(XmlDocument XMLBody)
{
//Get SQL connection string
XmlNodeList XMLNodes = SQLConnectionMethods.EstablishSQLServerConnection("SQL");
string ConnectionString = XMLNodes.Item(0).ChildNodes[0].InnerText;
string UserName = XMLNodes.Item(0).ChildNodes[1].InnerText;
string Password = XMLNodes.Item(0).ChildNodes[2].InnerText;
//Open connnection
SqlConnection cnn = new SqlConnection(ConnectionString);
SQLConnectionMethods.OpenSQLServerConnection(cnn);
try
{
string username = XMLBody.SelectSingleNode("register/registerdetails/username").InnerText;
string pass = XMLBody.SelectSingleNode("register/registerdetails/password").InnerText;
string fname = XMLBody.SelectSingleNode("register/registerdetails/firstname").InnerText;
string lname = XMLBody.SelectSingleNode("register/registerdetails/lastname").InnerText;
string email = XMLBody.SelectSingleNode("register/registerdetails/email").InnerText;
string accountRef = XMLBody.SelectSingleNode("register/registerdetails/accountreference").InnerText;
string client = XMLBody.SelectSingleNode("register/client").InnerText;
//Build Query string
string queryString = $"Insert into [dbo].[UserAccounts] (AccountReference, FirstName, LastName, Email, Username, Pass, Client) values ('{accountRef}', '{fname}', '{lname}', '{email}', '{username}', '{pass}', '{client}')";
//Process request
using (SqlCommand myCommand = new SqlCommand(queryString, cnn))
{
string Result = (string)myCommand.ExecuteScalar();
I could not find any problem in your code here but since hashing and verifying is a process which depends on a lot of factors to be successful i would like to give you some tips so that you can check it yourself for any potential problems.
make sure you are not escaping/sanityzing the password before
hashing it. This way you're altering the stored password. Let
$password = $_POST['password'];
both when you create the account and
when you check if the password match at login.
make sure you are enclosing the hash variable in single quotes (') and not double quotes (").using double quotes makes PHP read each paired character with "$" as indivisual variables which will probably cause your code to break, USE SINGLE QUOTES INSTEAD.
Ensure the Password field in the database (that stores the hashed
password) is able to store up to 255 characters. From the documentation
it is recommended to store the result in a database column that can
expand beyond 60 characters (255 characters would be a good choice). If the field is narrower the hash will be truncated and you'll never
have a match.
As you get the user by username at login ensure that username is unique
as long as it is your primary key (in the table
definition). Good idea to check this also upon user registration and login (at php level).
echo both hash and entered
values and make sure they match the ones that were inserted and
generated during password_hash() if the database value was different
(the hash), make sure the type of its column is varchar(256), the
hash is usually 60 characters long but the hashing function is
frequently improved so that length may expand in the future.
if the entered value was different (the user password), make sure the
filtering isn't corrupting the password value.
also check if another variable has the same name as the one you're storing the password in.
If password_verify($password, password_hash($password, PASSWORD_DEFAULT))
"works", then the problem is that $row['Password'] does not contain what is expected - including not being generated correctly.
If it "doesn't work" then
another line is causing the observed behavior. Both of these
outcomes allow focusing on a refined problem set.
try changing the password from the another column that matched and copy it to your password column and enter that password to check.if it worked then there is problem with your stored password
try copying this hash to your password column
$2y$10$uDnEpQpkh9RO5tWwOrHtneLAuYMRDstRaKGZFyHubObDR0789OMO6
this is the hashed password for 123456 using bycrypt. select this password and try to verify it with password_verify(123456,$yourhashedfromdatabase) after selecting this from sql if it works then there is probably some manipulation after your data is entered and goes to the database. it it does not then check if the password that reaches the database is exactly as your typed by echoing it.
UPDATE: after you updated your code i see that while entering the password you use "Pass" column but while extracting you use "Password" column. this could be the issue
I am working on page with register and login possibilities.
It always says that the password is incorrect. What am I doing wrong?
I also tried with iterator_to_array, it doesn't work either.
$db = get_db();
$mojlogin = $_POST['login'];
$mojehaslo = $_POST['haslo'];
empty($mors);
$mors = $db->morsy->findOne(array('login' => $mojlogin, "haslo1" => $mojehaslo));
if(password_verify($mojehaslo, $mors['haslo1'])){
echo "Zalogowany!\n";
$powitanie = "Witaj ponownie, ".$mojlogin."!";
echo "<h1 class='tytul'>$powitanie</h1>";
$_SESSION["user"] = $mojlogin;
} else {
echo "Niepoprawny login lub hasło!\n";
}
As far as I can tell from your code, you request the user password and use it as a search criteria to get his account from the database, which implies that instead of storing the hash of the password, you store the password itself.
The proper way to do this is to generate hash first, store it in haslo1 field, and then use it as a second argument in the password_verify function along with the actual password in $mojehaslo as the first one. Furthermore, you only use $mojlogin in the findOne() query, because the idea is to get the hash from the database corresponding to user login and compare it to the password that was entered.
You normally want to generate your hash using password_hash function:
$hash = password_hash($password, PASSWORD_DEFAULT);
Then, after you place it in haslo1 document field, you use almost the same code as you did before:
$mors = $db->morsy->findOne([ 'login' => $mojlogin ]);
if (password_verify($mojehaslo, $mors['haslo1'])) {
// here goes your entrance code
}
Check var_dump, always.
After not getting my login, my friends told me to use:
var_dump(iterator_to_array($db->morsy->find()))
I had white space before login, because of mistakes in form.
I have problems setting password for exiting user in Ion Auth, Version: 2.5.2, Codeigniter : 3.1.0-dev
In application/config/ion_auth.php I have by default :
$config['hash_method'] = 'bcrypt'; // sha1 or bcrypt, bcrypt is STRONGLY recommended
$config['default_rounds'] = 8; // This does not apply if random_rounds is set to true
$config['random_rounds'] = FALSE;
$config['min_rounds'] = 5;
$config['max_rounds'] = 9;
$config['salt_prefix'] = '$2y$';
$config['default_group'] = 'Members'; // Default group, use name
$config['admin_group'] = 'Admin'; // Default administrators group, use name
$config['identity'] = 'email'; // A database column which is used to login with
$config['min_password_length'] = 6; // Minimum Required Length of Password
$config['max_password_length'] = 20; // Maximum Allowed Length of Password
$config['email_activation'] = FALSE; // Email Activation for registration
$config['manual_activation'] = FALSE; // Manual Activation for registration
$config['remember_users'] = TRUE; // Allow users to be remembered and enable auto-login
//$config['user_expire'] = 986500; // How long to remember the user (seconds). Set to zero for no expiration
$config['user_expire'] = 0; // How long to remember the user (seconds). Set to zero for no expiration
$config['user_extend_on_login'] = TRUE; // Extend the users cookies every time they auto-login
$config['track_login_attempts'] = FALSE; // Track the number of failed login attempts for each user or ip.
$config['track_login_ip_address'] = TRUE; // Track login attempts by IP Address, if FALSE will track based on identity. (Default: TRUE)
$config['maximum_login_attempts'] = 3; // The maximum number of failed login attempts.
$config['lockout_time'] = 600; // The number of seconds to lockout an account due to exceeded attempts
$config['forgot_password_expiration'] = 0; // The number of milliseconds after which a forgot password request will expire. If
In my control I run :
$OkResult = $this->ion_auth_model->reset_password($lUserOperator['email'], $GeneratePassword) ;
AppUtils::deb($OkResult, '$OkResult::');
where $GeneratePassword is string like 'JKC3vmci', $lUserOperator['email'] is valid email of active user, value of returned value OkResult = 1
looking into db for updated user I see password value like '$2y$08$vyeSO30G4eQL3efuYbNii.VAlayDrAslKQNMDkdLYegggcsLWsQbe' and salt field is empty string(not NULL). But I can not login to system, but I login under usual login ok. What can be the reason of problem?
Also revieing code of ion_auth I see in reset_password function triggering events like post_change_password, post_change_password...
Could you please give ref to examples of using of this events?
In my control I run :
$OkResult = $this->ion_auth_model->reset_password(...
Why are you calling the ion_auth_model directly?
This is unnecessary and likely the cause of your troubles since you're bypassing much of Ion Auth's critical logic.
As per the developer's documentation:
NOTE: Methods available in the model are called through the controller using PHP5 magic. You should never use ion_auth_model->method() in your applications.
The developer has already provided many relevant functions you can use anywhere in your project. To update any user's account including resetting their password, you would use the update() class...
$id = 12; // <- Existing user's ID
$data = array(
'password' => '123456789', // <- NEW password
);
$this->ion_auth->update($id, $data); // <- Update the user's account
update() returns true if the update was successful and false if not.
If you don't know the user's id, then you simply do a standard database query on the "users" table to retrieve their id based on email address.
Could you please give ref to examples of using of this events?
See documenation: benedmunds.com/ion_auth
I've got a C5 site wherein I need to programmatically create user accounts. What I've done is use the register method of the UserInfo class, which seems to work. Problem is none of the users created this way are able to log in, the C5 login page just returns "Invalid email address or password."
I've checked and they are showing up in the users table. I've tried copying the password hash for a user who can log in, but the programmatically created user still can't log in. I've also asked another dev I know and after looking at the code says it's practically identical to how he's done this in the past. At this point I'm a bit stumped on how to move forward with troubleshooting this.
If it makes a difference the site is set to use email addresses instead of usernames for login.
//name = guy incognito \ both passed in
//email = 1234#5678.com \ via POST
function getRandomString($length) {
$seed = chr(mt_rand(97 ,122)).substr(md5(time( )), 1);
$rand = "";
for($y = 0; $y <= $length; $y++) {
$rand .= substr($seed, rand(0, strlen($seed)), 1);
}
return $rand;
}
$pswd = getRandomString(8);
$userData['uName'] = md5($name . rand(1, 1000) . date('Y-m-d H:i:s'));
$userData['uEmail'] = $email;
$userData['uPassword'] = $pswd;
$userData['uPasswordConfirm'] = $pswd;
$ui = UserInfo::register($userData);
Here's a screen capture of the entry created in the user table:
http://i.stack.imgur.com/N1ebw.png (unfortunately I lack the reputation to post images directly)
Edit - 19/09/2014
Having worked on this a little further I've traced the problem down into the checkPassword function of the 3rd party phpass library C5 is using. The hash it's generating when it checks during login is different than the hash generated at the time of account creation.
account creation hash = $2a$12$6UZ//BGdH6sO2AhfykvyHOLfzR2ADOuQVnzcFu6P9FckbJ56Y40WW
login attempt hash = $2a$12$6UZ//BGdH6sO2AhfykvyHOoxM727vGVnxo.3VsFYwDjKUM13SJqtO
After looking at concrete/core/dashboard/users/add.php I noticed they were registering users in a slightly different manner. Here they aren't passing a password confirmation, are specifying a default language, and most noticeably not calling UserInfo::Register but instead UserInfo::Add.
After updating my code to reflect how it was being done there things work. For the record:
$uName = md5($_POST['repName'] . rand(1, 1000) . date('Y-m-d H:i:s'));
$data = array('uName' => $uName, 'uPassword' => $authCode, 'uEmail' => $_POST['repEmail'], 'uDefaultLanguage' => 'En');
$ui = UserInfo::add($data);
I have a web aplication where I can create Tecnico
TecnicoController (application web)
$tecnico = new Tecnico;
$tecnico->idTecnico = Input::get('idtecnico');
$tecnico->Nombre = Input::get('nombre');
$tecnico->Apellido = Input::get('apellido');
$tecnico->Telefono = Input::get('telefono');
$tecnico->Contrasena = Hash::make(Input::get('idtecnico')); //<--- hash of my pass, eg pass: 12 -> hash: $12345abc
$path = public_path().'/tecnico';
$fotoPerfil = Input::file('imagen');
$fotoPerfil->move($path, Input::get('idtecnico'));
$tecnico->Foto ='/tecnico/'.$tecnico->idTecnico;
$tecnico->save();
Also I have a different project, that works as a server to access the database from a mobile application. A Tecnico from your cell phone can access your account by entering a contrasena (password) and idTecnico(id)
TecnicoController (server)
$idUnico = Input::get('idUnico');
$contrasena = Hash::make(Input::get('contrasena')); //<--- hash of my pass: eg pass: 12 -> hash: $146435gzc (change)
$tecnico = DB::table('Tecnico')->where('idTecnico', $idUnico)->where('Contrasena', $contrasena)->first();
The problem happens when you enter the password from the server. The Hashin creates a different value that exists in the database (when creating a Tecnico).
How I can get the same hash value that is in the database?
Unfortunately you can't do this easily in a query, your best bet would be to grab the user and then compare the password, like so.
$idUnico = Input::get('idUnico');
$tecnico = DB::table('Tecnico')->where('idTecnico', $idUnico)->first();
if($tecnico) {
if(Hash::check(Input::get('contrasena'), $technico->Contrasena)) {
// passwords are the same
}
}