3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Test
::More tests
=> 4;
27 my $dbh = C4
::Context
->dbh;
29 $dbh->{ AutoCommit
} = 0;
30 $dbh->{ RaiseError
} = 1;
32 # Variables controlling LDAP server config
36 my $anonymous_bind = 1;
37 # Variables controlling LDAP behaviour
38 my $desired_authentication_result = 'success';
39 my $desired_connection_result = 'error';
40 my $desired_bind_result = 'error';
41 my $desired_compare_result = 'error';
42 my $desired_search_result = 'error';
43 my $desired_count_result = 1;
44 my $non_anonymous_bind_result = 'error';
47 # Mock the context module
48 my $context = new Test
::MockModule
( 'C4::Context' );
49 $context->mock( 'config', \
&mockedC4Config
);
51 # Mock the Net::LDAP module
52 my $ldap = new Test
::MockModule
( 'Net::LDAP' );
54 $ldap->mock( 'new', sub {
55 if ( $desired_connection_result eq 'error' ) {
56 # We were asked to fail the LDAP conexion
59 # Return a mocked Net::LDAP object (Test::MockObject)
60 return mock_net_ldap
();
65 # C4::Auth_with_ldap needs several stuff set first ^^^
66 use_ok
( 'C4::Auth_with_ldap' );
67 can_ok
( 'C4::Auth_with_ldap', qw
/
71 subtest
"checkpw_ldap tests" => sub {
75 ## Connection fail tests
76 $desired_connection_result = 'error';
77 warning_is
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
( $dbh, 'hola', password
=> 'hey' ) }
78 "LDAP connexion failed",
79 "checkpw_ldap prints correct warning if LDAP conexion fails";
80 is
( $ret, 0, "checkpw_ldap returns 0 if LDAP conexion fails");
82 ## Connection success tests
83 $desired_connection_result = 'success';
85 subtest
"auth_by_bind = 1 tests" => sub {
91 $desired_authentication_result = 'success';
93 $desired_bind_result = 'error';
94 $desired_search_result = 'error';
98 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
99 $dbh, 'hola', password
=> 'hey' ) }
100 qr/Anonymous LDAP bind failed: LDAP error #1: error_name/,
101 "checkpw_ldap prints correct warning if LDAP anonymous bind fails";
102 is
( $ret, 0, "checkpw_ldap returns 0 if LDAP anonymous bind fails");
104 $desired_authentication_result = 'success';
106 $desired_bind_result = 'success';
107 $desired_search_result = 'success';
108 $desired_count_result = 0; # user auth problem
109 $non_anonymous_bind_result = 'success';
110 reload_ldap_module
();
111 is
( C4
::Auth_with_ldap
::checkpw_ldap
( $dbh, 'hola', password
=> 'hey' ),
112 0, "checkpw_ldap returns 0 if user lookup returns 0");
114 $non_anonymous_bind_result = 'error';
115 reload_ldap_module
();
117 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
118 $dbh, 'hola', password
=> 'hey' ) }
119 qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
120 "checkpw_ldap prints correct warning if LDAP bind fails";
121 is
( $ret, -1, "checkpw_ldap returns -1 LDAP bind fails for user (Bug 8148)");
123 # regression tests for bug 12831
124 $desired_authentication_result = 'error';
126 $desired_bind_result = 'error';
127 $desired_search_result = 'success';
128 $desired_count_result = 0; # user auth problem
129 $non_anonymous_bind_result = 'error';
130 reload_ldap_module
();
132 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
133 $dbh, 'hola', password
=> 'hey' ) }
134 qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
135 "checkpw_ldap prints correct warning if LDAP bind fails";
136 is
( $ret, 0, "checkpw_ldap returns 0 LDAP bind fails for user (Bug 12831)");
140 subtest
"auth_by_bind = 0 tests" => sub {
148 $desired_bind_result = 'error';
149 $non_anonymous_bind_result = 'error';
150 reload_ldap_module
();
152 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
153 $dbh, 'hola', password
=> 'hey' ) }
154 qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
155 "checkpw_ldap prints correct warning if LDAP bind fails";
156 is
( $ret, 0, "checkpw_ldap returns 0 if bind fails");
159 $desired_bind_result = 'success';
160 $non_anonymous_bind_result = 'success';
161 $desired_compare_result = 'error';
162 reload_ldap_module
();
164 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
165 $dbh, 'hola', password
=> 'hey' ) }
166 qr/LDAP Auth rejected : invalid password for user 'hola'. LDAP error #1: error_name/,
167 "checkpw_ldap prints correct warning if LDAP bind fails";
168 is
( $ret, -1, "checkpw_ldap returns -1 if bind fails (Bug 8148)");
172 $desired_bind_result = 'success';
173 $non_anonymous_bind_result = 'error';
174 $desired_compare_result = 'dont care';
175 reload_ldap_module
();
177 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
178 $dbh, 'hola', password
=> 'hey' ) }
179 qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
180 "checkpw_ldap prints correct warning if LDAP bind fails";
181 is
( $ret, 0, "checkpw_ldap returns 0 if bind fails");
184 $desired_bind_result = 'success';
185 $non_anonymous_bind_result = 'success';
186 $desired_compare_result = 'error';
187 reload_ldap_module
();
189 warning_like
{ $ret = C4
::Auth_with_ldap
::checkpw_ldap
(
190 $dbh, 'hola', password
=> 'hey' ) }
191 qr/LDAP Auth rejected : invalid password for user 'hola'. LDAP error #1: error_name/,
192 "checkpw_ldap prints correct warning if LDAP bind fails";
193 is
( $ret, -1, "checkpw_ldap returns -1 if bind fails (Bug 8148)");
198 subtest
"search_method tests" => sub {
202 my $ldap = mock_net_ldap
();
205 is
( C4
::Auth_with_ldap
::search_method
( $ldap, undef), undef,
206 "search_method returns undef on undefined userid");
207 is
( C4
::Auth_with_ldap
::search_method
( undef, "undef"), undef,
208 "search_method returns undef on undefined ldap object");
210 # search ->code and !->code
211 $desired_search_result = 'error';
212 reload_ldap_module
();
213 eval { $ret = C4
::Auth_with_ldap
::search_method
( $ldap, "undef"); };
214 like
( $@
, qr/LDAP search failed to return object : 1/,
215 "search_method prints correct warning when db->search returns error code");
217 $desired_search_result = 'success';
218 $desired_count_result = 2;
219 reload_ldap_module
();
220 warning_like
{ $ret = C4
::Auth_with_ldap
::search_method
( $ldap, '123') }
221 qr/^LDAP Auth rejected \: \(uid\=123\) gets 2 hits/,
222 "search_method prints correct warning when hits count is not 1";
223 is
( $ret, 0, "search_method returns 0 when hits count is not 1" );
227 # Function that mocks the call to C4::Context->config(param)
233 firstname
=> { is
=> 'givenname' },
234 surname
=> { is
=> 'sn' },
235 address
=> { is
=> 'postaladdress' },
236 city
=> { is
=> 'l' },
237 zipcode
=> { is
=> 'postalcode' },
238 branchcode
=> { is
=> 'branch' },
239 userid
=> { is
=> 'uid' },
240 password
=> { is
=> 'userpassword' },
241 email
=> { is
=> 'mail' },
242 categorycode
=> { is
=> 'employeetype' },
243 phone
=> { is
=> 'telephonenumber' }
247 anonymous_bind
=> $anonymous_bind,
248 auth_by_bind
=> $auth_by_bind,
249 base
=> 'dc=metavore,dc=com',
250 hostname
=> 'localhost',
251 mapping
=> \
%ldap_mapping,
253 principal_name
=> '%s@my_domain.com',
254 replicate
=> $replicate,
256 user
=> 'cn=Manager,dc=metavore,dc=com'
259 return \
%ldap_config;
262 # Function that mocks the call to Net::LDAP
265 my $mocked_ldap = Test
::MockObject
->new();
267 $mocked_ldap->mock( 'bind', sub {
273 # Args passed => non-anonymous bind
274 if ( $non_anonymous_bind_result eq 'error' ) {
275 return mock_net_ldap_message
(1,1,'error_name','error_text');
277 return mock_net_ldap_message
(0,0,'','');
280 $mocked_message = mock_net_ldap_message
(
281 ($desired_bind_result eq 'error' ) ?
1 : 0, # code
282 ($desired_bind_result eq 'error' ) ?
1 : 0, # error
283 ($desired_bind_result eq 'error' ) ?
'error_name' : 0, # error_name
284 ($desired_bind_result eq 'error' ) ?
'error_text' : 0 # error_text
288 return $mocked_message;
291 $mocked_ldap->mock( 'compare', sub {
295 if ( $desired_compare_result eq 'error' ) {
296 $mocked_message = mock_net_ldap_message
(1,1,'error_name','error_text');
298 # we expect return code 6 for success
299 $mocked_message = mock_net_ldap_message
(6,0,'','');
302 return $mocked_message;
305 $mocked_ldap->mock( 'search', sub {
307 return mock_net_ldap_search
(
308 ( $desired_count_result ) # count
309 ?
$desired_count_result
311 ( $desired_search_result eq 'error' ) # code
314 ( $desired_search_result eq 'error' ) # error
317 ( $desired_search_result eq 'error' ) # error_text
320 ( $desired_search_result eq 'error' ) # error_name
323 mock_net_ldap_entry
( 'sampledn', 1 ) # shift_entry
331 sub mock_net_ldap_search
{
332 my ( $count, $code, $error, $error_text,
333 $error_name, $shift_entry ) = @_;
335 my $mocked_search = Test
::MockObject
->new();
336 $mocked_search->mock( 'count', sub { return $count; } );
337 $mocked_search->mock( 'code', sub { return $code; } );
338 $mocked_search->mock( 'error', sub { return $error; } );
339 $mocked_search->mock( 'error_name', sub { return $error_name; } );
340 $mocked_search->mock( 'error_text', sub { return $error_text; } );
341 $mocked_search->mock( 'shift_entry', sub { return $shift_entry; } );
343 return $mocked_search;
346 sub mock_net_ldap_message
{
347 my ( $code, $error, $error_name, $error_text ) = @_;
349 my $mocked_message = Test
::MockObject
->new();
350 $mocked_message->mock( 'code', sub { $code } );
351 $mocked_message->mock( 'error', sub { $error } );
352 $mocked_message->mock( 'error_name', sub { $error_name } );
353 $mocked_message->mock( 'error_text', sub { $error_text } );
355 return $mocked_message;
358 sub mock_net_ldap_entry
{
359 my ( $dn, $exists ) = @_;
361 my $mocked_entry = Test
::MockObject
->new();
362 $mocked_entry->mock( 'dn', sub { return $dn; } );
363 $mocked_entry->mock( 'exists', sub { return $exists } );
365 return $mocked_entry;
368 # TODO: Once we remove the global variables in C4::Auth_with_ldap
369 # we shouldn't need this...
371 sub reload_ldap_module
{
372 delete $INC{'C4/Auth_with_ldap.pm'};
373 require C4
::Auth_with_ldap
;
374 C4
::Auth_with_ldap
->import;