[interchange] Use bcrypt in Strap demo
Josh Lavin <[email protected]> Tue, 17 Nov 2015 18:51:15 +0000
| Newsgroups | gmane.comp.web.interchange.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit f1de50ef12da5752046b8c59dacdbd0bdd71bb96 Author: Josh Lavin <[email protected]> Date: Mon Nov 16 17:01:12 2015 -0800 Use bcrypt in Strap demo * Show demo user credentials while in demo mode * Warnings about pepper * Rework password reset to change password and set (plain), then login user (promotes from_plain), then user can change their password without knowing the old one (we set from what we changed it to earlier). The initial set also invalidates the emailed link. dist/strap/README | 10 +++++++++- dist/strap/catalog.cfg | 14 +++++++++++--- dist/strap/pages/login.html | 20 ++++++++++++++++++++ dist/strap/pages/member/get_password.html | 12 ++++++------ dist/strap/pages/query/pw_reset.html | 23 ++++++++++------------- 5 files changed, 56 insertions(+), 23 deletions(-) --- diff --git a/dist/strap/README b/dist/strap/README index 57ecbae..48e805e 100644 --- a/dist/strap/README +++ b/dist/strap/README @@ -17,6 +17,8 @@ The Bootstrap and jQuery files are loaded from `variables/CSS` and Works best with Interchange version 5.8.1 or higher. +Requires installation of Bundle::Interchange CPAN module. + ## Usage `bin/makecat [your-catalog-name]` @@ -28,6 +30,12 @@ Note: if you previously installed the "standard" template, you should ## Notes +* **TURN OFF the MV_DEMO_MODE variable before using this in production!** + +* User passwords are crypted by default, using bcrypt. You *should* + change the "pepper" to something unique and random for your catalog. + Search for "pepper" in catalog.cfg. + * If you want stock alerting, you need to add a cronjob for the user of your catalog, to run the 'daily' Interchange job. Something like: @@ -62,7 +70,7 @@ Note: if you previously installed the "standard" template, you should * Password Reset page no longer emails password (bad practice). Now sends a basic encoded link to reset the password, which expires in 1 - day. Requires installation of Bundle::Interchange CPAN module. + day. * Checkout pages have a ton of clean up, and improved with user-experience guidelines for Checkout from Baymard Institute. diff --git a/dist/strap/catalog.cfg b/dist/strap/catalog.cfg index 576267f..8729aab 100644 --- a/dist/strap/catalog.cfg +++ b/dist/strap/catalog.cfg @@ -255,9 +255,17 @@ Pragma no_html_comment_embed # User session related settings. # Whether to encrypt passwords in UserDB -# We usually don't for users, so we can mail them their password -# We DO in admin, that is set in catalog_after.cfg -UserDB default crypt 0 +UserDB default crypt 1 +UserDB default bcrypt 1 + +# These 2 lines are needed for query/pw_reset +UserDB default promote 1 +UserDB default from_plain 1 + +# The pepper should be unique for your site, but note that if you change this, +# it will make previously-crypted passwords inaccessible -- +# so set this before you start adding users, or don't set at all. +#UserDB default bcrypt_pepper CHANGE_ME_255370299252265 # Set to 1 to make the username and password case-insensitive UserDB default ignore_case 1 diff --git a/dist/strap/pages/login.html b/dist/strap/pages/login.html index e7d5cb5..01f24b9 100644 --- a/dist/strap/pages/login.html +++ b/dist/strap/pages/login.html @@ -100,6 +100,26 @@ mv_username=email </fieldset> </form> + [if var MV_DEMO_MODE] + <div class="bg-info"><b>Demo mode:</b> try one of these default test users:</p><ul> + [loop acclist=1 list=| + [email protected]=kirk, + [email protected]=test, + [email protected]=king, + [email protected]=rollins, + [email protected]=adams, + [email protected]=riley, + [email protected]=carter, + [email protected]=keller, + [email protected]=michaels, + [email protected]=smith, + [email protected]=test, + [email protected]=jones, + [email protected]=lucas, + |]<li>[loop-code] ([loop-param label])</li> + [/loop]</ul></div> + [/if] + [else] [bounce page="[either][ecgi destination][or]member/service[/either]"] diff --git a/dist/strap/pages/member/get_password.html b/dist/strap/pages/member/get_password.html index f85817a..d97f55d 100644 --- a/dist/strap/pages/member/get_password.html +++ b/dist/strap/pages/member/get_password.html @@ -30,14 +30,14 @@ subject="__COMPANY__ password reset" from="__COMPANY__ <__EMAIL_SERVICE__>"][perl table=userdb] $Tag->tmp('hmac'); - $Tag->tmp('expire'); + $Tag->tmp('expires'); my $db = $Db{userdb}; my $uid = $Scratch->{found_user}; my $key = $Variable->{PASSWORD_RESET_CHECK_KEY}; - my $expire = $Scratch->{expire} = $Tag->time({ body => '%y%m%d%H', adjust => '1 days', }); - my ($email, $pw, $mod_time) = $db->get_slice($uid, ['email', 'password', 'mod_time']); - # using mod_time in hmac prevents clicking link again after pw_reset page loads - my $hmac = $Tag->filter({ op => "hmac_sha1_hex.$key", body => $mod_time . $expire . $email }); + my $expires = $Scratch->{expires} = $Tag->time({ body => '%y%m%d%H', adjust => '1 days', }); + my ($email, $pw, $mod_time, $expiry) = $db->get_slice($uid, [qw/email password mod_time expiration/]); + # using mod_time+expiry in hmac prevents clicking link again after pw_reset page loads + my $hmac = $Tag->filter({ op => "hmac_sha1_hex.$key", body => $mod_time . $expiry . $expires . $email }); $Scratch->{hmac} = substr($hmac, 0, 20); # cropping to fit in email; should be ok return; [/perl]Someone (maybe you) asked to reset the password for this member: @@ -49,7 +49,7 @@ this email and nothing will happen. [area href=query/pw_reset secure="__SECURE_ENABLE__" no_session=1 form=" u=[scratch found_user] - x=[scratch expire] + x=[scratch expires] k=[scratch hmac] "] diff --git a/dist/strap/pages/query/pw_reset.html b/dist/strap/pages/query/pw_reset.html index 8f50a79..e3ea997 100644 --- a/dist/strap/pages/query/pw_reset.html +++ b/dist/strap/pages/query/pw_reset.html @@ -11,28 +11,25 @@ [and cgi k] [userdb function=logout clear-cookie="MV_PASSWORD,MV_USERNAME" hide=1] [perl table=userdb] + delete $Scratch->{key_matches}; my $uid = $CGI->{u}; - my $expire = $CGI->{x}; + my $expires = $CGI->{x}; my $time = $Tag->time({ body => '%y%m%d%H' }); - return if ($expire < $time); - # validated expiry, so keep going + return if ($expires < $time); + # validated expires, so keep going my $db = $Db{userdb}; my $key = $Variable->{PASSWORD_RESET_CHECK_KEY}; - my ($email, $old_pw, $mod_time) = $db->get_slice($uid, ['email', 'password', 'mod_time']); - # using mod_time in hmac prevents clicking link again after pw_reset page loads - my $hmac = $Tag->filter({ op => "hmac_sha1_hex.$key", body => $mod_time . $expire . $email }); + my ($email, $mod_time, $expiry) = $db->get_slice($uid, [qw/email mod_time expiration/]); + # using mod_time+expiry in hmac prevents clicking link again after pw_reset page loads + my $hmac = $Tag->filter({ op => "hmac_sha1_hex.$key", body => $mod_time . $expiry . $expires . $email }); +#Debug("k: " . $CGI->{k} . ", hmac: " . substr($hmac, 0, 20) ); if($CGI->{k} eq substr($hmac, 0, 20)) { $Scratch->{key_matches} = 1; - ## reset password and set expiration, just in case they don't change pwd now; invalidates key (increases mod_time) + # reset password and set expiration, just in case they don't change pwd now; invalidates key my $new_pw; for(1 .. 4) { $new_pw .= int(rand(10)); } - my $cry_pw = $new_pw; - if( $Config->{UserDB}{crypt} ) { - $cry_pw = $Tag->crypt($new_pw); - } my $expire_pass = $Tag->time({ body => '%Y%m%d%H%M%S', adjust => '1 days', }); - $db->set_slice($uid, [qw/password expiration/], [$cry_pw, $expire_pass]); -Log(qq{ pass for $uid was $old_pw, now $cry_pw } ); + $db->set_slice($uid, [qw/password expiration/], [$new_pw, $expire_pass]); $Scratch->{pwd} = $new_pw; $Scratch->{email} = $email; }