View | Details | Raw Unified | Return to bug 27587
Collapse All | Expand All

(-)a/t/db_dependent/api/v1/patrons_password.t (-156 / +106 lines)
Lines 20-26 use Modern::Perl; Link Here
20
use Test::More tests => 2;
20
use Test::More tests => 2;
21
21
22
use Test::Mojo;
22
use Test::Mojo;
23
use Test::Warn;
24
23
25
use t::lib::TestBuilder;
24
use t::lib::TestBuilder;
26
use t::lib::Mocks;
25
use t::lib::Mocks;
Lines 30-41 use Koha::Patrons; Link Here
30
my $schema  = Koha::Database->new->schema;
29
my $schema  = Koha::Database->new->schema;
31
my $builder = t::lib::TestBuilder->new;
30
my $builder = t::lib::TestBuilder->new;
32
31
33
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
32
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
34
# this affects the other REST api tests
35
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
36
33
37
my $remote_address = '127.0.0.1';
34
my $t = Test::Mojo->new('Koha::REST::V1');
38
my $t              = Test::Mojo->new('Koha::REST::V1');
39
35
40
subtest 'set() (authorized user tests)' => sub {
36
subtest 'set() (authorized user tests)' => sub {
41
37
Lines 43-122 subtest 'set() (authorized user tests)' => sub { Link Here
43
39
44
    $schema->storage->txn_begin;
40
    $schema->storage->txn_begin;
45
41
46
    my ( $patron, $session ) = create_user_and_session({ authorized => 1 });
42
    my $privileged_patron = $builder->build_object(
43
        {
44
            class => 'Koha::Patrons',
45
            value => { flags => 1 }
46
        }
47
    );
48
    my $password = 'thePassword123';
49
    $privileged_patron->set_password(
50
        { password => $password, skip_validation => 1 } );
51
    my $userid = $privileged_patron->userid;
52
53
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
47
54
48
    t::lib::Mocks::mock_preference( 'minPasswordLength',     3 );
55
    t::lib::Mocks::mock_preference( 'minPasswordLength',     3 );
49
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
56
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
50
57
51
    my $new_password = 'abc';
58
    my $new_password = 'abc';
52
59
53
    my $tx
60
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
54
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
61
          . $patron->id
55
            . $patron->id
62
          . "/password" => json =>
56
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
63
          { password => $new_password, password_2 => $new_password } )
64
      ->status_is(200)->json_is('');
57
65
58
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
66
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
59
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
67
          . $patron->id
60
    $t->request_ok($tx)->status_is(200)->json_is( '' );
68
          . "/password" => json =>
61
69
          { password => $new_password, password_2 => 'cde' } )->status_is(400)
62
    $tx
70
      ->json_is( { error => 'Passwords don\'t match' } );
63
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
64
            . $patron->id
65
            . "/password" => json => { password => $new_password, password_2 => 'cde' } );
66
67
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
68
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
69
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Passwords don\'t match' });
70
71
71
    t::lib::Mocks::mock_preference( 'minPasswordLength', 5 );
72
    t::lib::Mocks::mock_preference( 'minPasswordLength', 5 );
72
    $tx
73
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
74
            . $patron->id
75
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
76
73
77
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
74
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
78
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
75
          . $patron->id
79
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Password length (3) is shorter than required (5)' });
76
          . "/password" => json =>
77
          { password => $new_password, password_2 => $new_password } )
78
      ->status_is(400)
79
      ->json_is(
80
        { error => 'Password length (3) is shorter than required (5)' } );
80
81
81
    $new_password = 'abc   ';
82
    $new_password = 'abc   ';
82
    $tx
83
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
83
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
84
          . $patron->id
84
            . $patron->id
85
          . "/password" => json =>
85
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
86
          { password => $new_password, password_2 => $new_password } )
86
87
      ->status_is(400)->json_is(
87
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
88
        {
88
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
89
            error =>
89
    $t->request_ok($tx)->status_is(400)->json_is({ error => '[Password contains leading/trailing whitespace character(s)]' });
90
              '[Password contains leading/trailing whitespace character(s)]'
91
        }
92
      );
90
93
91
    $new_password = 'abcdefg';
94
    $new_password = 'abcdefg';
92
    $tx
95
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
93
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
96
          . $patron->id
94
            . $patron->id
97
          . "/password" => json =>
95
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
98
          { password => $new_password, password_2 => $new_password } )
96
99
      ->status_is(200)->json_is('');
97
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
100
98
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
101
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 1 );
99
    $t->request_ok($tx)->status_is(200)->json_is('');
102
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
100
103
          . $patron->id
101
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 1);
104
          . "/password" => json =>
102
    $tx
105
          { password => $new_password, password_2 => $new_password } )
103
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
106
      ->status_is(400)->json_is( { error => '[Password is too weak]' } );
104
            . $patron->id
105
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
106
107
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
108
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
109
    $t->request_ok($tx)->status_is(400)->json_is({ error => '[Password is too weak]' });
110
107
111
    $new_password = 'ABcde123%&';
108
    $new_password = 'ABcde123%&';
112
    $tx
109
    $t->post_ok( "//$userid:$password@/api/v1/patrons/"
113
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
110
          . $patron->id
114
            . $patron->id
111
          . "/password" => json =>
115
            . "/password" => json => { password => $new_password, password_2 => $new_password } );
112
          { password => $new_password, password_2 => $new_password } )
116
113
      ->status_is(200)->json_is('');
117
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
118
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
119
    $t->request_ok($tx)->status_is(200)->json_is('');
120
114
121
    $schema->storage->txn_rollback;
115
    $schema->storage->txn_rollback;
122
};
116
};
Lines 127-134 subtest 'set_public() (unprivileged user tests)' => sub { Link Here
127
121
128
    $schema->storage->txn_begin;
122
    $schema->storage->txn_begin;
129
123
130
    my ( $patron, $session ) = create_user_and_session({ authorized => 0 });
124
    my $patron   = $builder->build_object( { class => 'Koha::Patrons' } );
131
    my $other_patron = $builder->build_object({ class => 'Koha::Patrons' });
125
    my $password = 'thePassword123';
126
    $patron->set_password( { password => $password, skip_validation => 1 } );
127
    my $userid       = $patron->userid;
128
    my $other_patron = $builder->build_object( { class => 'Koha::Patrons' } );
132
129
133
    # Enable the public API
130
    # Enable the public API
134
    t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
131
    t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
Lines 139-256 subtest 'set_public() (unprivileged user tests)' => sub { Link Here
139
136
140
    my $new_password = 'abc';
137
    my $new_password = 'abc';
141
138
142
    my $tx = $t->ua->build_tx(
139
    $t->post_ok(
143
              POST => "/api/v1/public/patrons/"
140
            "//$userid:$password@/api/v1/public/patrons/"
144
            . $patron->id
141
          . $patron->id
145
            . "/password" => json => {
142
          . "/password" => json => {
146
            password          => $new_password,
143
            password          => $new_password,
147
            password_repeated => $new_password,
144
            password_repeated => $new_password,
148
            old_password      => 'blah'
145
            old_password      => 'blah'
149
            }
146
          }
147
    )->status_is(403)->json_is(
148
        {
149
            error =>
150
              'Configuration prevents password changes by unprivileged users'
151
        }
150
    );
152
    );
151
153
152
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
153
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
154
    $t->request_ok($tx)
155
      ->status_is(403)
156
      ->json_is({
157
          error => 'Configuration prevents password changes by unprivileged users'
158
        });
159
160
    t::lib::Mocks::mock_preference( 'OpacPasswordChange', 1 );
154
    t::lib::Mocks::mock_preference( 'OpacPasswordChange', 1 );
161
155
162
    my $password = 'holapassword';
156
    $t->post_ok(
163
    $patron->set_password({ password => $password });
157
            "//$userid:$password@/api/v1/public/patrons/"
164
    $tx = $t->ua->build_tx(
158
          . $other_patron->id
165
              POST => "/api/v1/public/patrons/"
159
          . "/password" => json => {
166
            . $other_patron->id
167
            . "/password" => json => {
168
            password          => $new_password,
160
            password          => $new_password,
169
            password_repeated => $new_password,
161
            password_repeated => $new_password,
170
            old_password      => $password
162
            old_password      => $password
171
            }
163
          }
172
    );
164
    )->status_is(403)
173
165
      ->json_is( '/error',
174
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
166
        "Authorization failure. Missing required permission(s)." );
175
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
167
176
    $t->request_ok($tx)
168
    $t->post_ok(
177
      ->status_is(403)
169
            "//$userid:$password@/api/v1/public/patrons/"
178
      ->json_is('/error', "Authorization failure. Missing required permission(s).");
170
          . $patron->id
179
171
          . "/password" => json => {
180
    $tx = $t->ua->build_tx(
181
              POST => "/api/v1/public/patrons/"
182
            . $patron->id
183
            . "/password" => json => {
184
            password          => $new_password,
172
            password          => $new_password,
185
            password_repeated => 'wrong_password',
173
            password_repeated => 'wrong_password',
186
            old_password      => $password
174
            old_password      => $password
187
            }
175
          }
176
    )->status_is(400)->json_is(
177
        {
178
            error => "Passwords don't match"
179
        }
188
    );
180
    );
189
181
190
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
182
    $t->post_ok(
191
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
183
            "//$userid:$password@/api/v1/public/patrons/"
192
    $t->request_ok($tx)
184
          . $patron->id
193
      ->status_is(400)
185
          . "/password" => json => {
194
      ->json_is({
195
          error => "Passwords don't match"
196
        });
197
198
    $tx = $t->ua->build_tx(
199
              POST => "/api/v1/public/patrons/"
200
            . $patron->id
201
            . "/password" => json => {
202
            password          => $new_password,
186
            password          => $new_password,
203
            password_repeated => $new_password,
187
            password_repeated => $new_password,
204
            old_password      => 'badpassword'
188
            old_password      => 'badpassword'
205
            }
189
          }
190
    )->status_is(400)->json_is(
191
        {
192
            error => "Invalid password"
193
        }
206
    );
194
    );
207
195
208
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
196
    $t->post_ok(
209
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
197
            "//$userid:$password@/api/v1/public/patrons/"
210
    $t->request_ok($tx)
198
          . $patron->id
211
      ->status_is(400)
199
          . "/password" => json => {
212
      ->json_is({
213
          error => "Invalid password"
214
        });
215
216
    $tx = $t->ua->build_tx(
217
              POST => "/api/v1/public/patrons/"
218
            . $patron->id
219
            . "/password" => json => {
220
            password          => $new_password,
200
            password          => $new_password,
221
            password_repeated => $new_password,
201
            password_repeated => $new_password,
222
            old_password      => $password
202
            old_password      => $password
223
            }
203
          }
224
    );
204
    )->status_is(200)->json_is('');
225
226
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
227
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
228
    $t->request_ok($tx)
229
      ->status_is(200)
230
      ->json_is('');
231
205
232
    $schema->storage->txn_rollback;
206
    $schema->storage->txn_rollback;
233
};
207
};
234
235
sub create_user_and_session {
236
237
    my ( $args ) = @_;
238
    my $flags = ( $args->{authorized} ) ? 16 : 0;
239
240
    my $user = $builder->build_object(
241
        {
242
            class => 'Koha::Patrons',
243
            value => { flags => $flags }
244
        }
245
    );
246
247
    # Create a session for the authorized user
248
    my $session = C4::Auth::get_session('');
249
    $session->param( 'number',   $user->borrowernumber );
250
    $session->param( 'id',       $user->userid );
251
    $session->param( 'ip',       '127.0.0.1' );
252
    $session->param( 'lasttime', time() );
253
    $session->flush;
254
255
    return ( $user, $session );
256
}
257
- 

Return to bug 27587