diff --git a/html/captive-portal/templates/mfa/TOTP.html b/html/captive-portal/templates/mfa/TOTP.html index 145d4bfe99e3..b837382617ed 100644 --- a/html/captive-portal/templates/mfa/TOTP.html +++ b/html/captive-portal/templates/mfa/TOTP.html @@ -6,7 +6,7 @@
- +
+ + [% END %] [% IF exist %] diff --git a/html/common/qrcode.js b/html/common/qrcode.js index 0cfa61a8977c..eeb637ff3f5a 100644 --- a/html/common/qrcode.js +++ b/html/common/qrcode.js @@ -4,5 +4,8 @@ document.addEventListener('DOMContentLoaded', function () { const qrcode = document.getElementById('qrcode'); const otp = qrcode.getAttribute('data-otp'); const username = qrcode.getAttribute('data-username'); - new QRCode(qrcode, `otpauth://totp/${username}.packetfence?secret=${otp}`); + const digits = qrcode.getAttribute('data-digits'); + const period = qrcode.getAttribute('data-period'); + const suffix = qrcode.getAttribute('data-suffix'); + new QRCode(qrcode, `otpauth://totp/${username}.${suffix}?secret=${otp}&digits=${digits}&period=${period}`); }); diff --git a/html/pfappserver/lib/pfappserver/Form/Config/Mfa/TOTP.pm b/html/pfappserver/lib/pfappserver/Form/Config/Mfa/TOTP.pm index 717eb89089bb..f92e5097f005 100644 --- a/html/pfappserver/lib/pfappserver/Form/Config/Mfa/TOTP.pm +++ b/html/pfappserver/lib/pfappserver/Form/Config/Mfa/TOTP.pm @@ -42,9 +42,36 @@ has_field 'radius_mfa_method' => default => 'strip-otp', ); +has_field 'period' => + ( + type => 'Duration', + default => { + interval => 30, + unit => 's', + }, + ); + +has_field 'token_size' => + ( + type => 'IntRange', + label => 'Token size', + required => 1, + default => 6, + range_start => 1, + range_end => 10, + ); + +has_field 'suffix' => + ( + type => 'Text', + required => 1, + default => 'packetfence', + messages => { required => 'Please specify the suffix that will be added to the username' }, + ); + has_block definition => ( - render_list => [ qw(id radius_mfa_method) ], + render_list => [ qw(id radius_mfa_method period token_size suffix) ], ); =over diff --git a/html/pfappserver/root/src/views/Configuration/mfas/_components/FormTypeTOTP.vue b/html/pfappserver/root/src/views/Configuration/mfas/_components/FormTypeTOTP.vue index 253927a8cef5..cc02ad8fc6b2 100644 --- a/html/pfappserver/root/src/views/Configuration/mfas/_components/FormTypeTOTP.vue +++ b/html/pfappserver/root/src/views/Configuration/mfas/_components/FormTypeTOTP.vue @@ -15,6 +15,11 @@ :text="$i18n.t('Define the method to be used in RADIUS to trigger OTP.')" /> + + + + + + (is => 'rw' ); +=head2 token_size + +Size of the token + +=cut + +has token_size => (is => 'rw' ); + +=head2 period + +Period of time to generate the token + +=cut + +has period => (is => 'rw' ); + + +=head2 suffix + +Suffix added to the username + +=cut + +has suffix => (is => 'rw' ); + sub module_description { 'Generic TOTP MFA' } =head2 check_user @@ -52,7 +77,8 @@ sub check_user { my $logger = get_logger(); my $message; if ($self->radius_mfa_method eq 'strip-otp' || $self->radius_mfa_method eq 'second-password') { - if ($otp =~ /^\d{6,6}$/) { + my $token_size = self->token_size; + if ($otp =~ /^\d{$token_size,$token_size}$/) { return $self->verify_otp($username, $otp); } else { $message = "Method not supported for user $username"; @@ -87,7 +113,7 @@ sub verify_otp { sub generateCurrentNumber { my ($self, $otp) = @_; - my $paddedTime = sprintf("%016x", int(time() / 30)); + my $paddedTime = sprintf("%016x", int(time() / normalize_time($self->period))); my $data = pack('H*', $paddedTime); my $key = $self->decodeBase32($otp); @@ -95,10 +121,10 @@ sub generateCurrentNumber { my $offset = hex(substr($hmac, -1)); my $encrypted = hex(substr($hmac, $offset * 2, 8)) & 0x7fffffff; - - my $token = $encrypted % 1000000; - return sprintf("%06d", $token); - + my $div = '1'. '0' x $self->token_size; + my $token = $encrypted % $div; + my $token_size = '%0' . $self->token_size . 'd'; + return sprintf($token_size, $token); } sub decodeBase32 { @@ -130,7 +156,10 @@ sub redirect_info { return { exist => $exist, username => $username, - otp => $otp + otp => $otp, + period => normalize_time($self->period), + token_size => $self->token_size, + suffix => $self->suffix, }; }