Skip to content

Commit

Permalink
Use bcrypt in Strap demo
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
Josh Lavin committed Nov 17, 2015
1 parent e7f73cb commit f1de50e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
10 changes: 9 additions & 1 deletion dist/strap/README
Expand Up @@ -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]`
Expand All @@ -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:

Expand Down Expand Up @@ -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.
Expand Down
14 changes: 11 additions & 3 deletions dist/strap/catalog.cfg
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions dist/strap/pages/login.html
Expand Up @@ -100,6 +100,26 @@ <h1>[L]Please Log In[/L]</h1>
</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=|
kirk@icdevgroup.net=kirk,
devnull@icdevgroup.net=test,
king@icdevgroup.net=king,
Rollins@icdevgroup.net=rollins,
adams@icdevgroup.net=adams,
riley@icdevgroup.net=riley,
carter@icdevgroup.net=carter,
keller@icdevgroup.net=keller,
michael@icdevgroup.net=michaels,
smith@icdevgroup.net=smith,
milton@icdevgroup.net=test,
jones@icdevgroup.net=jones,
lucas@icdevgroup.net=lucas,
|]<li>[loop-code] ([loop-param label])</li>
[/loop]</ul></div>
[/if]

[else]

[bounce page="[either][ecgi destination][or]member/service[/either]"]
Expand Down
12 changes: 6 additions & 6 deletions dist/strap/pages/member/get_password.html
Expand Up @@ -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:
Expand All @@ -49,7 +49,7 @@

[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]
"]

Expand Down
23 changes: 10 additions & 13 deletions dist/strap/pages/query/pw_reset.html
Expand Up @@ -11,28 +11,25 @@ <h1>Password Reset</h1>
[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;
}
Expand Down

0 comments on commit f1de50e

Please sign in to comment.