[freeside-commits] branch FREESIDE_4_BRANCH updated. 618c671fd12beb2122a4c32c0042546a19a9c765

Ivan Kohler ivan at freeside.biz
Wed Sep 7 17:22:55 PDT 2022


The branch, FREESIDE_4_BRANCH has been updated
       via  618c671fd12beb2122a4c32c0042546a19a9c765 (commit)
      from  6229b35780da2f5593202aa1f0a61f31eb8fa9fa (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 618c671fd12beb2122a4c32c0042546a19a9c765
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Wed Sep 7 17:22:54 2022 -0700

    google authenticator support, RT#86743

diff --git a/FS/FS/AuthCookieHandler.pm b/FS/FS/AuthCookieHandler.pm
index 93d8ea6a5..b7d0dbf5b 100644
--- a/FS/FS/AuthCookieHandler.pm
+++ b/FS/FS/AuthCookieHandler.pm
@@ -13,13 +13,13 @@ sub useragent_ip {
 }
 
 sub authen_cred {
-  my( $self, $r, $username, $password ) = @_;
+  my( $self, $r, $username, $password, $totp_code ) = @_;
 
   preuser_setup();
 
   my $info = {};
 
-  unless ( FS::Auth->authenticate($username, $password, $info) ) {
+  unless ( FS::Auth->authenticate($username, $password, $totp_code, $info) ) {
     warn "failed auth $username from ". $self->useragent_ip($r). "\n";
     return undef;
   }
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index ad88f96ff..f1eb2b23d 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -5818,6 +5818,7 @@ sub tables_hashref {
         'username',           'varchar',     '', $char_d, '', '',
         '_password',          'varchar', 'NULL', $char_d, '', '',
         '_password_encoding', 'varchar', 'NULL', $char_d, '', '',
+        'totp_secret32',         'char', 'NULL',      32, '', '',
         'last',               'varchar', 'NULL', $char_d, '', '', 
         'first',              'varchar', 'NULL', $char_d, '', '', 
         'user_custnum',           'int', 'NULL',      '', '', '',
diff --git a/FS/FS/access_user.pm b/FS/FS/access_user.pm
index f23aa77f9..270f8bb27 100644
--- a/FS/FS/access_user.pm
+++ b/FS/FS/access_user.pm
@@ -13,6 +13,7 @@ use FS::agent;
 use FS::cust_main;
 use FS::sales;
 use Carp qw( croak );
+use Auth::GoogleAuth;
 
 $DEBUG = 0;
 $me = '[FS::access_user]';
@@ -239,6 +240,7 @@ sub check {
     $self->ut_numbern('usernum')
     || $self->ut_alpha_lower('username')
     || $self->ut_textn('_password')
+    || $self->ut_alphan('totp_secret32')
     || $self->ut_textn('last')
     || $self->ut_textn('first')
     || $self->ut_foreign_keyn('user_custnum', 'cust_main', 'custnum')
@@ -733,6 +735,44 @@ sub change_password_fields {
   FS::Auth->auth_class->change_password_fields( @_ );
 }
 
+=item google_auth
+
+=cut
+
+sub google_auth {
+  my( $self ) = @_;
+  my $issuer = FS::Conf->new->config('company_name'). ' Freeside';
+  my $label = $issuer. ':'. $self->username;
+
+  Auth::GoogleAuth->new({
+    secret => $self->totp_secret32,
+    issuer => $issuer,
+    key_id => $label,
+  });
+
+}
+
+=item set_totp_secret32
+
+=cut
+
+sub set_totp_secret32 {
+  my( $self ) = @_;
+
+  $self->totp_secret32( $self->google_auth->generate_secret32 );
+  $self->replace;
+}
+
+=item totp_qr_code_url
+
+=cut
+
+sub totp_qr_code_url {
+  my( $self ) = @_;
+
+  $self->google_auth->qr_code;
+}
+
 =item locale
 
 =cut
diff --git a/debian/control b/debian/control
index fc817c05c..079765a11 100644
--- a/debian/control
+++ b/debian/control
@@ -109,7 +109,7 @@ Depends: aspell-en,gnupg,ghostscript,gsfonts,gzip,
  libspreadsheet-xlsx-perl, libpod-simple-perl, libwebservice-northern911-perl,
  liblocale-codes-perl, liblocale-po-perl, libgeo-uscensus-geocoding-perl,
  libnet-sftp-foreign-perl, libpdf-webkit-perl, libgeo-shapelib-perl,
- libgeo-json-perl
+ libgeo-json-perl, libauth-googleauth-perl
 Conflicts: libparams-classify-perl (>= 0.013-6)
 Replaces: freeside (<<4)
 Breaks: freeside (<<4)
diff --git a/httemplate/browse/access_user.html b/httemplate/browse/access_user.html
index 446bfe0be..658762763 100644
--- a/httemplate/browse/access_user.html
+++ b/httemplate/browse/access_user.html
@@ -49,6 +49,11 @@ my $groups_sub = sub {
 
 };
 
+my $goog_auth_sub = sub {
+  my $access_user = shift;
+  $access_user->totp_secret32 ? 'Enabled' : '';
+};
+
 my $installer_sub = sub {
   my $access_user = shift;
   my @sched_item = $access_user->sched_item or return '';
@@ -66,11 +71,23 @@ my $count_query = 'SELECT COUNT(*) FROM access_user';
 my $link = [ $p.'edit/access_user.html?', 'usernum' ];
 
 my @header = (
-  'Username', 'Full name', 'Groups',    'Installer',    'Customer' );
+  'Username',
+  'Full name',
+  'Groups',
+  'Google Auth',
+  'Installer',
+  'Customer',
+);
 my @fields = (
-  'username', 'name',      $groups_sub, $installer_sub, $cust_sub, );
-my $align = 'lllcl';
-my @links = ( $link, $link, $link, '', '', $cust_link );
+  'username',
+  'name',
+  $groups_sub,
+  $goog_auth_sub,
+  $installer_sub,
+  $cust_sub,
+);
+my $align = 'lllccl';
+my @links = ( $link, $link, $link, '', '', '', $cust_link );
 
 #if ( FS::Conf->new->config('ticket_system') ) {
 #  push @header, 'Ticketing';
diff --git a/httemplate/edit/process/access_user.html b/httemplate/edit/process/access_user.html
index c27262017..8e264c1a9 100644
--- a/httemplate/edit/process/access_user.html
+++ b/httemplate/edit/process/access_user.html
@@ -5,7 +5,7 @@
 <%   include( 'elements/process.html',
                  'table'          => 'access_user',
                  'viewall_dir'    => 'browse',
-                 'copy_on_empty'  => [ '_password', '_password_encoding' ],
+                 'copy_on_empty'  => [ '_password', '_password_encoding', 'totp_secret32' ],
                  'clear_on_error' => [ '_password', '_password2' ],
                  'process_m2m'    => { 'link_table'   => 'access_usergroup',
                                        'target_table' => 'access_group',
diff --git a/httemplate/loginout/login.html b/httemplate/loginout/login.html
index 72e9525c4..1785ea796 100644
--- a/httemplate/loginout/login.html
+++ b/httemplate/loginout/login.html
@@ -27,6 +27,10 @@
         <TD ALIGN="right">Password: </TD>
         <TD><INPUT TYPE="password" NAME="credential_1" SIZE="13"></TD>
       </TR>
+      <TR>
+        <TD ALIGN="right">One-time code: </TD>
+        <TD><INPUT TYPE="text" NAME="credential_2" SIZE="13"></TD>
+      </TR>
     </TABLE>
     <BR>
  
@@ -42,7 +46,7 @@
 my %error = (
   'no_cookie'       => '', #First login, don't display an error
   'bad_cookie'      => 'Bad Cookie', #timed out?
-  'bad_credentials' => 'Incorrect username / password',
+  'bad_credentials' => 'Incorrect username / password / one-time code',
   #'logout'          => 'You have been logged out.',
 );
 
diff --git a/httemplate/pref/pref.html b/httemplate/pref/pref.html
index 56fde6d44..5f68d3e46 100644
--- a/httemplate/pref/pref.html
+++ b/httemplate/pref/pref.html
@@ -29,6 +29,18 @@
     </TABLE>
     <BR>
 
+    <FONT CLASS="fsinnerbox-title"><% emt('Google Authenticator') %></FONT>
+    <TABLE CLASS="fsinnerbox">
+      <TR>
+%       if ( $curuser->totp_secret32 ) {
+          <TD><IMG SRC="<% $curuser->totp_qr_code_url %>"</IMG></TD>
+%       } else {
+          <TD><A HREF="<%$p%>pref/set_totp_secret32.html">Enable</A></TD>
+%       }
+      </TR>
+    </TABLE>
+    <BR>
+
 % }
 
 <FONT CLASS="fsinnerbox-title"><% emt("Interface") %></FONT>
diff --git a/httemplate/pref/set_totp_secret32.html b/httemplate/pref/set_totp_secret32.html
new file mode 100644
index 000000000..f5676bc38
--- /dev/null
+++ b/httemplate/pref/set_totp_secret32.html
@@ -0,0 +1,19 @@
+<& /elements/header.html, mt('Google Authenticator for [_1]', $FS::CurrentUser::CurrentUser->username) &>
+
+Scan this code with the Google Authenticator application on your phone.
+<BR><BR>
+
+<IMG SRC="<% $access_user->totp_qr_code_url %>"></IMG>
+<BR><BR>
+
+Future logins will require a 6-digit code generated by the application.
+
+<& /elements/footer.html &>
+<%init>
+
+my $access_user = $FS::CurrentUser::CurrentUser;
+
+my $error = $access_user->set_totp_secret32 unless length($access_user->totp_secret32);
+die $error if $error; #better error handling for this "shouldn't happen" case?
+
+</%init>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/AuthCookieHandler.pm               |  4 ++--
 FS/FS/Schema.pm                          |  1 +
 FS/FS/access_user.pm                     | 40 ++++++++++++++++++++++++++++++++
 debian/control                           |  2 +-
 httemplate/browse/access_user.html       | 25 ++++++++++++++++----
 httemplate/edit/process/access_user.html |  2 +-
 httemplate/loginout/login.html           |  6 ++++-
 httemplate/pref/pref.html                | 12 ++++++++++
 httemplate/pref/set_totp_secret32.html   | 19 +++++++++++++++
 9 files changed, 102 insertions(+), 9 deletions(-)
 create mode 100644 httemplate/pref/set_totp_secret32.html




More information about the freeside-commits mailing list