From: Jonathan Prykop Date: Mon, 7 Dec 2015 23:46:45 +0000 (-0600) Subject: RT#29354: Password Security in Email [v3 merge] X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=6f1a71826d05033213bda352f8c6753094093f56 RT#29354: Password Security in Email [v3 merge] --- diff --git a/FS/FS/Password_Mixin.pm b/FS/FS/Password_Mixin.pm index 327eda86c..eb1db81e8 100644 --- a/FS/FS/Password_Mixin.pm +++ b/FS/FS/Password_Mixin.pm @@ -69,6 +69,29 @@ sub is_password_allowed { return '' unless $self->get($self->primary_key); # for validating new passwords pre-insert + #check against customer fields + my $cust_main = $self->cust_main; + if ($cust_main) { + my @words; + # words from cust_main + foreach my $field ( qw( last first daytime night fax mobile ) ) { + push @words, split(/\W/,$cust_main->get($field)); + } + # words from cust_location + foreach my $loc ($cust_main->cust_location) { + foreach my $field ( qw(address1 address2 city county state zip) ) { + push @words, split(/\W/,$loc->get($field)); + } + } + # do the actual checking + foreach my $word (@words) { + next unless length($word) > 2; + if ($password =~ /$word/i) { + return qq(Password contains account information '$word'); + } + } + } + if ( $conf->config('password-no_reuse') =~ /^(\d+)$/ ) { my $no_reuse = $1; diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index e963c8082..203150f7c 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -2785,6 +2785,7 @@ sub password_svc_check { my ($self, $password) = @_; foreach my $field ( qw(username finger) ) { foreach my $word (split(/\W+/,$self->get($field))) { + next unless length($word) > 2; if ($password =~ /$word/i) { return qq(Password contains account information '$word'); } diff --git a/fs_selfservice/FS-SelfService/cgi/add_password_validation.html b/fs_selfservice/FS-SelfService/cgi/add_password_validation.html deleted file mode 100644 index e349fd7ad..000000000 --- a/fs_selfservice/FS-SelfService/cgi/add_password_validation.html +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/fs_selfservice/FS-SelfService/cgi/add_password_validation.js b/fs_selfservice/FS-SelfService/cgi/add_password_validation.js new file mode 100644 index 000000000..e2e3227f1 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/add_password_validation.js @@ -0,0 +1,38 @@ +function add_password_validation (fieldid,nologin) { + var inputfield = document.getElementById(fieldid); + inputfield.onchange = function () { + var fieldid = this.id+'_result'; + var resultfield = document.getElementById(fieldid); + var svcnum = ''; + var svcfield = document.getElementById(this.id+'_svcnum'); + if (svcfield) { + svcnum = svcfield.options[svcfield.selectedIndex].value; + } + if (this.value) { + resultfield.innerHTML = 'Validating password...'; + var action = nologin ? 'validate_password_nologin' : 'validate_password'; + send_xmlhttp('selfservice.cgi', + ['action',action,'fieldid',fieldid,'svcnum',svcnum,'check_password',this.value], + function (result) { + result = JSON.parse(result); + var resultfield = document.getElementById(result.fieldid); + if (resultfield) { + var errorimg = ''; + var validimg = ''; + if (result.valid) { + resultfield.innerHTML = validimg+'Password valid!'; + } else if (result.error) { + resultfield.innerHTML = errorimg+''+result.error+''; + } else { + result.syserror = result.syserror || 'Server error'; + resultfield.innerHTML = errorimg+''+result.syserror+''; + } + } + } + ); + } else { + resultfield.innerHTML = ''; + } + }; +} + diff --git a/fs_selfservice/FS-SelfService/cgi/change_password.html b/fs_selfservice/FS-SelfService/cgi/change_password.html index ef665545a..879faf285 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_password.html +++ b/fs_selfservice/FS-SelfService/cgi/change_password.html @@ -28,11 +28,11 @@
-<%= include('send_xmlhttp') %> -<%= include('add_password_validation') %> - + + + diff --git a/fs_selfservice/FS-SelfService/cgi/images/error.png b/fs_selfservice/FS-SelfService/cgi/images/error.png new file mode 100644 index 000000000..628cf2dae Binary files /dev/null and b/fs_selfservice/FS-SelfService/cgi/images/error.png differ diff --git a/fs_selfservice/FS-SelfService/cgi/images/tick.png b/fs_selfservice/FS-SelfService/cgi/images/tick.png new file mode 100644 index 000000000..a9925a06a Binary files /dev/null and b/fs_selfservice/FS-SelfService/cgi/images/tick.png differ diff --git a/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html b/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html index ec672c8d5..da6fc8d29 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html +++ b/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html @@ -15,6 +15,7 @@ +
<%= if (!$error) { @@ -23,16 +24,27 @@ - + + + - - + + END @@ -40,6 +52,7 @@ END %>
New password: + + + + + + +
Re-enter new password:
+
<%= $body_footer %> diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index f6f3c21d1..eac5a9874 100755 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -94,6 +94,7 @@ my @nologin_actions = (qw( process_forgot_password do_process_forgot_password process_forgot_password_session + validate_password_nologin )); push @actions, @nologin_actions; my %nologin_actions = map { $_=>1 } @nologin_actions; @@ -1118,6 +1119,14 @@ sub validate_password { ) } +sub validate_password_nologin { + $action = 'validate_password'; #use same landing page + validate_passwd( + map { $_ => scalar($cgi->param($_)) } + qw( fieldid check_password ) + ) +} + #-- sub do_template { diff --git a/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html b/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html deleted file mode 100644 index ac85cb2f7..000000000 --- a/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html +++ /dev/null @@ -1,45 +0,0 @@ - - diff --git a/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js b/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js new file mode 100644 index 000000000..e2991684a --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js @@ -0,0 +1,43 @@ +function rs_init_object () { + var A; + try { + A=new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + A=new ActiveXObject("Microsoft.XMLHTTP"); + } catch (oc) { + A=null; + } + } + if(!A && typeof XMLHttpRequest != "undefined") + A = new XMLHttpRequest(); + if (!A) + alert("Can't create XMLHttpRequest object"); + return A; +} + +function send_xmlhttp (url,args,callback) { + args = args || []; + callback = callback || function (data) { return data }; + var content = ''; + for (var i = 0; i < args.length; i = i + 2) { + content = content + "&" + args[i] + "=" + escape(args[i+1]); + } + content = content.replace( /[+]/g, '%2B'); // fix unescaped plus signs + + var xmlhttp = rs_init_object(); + xmlhttp.open("POST", url, true); + + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState != 4) + return; + if (xmlhttp.status == 200) { + var data = xmlhttp.responseText; + callback(data); + } + }; + + xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + xmlhttp.send(content); +} + diff --git a/fs_selfservice/FS-SelfService/cgi/signup.cgi b/fs_selfservice/FS-SelfService/cgi/signup.cgi index 072ce96be..817fdd310 100755 --- a/fs_selfservice/FS-SelfService/cgi/signup.cgi +++ b/fs_selfservice/FS-SelfService/cgi/signup.cgi @@ -508,31 +508,3 @@ use FS::SelfService qw( regionselector expselect popselector domainselector didselector ); -sub add_password_validation { - my $fieldid = shift; - my $out = ''; - if ((-e './send_xmlhttp.html') && (-e './add_password_validation.html')) { - my $template = new Text::Template( TYPE => 'FILE', - SOURCE => "./send_xmlhttp.html", - DELIMITERS => [ '<%=', '%>' ], - UNTAINT => 1, - ) - or die $Text::Template::ERROR; - $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' ); - $template = new Text::Template( TYPE => 'FILE', - SOURCE => "./add_password_validation.html", - DELIMITERS => [ '<%=', '%>' ], - UNTAINT => 1, - ) - or die $Text::Template::ERROR; - $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' ); - $out .= < -add_password_validation('$fieldid'); - -ENDOUT - } - return $out; -} - - diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html index 5900ba689..def52991e 100755 --- a/fs_selfservice/FS-SelfService/cgi/signup.html +++ b/fs_selfservice/FS-SelfService/cgi/signup.html @@ -386,12 +386,12 @@ ENDOUT Password -
-ENDOUT - - $OUT .= add_password_validation('new_password'); - - $OUT .= < + + + diff --git a/httemplate/elements/validate_password.html b/httemplate/elements/validate_password.html index fd2cb6ca0..a488c4f16 100644 --- a/httemplate/elements/validate_password.html +++ b/httemplate/elements/validate_password.html @@ -32,13 +32,15 @@ function add_password_validation (fieldid) { result = JSON.parse(result); var resultfield = document.getElementById(result.fieldid); if (resultfield) { + var errorimg = ''; + var validimg = ''; if (result.valid) { - resultfield.innerHTML = 'Password valid!'; + resultfield.innerHTML = validimg+'Password valid!'; } else if (result.error) { - resultfield.innerHTML = ''+result.error+''; + resultfield.innerHTML = errorimg+''+result.error+''; } else { result.syserror = result.syserror || 'Server error'; - resultfield.innerHTML = ''+result.syserror+''; + resultfield.innerHTML = errorimg+''+result.syserror+''; } } }