]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1388148 - Test password quality checking code
authorDylan William Hardison <dylan@hardison.net>
Thu, 17 Aug 2017 22:29:49 +0000 (18:29 -0400)
committerGitHub <noreply@github.com>
Thu, 17 Aug 2017 22:29:49 +0000 (18:29 -0400)
.circleci/checksetup_answers.txt
.circleci/config.yml
Bugzilla/Test/Util.pm [new file with mode: 0644]
scripts/entrypoint.pl
scripts/generate_bmo_data.pl
t/bmo/passwords.t [new file with mode: 0644]

index 80a1d40d232abaf1dfecd925fd40f67a20f10605..bcdefa38e8856ee744e63b258a6c5b7ad0a1e7e7 100644 (file)
@@ -1,11 +1,13 @@
 $answer{'ADMIN_EMAIL'} = 'admin@mozilla.bugs';
 $answer{'ADMIN_OK'} = 'Y';
-$answer{'ADMIN_PASSWORD'} = 'password';
+$answer{'ADMIN_PASSWORD'} = 'passWord1234!';
 $answer{'ADMIN_REALNAME'} = 'QA Admin';
 $answer{'NO_PAUSE'} = 1;
 $answer{'bugzilla_version'} = '1';
 $answer{'create_htaccess'} = '1';
 $answer{'cvsbin'} = '/usr/bin/cvs';
+$answer{'password_complexity'} = 'bmo';
 $answer{'diffpath'} = '/usr/bin';
 $answer{'interdiffbin'} = '/usr/bin/interdiff';
 $answer{'urlbase'} = 'http://<<HOSTNAME>>:8000/';
+$answer{'mail_delivery_method'} = 'Test';
index 619f1cb11db7da49c6002ec79fed25a1ccc15186..cd2ec0e100dbb3a9b90d93b23a648e4a340d17d1 100644 (file)
@@ -120,13 +120,48 @@ jobs:
       - store_artifacts:
           path: /app/artifacts
 
+  test_bmo:
+    parallelism: 4
+    working_directory: /app
+    docker:
+      - <<: *bmo_slim_image
+        environment:
+          <<: *bmo_env
+          BZ_QA_ANSWERS_FILE:  /app/.circleci/checksetup_answers.txt
+          TWD_HOST: localhost
+          TWD_PORT: 4444
+          TWD_BROWSER: firefox
+      - <<: *mysql_image
+        environment: *mysql_env
+      - image: memcached:latest
+      - image: selenium/standalone-firefox:2.53.1
+    steps:
+      - checkout
+      - run: |
+          mv /opt/bmo/local /app/local
+          perl checksetup.pl --no-database --default-localconfig
+          perl -MSys::Hostname -i -pE 's/<<HOSTNAME>>/hostname()/ges' $BZ_QA_ANSWERS_FILE
+          rm -f /app/localconfig
+          /app/scripts/entrypoint.pl load_test_data
+          mkdir artifacts
+      - run: |
+          BZ_BASE_URL="http://$(hostname):$PORT"
+          export BZ_BASE_URL
+          rm -f /app/localconfig
+          /app/scripts/entrypoint.pl test_bmo -q -f t/bmo/*.t
+
+
+
 workflows:
   version: 2
   tests:
     jobs:
+      - test_bmo
       - test_sanity
       - test_webservices
-      - test_selenium
+      - test_selenium:
+          requires:
+            - test_bmo
       - build:
           requires:
             - test_sanity
diff --git a/Bugzilla/Test/Util.pm b/Bugzilla/Test/Util.pm
new file mode 100644 (file)
index 0000000..4c9981e
--- /dev/null
@@ -0,0 +1,32 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Test::Util;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use base qw(Exporter);
+our @EXPORT = qw(create_user);
+
+use Bugzilla::User;
+
+sub create_user {
+    my ($login, $password, %extra) = @_;
+    require Bugzilla;
+    return Bugzilla::User->create({
+        login_name    => $login,
+        cryptpassword => $password,
+        disabledtext  => "",
+        disable_mail  => 0,
+        extern_id     => 0,
+        %extra,
+    });
+}
+
+1;
index 2d1ef8fe9df586881b3d7599ffdf0598fb0c6504..c395511318a5988e433ee9915de3bdbe326b2644 100755 (executable)
@@ -3,16 +3,18 @@ use 5.10.1;
 use strict;
 use warnings;
 use lib qw(/app /app/local/lib/perl5);
+
 use Bugzilla::Install::Localconfig ();
 use Bugzilla::Install::Util qw(install_string);
+use Bugzilla::Test::Util qw(create_user);
 use DBI;
 use Data::Dumper;
 use English qw($EUID);
 use File::Copy::Recursive qw(dircopy);
 use Getopt::Long qw(:config gnu_getopt);
 use LWP::Simple qw(get);
-use User::pwent;
 use POSIX qw(WEXITSTATUS setsid);
+use User::pwent;
 
 use IO::Async::Loop;
 use IO::Async::Process;
@@ -53,7 +55,7 @@ sub cmd_load_test_data {
         run( 'perl', 'generate_test_data.pl' );
     }
     else {
-        run( 'perl', 'scripts/generate_bmo_data.pl' );
+        run( 'perl', 'scripts/generate_bmo_data.pl', '--param' => 'use_mailer_queue=0' );
     }
 }
 
@@ -76,6 +78,8 @@ sub cmd_test_webservices {
     my $conf = require $ENV{BZ_QA_CONF_FILE};
 
     check_data_dir();
+    wait_for_db();
+
     my @httpd_cmd = ( '/usr/sbin/httpd', '-DFOREGROUND', '-f', '/app/httpd/httpd.conf' );
     if ($ENV{BZ_QA_LEGACY_MODE}) {
         copy_qa_extension();
@@ -98,6 +102,7 @@ sub cmd_test_selenium {
     my $conf = require $ENV{BZ_QA_CONF_FILE};
 
     check_data_dir();
+    wait_for_db();
     my @httpd_cmd = ( '/usr/sbin/httpd', '-DFOREGROUND', '-f', '/app/httpd/httpd.conf' );
     if ($ENV{BZ_QA_LEGACY_MODE}) {
         copy_qa_extension();
@@ -121,6 +126,16 @@ sub cmd_prove   { run( "prove", "-I/app", "-I/app/local/lib/perl5", @_ ); }
 sub cmd_version { run( 'cat',   '/app/version.json' ); }
 
 sub cmd_test_bmo {
+    check_data_dir();
+    wait_for_db();
+
+    $ENV{BZ_TEST_NEWBIE} = 'newbie@mozilla.example';
+    $ENV{BZ_TEST_NEWBIE_PASS} = 'captain.space.bagel.ROBOT!';
+    create_user($ENV{BZ_TEST_NEWBIE}, $ENV{BZ_TEST_NEWBIE_PASS}, realname => "Newbie User");
+
+    $ENV{BZ_TEST_NEWBIE2} = 'newbie2@mozilla.example';
+    $ENV{BZ_TEST_NEWBIE2_PASS} = 'captain.space.pants.time.lord';
+
     prove_with_httpd(
         httpd_url => $ENV{BZ_BASE_URL},
         httpd_cmd => [ '/usr/sbin/httpd', '-f', '/app/httpd/httpd.conf',  '-DFOREGROUND' ],
@@ -131,9 +146,6 @@ sub cmd_test_bmo {
 sub prove_with_httpd {
     my (%param) = @_;
 
-    check_data_dir();
-    wait_for_db();
-
     unless (-d "/app/logs") {
         mkdir("/app/logs") or die "unable to mkdir(/app/logs): $!\n";
     }
index 788227443a3cdc6e044bf744badfb74437272ac3..b2df7ddbad76e96d9cf0f1394e640f961d034ee4 100755 (executable)
@@ -63,7 +63,8 @@ my %user_prefs = (
     zoom_textareas         => 'off',
 );
 
-GetOptions('user-pref=s%' => \%user_prefs);
+my %opt_param;
+GetOptions('user-pref=s%' => \%user_prefs, 'param=s' => \%opt_param);
 
 my $admin_email = shift || 'admin@mozilla.bugs';
 Bugzilla->set_user(Bugzilla::User->check({ name => $admin_email }));
@@ -496,6 +497,7 @@ my %set_params = (
     use_mailer_queue          => 1,
     user_info_class           => 'GitHubAuth,CGI',
     user_verify_class         => 'GitHubAuth,DB',
+    %opt_param,
 );
 
 my $params_modified;
diff --git a/t/bmo/passwords.t b/t/bmo/passwords.t
new file mode 100644 (file)
index 0000000..d10eddf
--- /dev/null
@@ -0,0 +1,260 @@
+#!/usr/bin/env perl
+use 5.10.1;
+use strict;
+use warnings;
+use autodie;
+use constant DRIVER => 'Test::Selenium::Remote::Driver';
+
+use Test::More 1.302;
+#use constant DRIVER => 'Test::Selenium::Chrome';
+BEGIN { plan skip_all => "these tests only run in CI" unless $ENV{CI} && $ENV{CIRCLE_JOB} eq 'test_bmo' };
+
+use ok DRIVER;
+
+my $ADMIN_LOGIN  = $ENV{BZ_TEST_ADMIN} // 'admin@mozilla.bugs';
+my $ADMIN_PW_OLD = $ENV{BZ_TEST_ADMIN_PASS} // 'passWord1234!';
+my $ADMIN_PW_NEW = $ENV{BZ_TEST_ADMIN_NEWPASS} // 'she7Ka8t';
+
+my @require_env = qw(
+    BZ_BASE_URL
+    BZ_TEST_NEWBIE
+    BZ_TEST_NEWBIE_PASS
+);
+
+if (DRIVER =~ /Remote/) {
+    push @require_env, qw( TWD_HOST TWD_PORT );
+}
+my @missing_env = grep { ! exists $ENV{$_} } @require_env;
+BAIL_OUT("Missing env: @missing_env") if @missing_env;
+
+eval {
+    my $sel = DRIVER->new(base_url => $ENV{BZ_BASE_URL});
+    $sel->set_implicit_wait_timeout(600);
+
+    login_ok($sel, $ADMIN_LOGIN, $ADMIN_PW_OLD);
+
+    change_password($sel, $ADMIN_PW_OLD, 'newpassword', 'newpassword2');
+    $sel->title_is("Passwords Don't Match");
+    $sel->body_text_contains('The two passwords you entered did not match.');
+
+    change_password($sel, $ADMIN_PW_OLD . "x", "newpassword2", "newpassword2");
+    $sel->title_is("Incorrect Old Password");
+
+    change_password($sel, $ADMIN_PW_OLD, "password", "password");
+    $sel->title_is("Password Fails Requirements");
+
+    change_password($sel, $ADMIN_PW_OLD, $ADMIN_PW_NEW, $ADMIN_PW_NEW);
+    $sel->title_is("User Preferences");
+    logout_ok($sel);
+
+    login_ok($sel, $ADMIN_LOGIN, $ADMIN_PW_NEW);
+
+    # we don't protect against password re-use
+    change_password($sel, $ADMIN_PW_NEW, $ADMIN_PW_OLD, $ADMIN_PW_OLD);
+    $sel->title_is("User Preferences");
+    logout_ok($sel);
+
+    login_ok($sel, $ENV{BZ_TEST_NEWBIE}, $ENV{BZ_TEST_NEWBIE_PASS});
+
+    $sel->get_ok("/editusers.cgi");
+    $sel->title_is("Authorization Required");
+    logout_ok($sel);
+
+    login_ok($sel, $ADMIN_LOGIN, $ADMIN_PW_OLD);
+
+    toggle_require_password_change($sel, $ENV{BZ_TEST_NEWBIE});
+    logout_ok($sel);
+
+    login($sel, $ENV{BZ_TEST_NEWBIE}, $ENV{BZ_TEST_NEWBIE_PASS});
+    $sel->title_is('Password change required');
+    click_and_type($sel, "old_password", $ENV{BZ_TEST_NEWBIE_PASS});
+    click_and_type($sel, "new_password1", "password");
+    click_and_type($sel, "new_password2", "password");
+    submit($sel, '//input[@id="submit"]');
+    $sel->title_is('Password Fails Requirements');
+
+    $sel->go_back_ok();
+    $sel->title_is('Password change required');
+    click_and_type($sel, "old_password", $ENV{BZ_TEST_NEWBIE_PASS});
+    click_and_type($sel, "new_password1", "!!" . $ENV{BZ_TEST_NEWBIE_PASS});
+    click_and_type($sel, "new_password2", "!!" . $ENV{BZ_TEST_NEWBIE_PASS});
+    submit($sel, '//input[@id="submit"]');
+    $sel->title_is('Password Changed');
+    change_password(
+        $sel,
+        "!!" . $ENV{BZ_TEST_NEWBIE_PASS},
+        $ENV{BZ_TEST_NEWBIE_PASS},
+        $ENV{BZ_TEST_NEWBIE_PASS}
+    );
+    $sel->title_is("User Preferences");
+
+    $sel->get_ok("/userprefs.cgi?tab=account");
+    $sel->title_is("User Preferences");
+    click_link($sel, "I forgot my password");
+    $sel->body_text_contains(
+        ["A token for changing your password has been emailed to you.",
+         "Follow the instructions in that email to change your password."],
+    );
+    my $token = get_token();
+    ok($token, "got a token from resetting password");
+    $sel->get_ok("/token.cgi?t=$token&a=cfmpw");
+    $sel->title_is('Change Password');
+    click_and_type($sel, "password", "nopandas");
+    click_and_type($sel, "matchpassword", "nopandas");
+    submit($sel, '//input[@id="update"]');
+    $sel->title_is('Password Fails Requirements');
+    $sel->go_back_ok();
+    $sel->title_is('Change Password');
+    click_and_type($sel, "password", '??' . $ENV{BZ_TEST_NEWBIE_PASS});
+    click_and_type($sel, "matchpassword", '??' . $ENV{BZ_TEST_NEWBIE_PASS});
+    submit($sel, '//input[@id="update"]');
+    $sel->title_is('Password Changed');
+    $sel->get_ok("/token.cgi?t=$token&a=cfmpw");
+    $sel->title_is('Token Does Not Exist');
+    $sel->get_ok("/login");
+    $sel->title_is('Log in to Bugzilla');
+    login_ok($sel, $ENV{BZ_TEST_NEWBIE}, "??" . $ENV{BZ_TEST_NEWBIE_PASS});
+    change_password(
+        $sel,
+        "??" . $ENV{BZ_TEST_NEWBIE_PASS},
+        $ENV{BZ_TEST_NEWBIE_PASS},
+        $ENV{BZ_TEST_NEWBIE_PASS}
+    );
+    $sel->title_is("User Preferences");
+
+    logout_ok($sel);
+    open my $fh, '>', '/app/data/mailer.testfile';
+    close $fh;
+
+    $sel->get('/createaccount.cgi');
+    $sel->title_is('Create a new Bugzilla account');
+    click_and_type($sel, 'login', $ENV{BZ_TEST_NEWBIE2});
+    $sel->find_element('//input[@id="etiquette"]', 'xpath')->click();
+    submit($sel, '//input[@value="Create Account"]');
+    $sel->title_is("Request for new user account '$ENV{BZ_TEST_NEWBIE2}' submitted");
+    my ($create_token) = search_mailer_testfile(
+        qr{/token\.cgi\?t=([^&]+)&a=request_new_account}xs
+    );
+    $sel->get("/token.cgi?t=$create_token&a=request_new_account");
+    click_and_type($sel, 'passwd1', $ENV{BZ_TEST_NEWBIE2_PASS});
+    click_and_type($sel, 'passwd2', $ENV{BZ_TEST_NEWBIE2_PASS});
+    submit($sel, '//input[@value="Create"]');
+
+    $sel->title_is('Bugzilla Main Page');
+    $sel->body_text_contains(
+        ["The user account $ENV{BZ_TEST_NEWBIE2} has been created",
+         "successfully"]
+    );
+};
+if ($@) {
+    fail("got exception $@");
+}
+done_testing();
+
+sub submit {
+    my ($sel, $xpath) = @_;
+    $sel->find_element($xpath, 'xpath')->submit();
+}
+
+sub get_token {
+    my $token;
+    my $count = 0;
+    do {
+        sleep 1 if $count++;
+        open my $fh, '<', '/app/data/mailer.testfile';
+        my $content = do {
+            local $/ = undef;
+            <$fh>;
+        };
+        ($token) = $content =~ m!/token\.cgi\?t=3D([^&]+)&a=3Dcfmpw!s;
+        close $fh;
+    } until $token || $count > 60;
+    return $token;
+}
+
+sub search_mailer_testfile {
+    my ($regexp) = @_;
+    my $content = "";
+    my @result;
+    my $count = 0;
+    do {
+        sleep 1 if $count++;
+        open my $fh, '<', '/app/data/mailer.testfile';
+        $content .= do {
+            local $/ = undef;
+            <$fh>;
+        };
+        close $fh;
+        my $decoded = $content;
+        $decoded =~ s/\r\n/\n/gs;
+        $decoded =~ s/=\n//gs;
+        $decoded =~ s/=([[:xdigit:]]{2})/chr(hex($1))/ges;
+        @result = $decoded =~ $regexp;
+    } until @result || $count > 60;
+    return @result;
+}
+
+sub click_and_type {
+    my ($sel, $name, $text) = @_;
+
+    eval {
+        my $el = $sel->find_element(qq{//input[\@name="$name"]}, 'xpath');
+        $el->click();
+        $sel->send_keys_to_active_element($text);
+        pass("found $name and typed $text");
+    };
+    if ($@) {
+        fail("failed to find $name");
+    }
+}
+
+sub click_link {
+    my ($sel, $text) = @_;
+    my $el = $sel->find_element($text, 'link_text');
+    $el->click();
+}
+
+sub change_password {
+    my ($sel, $old, $new1, $new2) = @_;
+    $sel->get_ok("/userprefs.cgi?tab=account");
+    $sel->title_is("User Preferences");
+    click_and_type($sel, "old_password", $old);
+    click_and_type($sel, "new_password1", $new1);
+    click_and_type($sel, "new_password2", $new2);
+    submit($sel, '//input[@value="Submit Changes"]');
+}
+
+sub toggle_require_password_change {
+    my ($sel, $login) = @_;
+    $sel->get_ok("/editusers.cgi");
+    $sel->title_is("Search users");
+    click_and_type($sel, 'matchstr', $login);
+    submit($sel, '//input[@id="search"]');
+    $sel->title_is("Select user");
+    click_link($sel, $login);
+    $sel->find_element('//input[@id="password_change_required"]')->click;
+    submit($sel, '//input[@id="update"]');
+    $sel->title_is("User $login updated");
+}
+
+sub login {
+    my ($sel, $login, $password) = @_;
+
+    $sel->get_ok("/login");
+    $sel->title_is("Log in to Bugzilla");
+    click_and_type($sel, 'Bugzilla_login', $login);
+    click_and_type($sel, 'Bugzilla_password', $password);
+    submit($sel, '//input[@name="GoAheadAndLogIn"]');
+}
+
+sub login_ok {
+    my ($sel) = @_;
+    login(@_);
+    $sel->title_is('Bugzilla Main Page');
+}
+
+sub logout_ok {
+    my ($sel) = @_;
+    $sel->get_ok('/index.cgi?logout=1');
+    $sel->title_is("Logged Out");
+}