default to a session cookie instead of setting an explicit timeout, weird timezone...
[freeside.git] / FS / FS / Auth / internal.pm
1 package FS::Auth::internal;
2 #use base qw( FS::Auth );
3
4 use strict;
5 use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 de_base64);
6 use FS::Record qw( qsearchs );
7 use FS::access_user;
8
9 sub authenticate {
10   my($self, $username, $check_password, $totp_code ) = @_;
11
12   my $access_user =
13     ref($username) ? $username
14                    : qsearchs('access_user', { 'username' => $username,
15                                                'disabled' => '',
16                                              }
17                              )
18     or return 0;
19
20   my $pw_check;
21   if ( $access_user->_password_encoding eq 'bcrypt' ) {
22
23     my( $cost, $salt, $hash ) = split(',', $access_user->_password);
24
25     my $check_hash = en_base64( bcrypt_hash( { key_nul => 1,
26                                                cost    => $cost,
27                                                salt    => de_base64($salt),
28                                              },
29                                              $check_password
30                                            )
31                               );
32
33     $pw_check = $hash eq $check_hash;
34
35   } else {
36
37     return 0 if $access_user->_password eq 'notyet'
38              || $access_user->_password eq '';
39
40     $pw_check = $access_user->_password eq $check_password;
41
42   }
43
44   return $pw_check if ! $pw_check || ! length($access_user->totp_secret32);
45
46   #2fa
47   $access_user->google_auth->verify( $totp_code, 1 );
48 }
49
50 sub autocreate { 0; }
51
52 sub change_password {
53   my($self, $access_user, $new_password) = @_;
54
55   # do nothing if the password is unchanged
56   #XXX breaks password changes in employee edit ($access_user object already
57   # has new [plaintext] password)
58   #return if $self->authenticate( $access_user, $new_password );
59
60   $self->change_password_fields( $access_user, $new_password );
61
62   $access_user->replace;
63
64 }
65
66 sub change_password_fields {
67   my($self, $access_user, $new_password) = @_;
68
69   $access_user->_password_encoding('bcrypt');
70
71   my $cost = 8;
72
73   my $salt = pack( 'C*', map int(rand(256)), 1..16 );
74
75   my $hash = bcrypt_hash( { key_nul => 1,
76                             cost    => $cost,
77                             salt    => $salt,
78                           },
79                           $new_password,
80                         );
81
82   $access_user->_password(
83     join(',', $cost, en_base64($salt), en_base64($hash) )
84   );
85
86 }
87
88 1;