From 373dd4c202c648a6a95a817568f8999cd112f6c5 Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Mon, 9 Oct 2017 12:38:59 +0200 Subject: [PATCH] TT#21818 Check passwords against libcrack and user * When enabling password_sip/web_validate, panel checks password against username (web and sip, respectively), and runs it through cracklib to enforce a reasonably strong password. * Add auto-generate buttons next to web/sip password. Change-Id: I11f5f6c2d69dc5658f298094f7d17d26d0a26ee1 --- debian/control | 2 ++ lib/NGCP/Panel/Utils/Form.pm | 28 ++++++++++++++++++++++++++++ sandbox/cracklib.pl | 17 +++++++++++++++++ share/static/js/libs/ngcp-pwdgen.js | 25 +++++++++++++++++++++++++ share/templates/customer/details.tt | 1 + share/templates/subscriber/master.tt | 2 ++ 6 files changed, 75 insertions(+) create mode 100755 sandbox/cracklib.pl create mode 100644 share/static/js/libs/ngcp-pwdgen.js diff --git a/debian/control b/debian/control index f2ab2073e2..6606baee71 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Homepage: https://www.sipwise.com/ Package: ngcp-panel Architecture: all Depends: + cracklib-runtime, gettext, ghostscript, gnutls-bin, @@ -26,6 +27,7 @@ Depends: libcatalyst-view-tt-perl, libconfig-general-perl, libconvert-ascii85-perl, + libcrypt-cracklib-perl, libcrypt-eksblowfish-perl, libcrypt-jwt-perl, libcrypt-rc4-perl, diff --git a/lib/NGCP/Panel/Utils/Form.pm b/lib/NGCP/Panel/Utils/Form.pm index 70003a8e5d..f768509302 100644 --- a/lib/NGCP/Panel/Utils/Form.pm +++ b/lib/NGCP/Panel/Utils/Form.pm @@ -1,6 +1,7 @@ package NGCP::Panel::Utils::Form; use Sipwise::Base; +use Crypt::Cracklib; sub validate_password { my %params = @_; @@ -30,6 +31,33 @@ sub validate_password { if($r->{password_musthave_specialchar} && $pass !~ /[^0-9a-zA-Z]/) { $field->add_error($c->loc('Must contain special characters')); } + if($field->name eq "password" && $r->{password_sip_validate}) { + my $user; + if($field->form->field('username')) { + $user = $field->form->field('username')->value; + } elsif($c->stash->{subscriber}) { + $user = $c->stash->{subscriber}->provisioning_voip_subscriber->username; + } + if(defined $user && $pass =~ /$user/i) { + $field->add_error($c->loc('Password must not contain username')); + } + unless(Crypt::Cracklib::check($pass)) { + $field->add_error($c->loc('Password is too weak')); + } + } elsif($field->name eq "webpassword" && $r->{password_web_validate}) { + my $user; + if($field->form->field('webusername')) { + $user = $field->form->field('webusername')->value; + } elsif($c->stash->{subscriber}) { + $user = $c->stash->{subscriber}->provisioning_voip_subscriber->webusername; + } + if(defined $user && $pass =~ /$user/i) { + $field->add_error($c->loc('Web password must not contain username')); + } + unless(Crypt::Cracklib::check($pass)) { + $field->add_error($c->loc('Web password is too weak')); + } + } } sub validate_entities { diff --git a/sandbox/cracklib.pl b/sandbox/cracklib.pl new file mode 100755 index 0000000000..3ea6e307d4 --- /dev/null +++ b/sandbox/cracklib.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl +use strict; +use warnings; +use English; + +use Crypt::Cracklib; + +my $pass = $ARGV[0]; +unless(defined $pass) { + die "Usage: $PROGRAM_NAME \n"; +} + +if(check($pass, undef)) { + print "Password ok\n"; +} else { + print "Password NOT ok\n"; +} diff --git a/share/static/js/libs/ngcp-pwdgen.js b/share/static/js/libs/ngcp-pwdgen.js new file mode 100644 index 0000000000..28d0a1e4ef --- /dev/null +++ b/share/static/js/libs/ngcp-pwdgen.js @@ -0,0 +1,25 @@ + function generate_password(len) { + var text = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?/-_%$()[]"; + for (var i = 0; i < len; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } + $(document).ready(function() { + var btn = '
Generate
'; + + var passwd_btn = $(btn); + passwd_btn.click(function() { + $('input#password').val(generate_password(16)); + }); + $('input#password').attr("style", "width: 80% !important"); + $('input#password').after(passwd_btn); + + var webpasswd_btn = $(btn); + webpasswd_btn.click(function() { + $('input#webpassword').val(generate_password(16)); + }); + $('input#webpassword').attr("style", "width: 80% !important"); + $('input#webpassword').after(webpasswd_btn); + }); diff --git a/share/templates/customer/details.tt b/share/templates/customer/details.tt index 8316197457..c8b3ef3ca2 100644 --- a/share/templates/customer/details.tt +++ b/share/templates/customer/details.tt @@ -731,6 +731,7 @@ $(function() { modal_footer(); modal_script(m.close_target = close_target); -%] + [% ELSIF edit_flag == 1 -%] [% IF form.has_for_js; diff --git a/share/templates/subscriber/master.tt b/share/templates/subscriber/master.tt index bc6683fa8d..613578fa05 100644 --- a/share/templates/subscriber/master.tt +++ b/share/templates/subscriber/master.tt @@ -347,6 +347,8 @@ function process_pbx_items(moveId,direction){ modal_footer(); modal_script(m.close_target = close_target); -%] + + [% END -%]