In this lab, you're going to make a better User
model with password hashing. Check out the empty repo to start, and create a new directory to work in on your VM. Linking a new directory to the webserver:
etomai@lamp-6312-vm:~$ mkdir assn08 etomai@lamp-6312-vm:~$ sudo ln -s ~/assn08 /var/www/html/assn08
Repo invite: https://classroom.github.com/a/giCdAeoT
For this assignment, we need to update our database user table with a password field. Using myPhpAdmin, add the following column to the user table:
password_hash
: varchar(128)
Create (or copy) your composer.json
file and use composer to install propel in this project. You have to edit out the autoload section in composer.json
or it will error and corrupt the install trying to load models that aren't there yet.
Then, generate your models with propel init
. Afterward, put the autoload section back in composer.json
and run composer dump-autoload
.
In a new php file, do a quick check to make sure that your User
model is properly configured and works.
User
with bogus dataLoad the page to see if it works, and check your database to confirm that the test user was added.
In this part, we're going to take advantage of the fact that Propel creates a stub User
model (in models) that inherits from the Base/User
model. That stub allows us to add functionality. In this case, we're going to override setPasswordHash
to take the provided password, hash it, and store the result in the database (instead of storing the actual password).
Never roll your own security code! We have a nice option here with the simple PhPassLib hashing library, which we can install using composer and autoload. Update your require
section of your composer.json
to include:
"require": { "propel/propel": "~2.0@dev", "rych/phpass": "3.0.*@beta" }
Then run composer update
to install the new library and composer dump-autoload
. Autoload is a bit overly complex and opaque, but you see the advantages here for a project that uses many dependencies. Since we're already using require_once "vendor/autoload.php";
in our Controller, we're all set to use PhPassLib as well.
Comment out your insert code for a minute and run this simple example in your php file to see how PhPassLib works.
$password = "horriblepassword"; // Calculate a bcrypt hash from a password $hash = PHPassLib\Hash\BCrypt::hash($password); echo "First hash is: ".$hash."<br/>"; // Do it again! $hash = PHPassLib\Hash\BCrypt::hash($password); echo "Second hash is different (salt changed): ".$hash."<br/>"; // Calculate a bcrypt hash with a specific number of rounds $hash = PHPassLib\Hash\BCrypt::hash($password, array ('rounds' => 16)); echo "Third hash is sloooow: ".$hash."<br/>"; // Check supplied password against a stored hash if (PHPassLib\Hash\BCrypt::verify($password, $hash)) { echo "Password is valid!<br/>"; }
Now your part! Add a setPasswordHash
method to the User
model to override Base\User::setPasswordHash
. Your method should:
Note, in PHP you use parent::method_name()
to call an overridden parent method.
Now uncomment and re-run the insert test in your php file. Check your db - you should be storing users with real password hashes.
Finally, update the User
model to add a login
method. Comment out your testing and insert code and paste in the following and make it work.
// set $username and $password to a valid combination $user = UserQuery::create()->findOneByUsername($username); echo "Got user: ".$user."<br/>"; echo "Login with correct password...<br/>"; if( $user->login($password) ) { echo "Success!<br/>"; } else { echo "Failure!<br/>"; } echo "Login with incorrect password...<br/>"; if( $user->login("bogusbogusbogus") ) { echo "Success! (that's bad)<br/>"; } else { echo "Failure! (that's good)<br/>"; }
Commit the php file you tested with, with the testing, insert and login code in it (just keep it neat and comment our parts you're not using), as well as your modified User.php
model.