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>.
21 use Module::Load::Conditional qw/check_install/;
25 use File::Temp qw(tempdir);
27 use t::lib::Mocks::Logger;
34 if ( check_install( module => 'Test::DBIx::Class' ) ) {
38 plan skip_all => "Need Test::DBIx::Class";
42 use Test::DBIx::Class {
43 schema_class => 'Koha::Schema',
44 connect_info => [ 'dbi:SQLite:dbname=:memory:', '', '' ]
48 my $matchpoint = 'userid';
52 'userid' => { 'is' => 'uid' },
53 'surname' => { 'is' => 'sn' },
54 'dateexpiry' => { 'is' => 'exp' },
55 'categorycode' => { 'is' => 'cat' },
56 'address' => { 'is' => 'add' },
57 'city' => { 'is' => 'city' },
59 $ENV{'uid'} = "test1234";
68 my $context = Test::MockModule->new('C4::Context');
71 $context->mock( 'config', \&mockedConfig );
74 my $OPACBaseURL = "testopac.com";
75 my $staffClientBaseURL = "teststaff.com";
76 $context->mock( 'preference', \&mockedPref );
79 $context->mock( 'timezone', sub { return 'local'; } );
82 my $interface = 'opac';
83 $context->mock( 'interface', \&mockedInterface );
86 my $database = Test::MockModule->new('Koha::Database');
89 $database->mock( 'schema', \&mockedSchema );
92 ##############################################################
94 my $logger = t::lib::Mocks::Logger->new();
97 use C4::Auth_with_shibboleth qw( shib_ok login_shib_url get_login_shib checkpw_shib );
98 require_ok('C4::Auth_with_shibboleth');
102 subtest "shib_ok tests" => sub {
106 # correct config, no debug
107 is( shib_ok(), '1', "good config" );
109 # bad config, no debug
111 warnings_are { $result = shib_ok() }
112 [ { carped => 'shibboleth matchpoint not defined' }, ],
113 "undefined matchpoint = fatal config, warning given";
114 is( $result, '0', "bad config" );
116 $matchpoint = 'email';
117 warnings_are { $result = shib_ok() }
118 [ { carped => 'shibboleth matchpoint not mapped' }, ],
119 "unmapped matchpoint = fatal config, warning given";
120 is( $result, '0', "bad config" );
122 # add test for undefined shibboleth block
128 #my $query = CGI->new();
129 #is(logout_shib($query),"https://".$opac."/Shibboleth.sso/Logout?return="."https://".$opac,"logout_shib");
132 subtest "login_shib_url tests" => sub {
135 my $string = 'language=en-GB¶m="hehâ¤"';
136 my $query_string = Encode::encode('UTF-8', $string);
137 my $query_string_uri_escaped = URI::Escape::uri_escape_utf8('?'.$string);
139 local $ENV{REQUEST_METHOD} = 'GET';
140 local $ENV{QUERY_STRING} = $query_string;
141 local $ENV{SCRIPT_NAME} = '/cgi-bin/koha/opac-user.pl';
142 my $query = CGI->new($query_string);
144 login_shib_url($query),
145 'https://testopac.com'
146 . '/Shibboleth.sso/Login?target='
147 . 'https://testopac.com/cgi-bin/koha/opac-user.pl'
148 . $query_string_uri_escaped,
152 my $post_params = 'user=bob&password=wideopen';
153 local $ENV{REQUEST_METHOD} = 'POST';
154 local $ENV{CONTENT_LENGTH} = length($post_params);
156 my $dir = tempdir( CLEANUP => 1 );
157 my $infile = "$dir/in.txt";
158 open my $fh_write, '>', $infile or die "Could not open '$infile' $!";
159 print $fh_write $post_params;
162 open my $fh_read, '<', $infile or die "Could not open '$infile' $!";
164 $query = CGI->new($fh_read);
166 login_shib_url($query),
167 'https://testopac.com'
168 . '/Shibboleth.sso/Login?target='
169 . 'https://testopac.com/cgi-bin/koha/opac-user.pl',
177 subtest "get_login_shib tests" => sub {
183 $login = get_login_shib();
185 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
186 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
189 is( $login, "test1234", "good config, attribute value returned" );
193 subtest "checkpw_shib tests" => sub {
198 my ( $retval, $retcard, $retuserid );
200 # Setup Mock Database Data
203 [qw/cardnumber userid surname address city email/],
204 [qw/testcardnumber test1234 renvoize myaddress johnston /],
205 [qw/testcardnumber1 test12345 clamp1 myaddress quechee kid@clamp.io/],
206 [qw/testcardnumber2 test123456 clamp2 myaddress quechee kid@clamp.io/],
208 'Category' => [ [qw/categorycode default_privacy/], [qw/S never/], ]
210 'Installed some custom fixtures via the Populate fixture class';
213 $shib_login = "test1234";
214 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
216 is( $logger->count(), 2, "Two debugging entries");
217 is( $retval, "1", "user authenticated" );
218 is( $retcard, "testcardnumber", "expected cardnumber returned" );
219 is( $retuserid, "test1234", "expected userid returned" );
220 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
221 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
225 $shib_login = 'martin';
226 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
227 is( $retval, "0", "user not authenticated" );
228 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
229 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
232 # duplicated matchpoint
233 $matchpoint = 'email';
234 $mapping{'email'} = { is => 'email' };
235 $shib_login = 'kid@clamp.io';
236 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
237 is( $retval, "0", "user not authenticated if duplicated matchpoint" );
238 $logger->debug_is("koha borrower field to match: email", "borrower match field debug info")
239 ->debug_is("shibboleth attribute to match: email", "shib match attribute debug info")
242 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
243 $logger->debug_is("koha borrower field to match: email", "borrower match field debug info")
244 ->debug_is("shibboleth attribute to match: email", "shib match attribute debug info")
245 ->warn_is('There are several users with email of kid@clamp.io, matchpoints must be unique', "duplicated matchpoint warned with debug")
252 $shib_login = 'test4321';
253 $ENV{'uid'} = 'test4321';
255 $ENV{'exp'} = "2017";
257 $ENV{'add'} = 'Address';
258 $ENV{'city'} = 'City';
260 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
261 is( $retval, "1", "user authenticated" );
262 is( $retuserid, "test4321", "expected userid returned" );
263 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
264 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
267 ok my $new_user = ResultSet('Borrower')
268 ->search( { 'userid' => 'test4321' }, { rows => 1 } ), "new user found";
269 is_fields [qw/surname dateexpiry address city/], $new_user->next,
270 [qw/pika 2017 Address City/],
271 'Found $new_users surname';
276 $ENV{'city'} = 'AnotherCity';
277 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
278 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
279 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
282 ok my $sync_user = ResultSet('Borrower')
283 ->search( { 'userid' => 'test4321' }, { rows => 1 } ), "sync user found";
285 is_fields [qw/surname dateexpiry address city/], $sync_user->next,
286 [qw/pika 2017 Address AnotherCity/],
287 'Found $sync_user synced city';
291 $shib_login = "test1234";
292 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
293 is( $retval, "1", "user authenticated" );
294 is( $retcard, "testcardnumber", "expected cardnumber returned" );
295 is( $retuserid, "test1234", "expected userid returned" );
296 $logger->debug_is("koha borrower field to match: userid", "borrower match field debug info")
297 ->debug_is("shibboleth attribute to match: uid", "shib match attribute debug info")
301 $shib_login = "martin";
302 ( $retval, $retcard, $retuserid ) = checkpw_shib($shib_login);
303 is( $retval, "0", "user not authenticated" );
304 $logger->info_is("There are several users with userid of martin, matchpoints must be unique", "Duplicated matchpoint warned to info");
308 $OPACBaseURL = "testopac.com";
309 is( C4::Auth_with_shibboleth::_get_uri(),
310 "https://testopac.com", "https opac uri returned" );
314 $OPACBaseURL = "http://testopac.com";
315 my $result = C4::Auth_with_shibboleth::_get_uri();
316 is( $result, "https://testopac.com", "https opac uri returned" );
317 $logger->warn_is("Shibboleth requires OPACBaseURL/staffClientBaseURL to use the https protocol!", "Improper protocol logged to warn")
320 $OPACBaseURL = "https://testopac.com";
321 is( C4::Auth_with_shibboleth::_get_uri(),
322 "https://testopac.com", "https opac uri returned" );
326 $OPACBaseURL = undef;
327 $result = C4::Auth_with_shibboleth::_get_uri();
328 is( $result, "https://", "https $interface uri returned" );
330 $logger->warn_is("Syspref staffClientBaseURL or OPACBaseURL not set!", "undefined OPACBaseURL - received expected warning")
333 ## _get_uri - intranet
334 $interface = 'intranet';
335 $staffClientBaseURL = "teststaff.com";
336 is( C4::Auth_with_shibboleth::_get_uri(),
337 "https://teststaff.com", "https $interface uri returned" );
342 $staffClientBaseURL = "http://teststaff.com";
343 $result = C4::Auth_with_shibboleth::_get_uri();
344 is( $result, "https://teststaff.com", "https $interface uri returned" );
345 $logger->warn_is("Shibboleth requires OPACBaseURL/staffClientBaseURL to use the https protocol!")
348 $staffClientBaseURL = "https://teststaff.com";
349 is( C4::Auth_with_shibboleth::_get_uri(),
350 "https://teststaff.com", "https $interface uri returned" );
351 is( $logger->count(), 0, 'No logging' );
353 $staffClientBaseURL = undef;
354 $result = C4::Auth_with_shibboleth::_get_uri();
355 is( $result, "https://", "https $interface uri returned" );
356 $logger->warn_is("Syspref staffClientBaseURL or OPACBaseURL not set!", "undefined staffClientBaseURL - received expected warning")
360 # Internal helper function, covered in tests above
366 'autocreate' => $autocreate,
368 'matchpoint' => $matchpoint,
369 'mapping' => \%mapping
379 if ( $param eq 'OPACBaseURL' ) {
380 $return = $OPACBaseURL;
383 if ( $param eq 'staffClientBaseURL' ) {
384 $return = $staffClientBaseURL;
390 sub mockedInterface {
398 ## Convenience method to reset config
400 $matchpoint = 'userid';
404 'userid' => { 'is' => 'uid' },
405 'surname' => { 'is' => 'sn' },
406 'dateexpiry' => { 'is' => 'exp' },
407 'categorycode' => { 'is' => 'cat' },
408 'address' => { 'is' => 'add' },
409 'city' => { 'is' => 'city' },
411 $ENV{'uid'} = "test1234";
416 $ENV{'city'} = undef;