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

(-)a/C4/Auth.pm (-1 / +13 lines)
Lines 150-155 Output.pm module. Link Here
150
sub get_template_and_user {
150
sub get_template_and_user {
151
151
152
    my $in = shift;
152
    my $in = shift;
153
    my $extensions = shift // {};
153
    my ( $user, $cookie, $sessionID, $flags );
154
    my ( $user, $cookie, $sessionID, $flags );
154
155
155
    # Get shibboleth login attribute
156
    # Get shibboleth login attribute
Lines 168-173 sub get_template_and_user { Link Here
168
    );
169
    );
169
170
170
    if ( $in->{'template_name'} !~ m/maintenance/ ) {
171
    if ( $in->{'template_name'} !~ m/maintenance/ ) {
172
        my $checkauth_extensions = {};
173
        if ( $extensions && ref $extensions eq 'HASH' ){
174
            $checkauth_extensions = $extensions->{checkauth};
175
        }
171
        ( $user, $cookie, $sessionID, $flags ) = checkauth(
176
        ( $user, $cookie, $sessionID, $flags ) = checkauth(
172
            $in->{'query'},
177
            $in->{'query'},
173
            $in->{'authnotrequired'},
178
            $in->{'authnotrequired'},
Lines 175-180 sub get_template_and_user { Link Here
175
            $in->{'type'},
180
            $in->{'type'},
176
            undef,
181
            undef,
177
            $in->{template_name},
182
            $in->{template_name},
183
            $checkauth_extensions,
178
        );
184
        );
179
    }
185
    }
180
186
Lines 817-824 sub checkauth { Link Here
817
    my $type            = shift;
823
    my $type            = shift;
818
    my $emailaddress    = shift;
824
    my $emailaddress    = shift;
819
    my $template_name   = shift;
825
    my $template_name   = shift;
826
    my $extensions = shift // {};
820
    $type = 'opac' unless $type;
827
    $type = 'opac' unless $type;
821
828
829
    my $check_sessionID = $query->cookie("CGISESSID");
830
    if ($extensions && ref $extensions eq 'HASH' && $extensions->{sessionID}){
831
        $check_sessionID = $extensions->{sessionID};
832
    }
833
822
    unless ( C4::Context->preference("OpacPublic") ) {
834
    unless ( C4::Context->preference("OpacPublic") ) {
823
        my @allowed_scripts_for_private_opac = qw(
835
        my @allowed_scripts_for_private_opac = qw(
824
          opac-memberentry.tt
836
          opac-memberentry.tt
Lines 875-881 sub checkauth { Link Here
875
    elsif ( $emailaddress) {
887
    elsif ( $emailaddress) {
876
        # the Google OpenID Connect passes an email address
888
        # the Google OpenID Connect passes an email address
877
    }
889
    }
878
    elsif ( $sessionID = $query->cookie("CGISESSID") )
890
    elsif ( $sessionID = $check_sessionID )
879
    {    # assignment, not comparison
891
    {    # assignment, not comparison
880
        $session = get_session($sessionID);
892
        $session = get_session($sessionID);
881
        C4::Context->_new_userenv($sessionID);
893
        C4::Context->_new_userenv($sessionID);
(-)a/Koha/Auth/Shim.pm (+106 lines)
Line 0 Link Here
1
package Koha::Auth::Shim;
2
3
# Copyright 2021 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
21
use Modern::Perl;
22
23
use C4::Auth;
24
use C4::Context;
25
use Koha::Patrons;
26
27
=head1 API
28
29
=head2 Class Methods
30
31
=head3 cgi_is_authenticated
32
33
    This method checks if there is a CGISESSID and if the associated session
34
    exists and has a patron attached to it.
35
36
=cut
37
38
#NOTE: CGI
39
sub cgi_is_authenticated {
40
    my ($class,$args) = @_;
41
    my $is_authenticated;
42
    my $cgi = $args->{cgi};
43
    if ($cgi){
44
        my $sessionID = $cgi->cookie('CGISESSID');
45
        if ($sessionID){
46
            my $session = C4::Auth::get_session($sessionID);
47
            if ($session){
48
                my $id = $session->param('id');
49
                if ($id){
50
                    my $patrons = Koha::Patrons->search({ userid => $id });
51
                    if ($patrons->count){
52
                        $is_authenticated = 1;
53
                    }
54
                }
55
            }
56
        }
57
    }
58
    return $is_authenticated;
59
}
60
61
=head3 create_session
62
63
    This method creates a Koha session for a patron.
64
65
=cut
66
67
sub create_session {
68
    my ($class,$args) = @_;
69
    my $complete_session;
70
    my $patron = $args->{patron};
71
    if ($patron){
72
        my $session = C4::Auth::get_session("");
73
        if ($session){
74
            my $sessionID = $session->id;
75
            if ($sessionID){
76
                C4::Context->_new_userenv($sessionID);
77
                $session->param( 'number',       $patron->borrowernumber );
78
                $session->param( 'id',           $patron->userid );
79
                $session->param( 'cardnumber',   $patron->cardnumber );
80
                $session->param( 'firstname',    $patron->firstname );
81
                $session->param( 'surname',      $patron->surname );
82
                $session->param( 'branch',       $patron->library->branchcode );
83
                $session->param( 'branchname',   $patron->library->branchname );
84
                $session->param( 'flags',        $patron->flags );
85
                $session->param( 'emailaddress', $patron->email );
86
                $session->param( 'ip',           $session->remote_addr() );
87
                $session->param( 'lasttime',     time() );
88
                C4::Context->set_userenv(
89
                    $session->param('number'),       $session->param('id'),
90
                    $session->param('cardnumber'),   $session->param('firstname'),
91
                    $session->param('surname'),      $session->param('branch'),
92
                    $session->param('branchname'),   $session->param('flags'),
93
                    $session->param('emailaddress'), $session->param('shibboleth'),
94
                    $session->param('desk_id'),      $session->param('desk_name'),
95
                    $session->param('register_id'),  $session->param('register_name')
96
                );
97
                #NOTE: Persist session immediately. Otherwise, scoping issues can bite you.
98
                $session->flush();
99
                $complete_session = $session;
100
            }
101
        }
102
    }
103
    return $complete_session;
104
}
105
106
1;
(-)a/Koha/Auth/Type/Token/Ical.pm (+61 lines)
Line 0 Link Here
1
package Koha::Auth::Type::Token::Ical;
2
3
# Copyright 2021 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Koha::Patron::Attributes;
23
use Koha::Patrons;
24
use Koha::Auth::Shim;
25
26
=head1 API
27
28
=head2 Class Methods
29
30
=head3 authenticate
31
32
    This method takes a factor (ie a token) and finds the associated patron.
33
34
    On success, returns a new Koha session, which can be used to log into Koha.
35
36
=cut
37
38
sub authenticate {
39
    my ($class,$args) = @_;
40
    my $session;
41
    my $token = $args->{token};
42
    if ($token){
43
        my $attributes = Koha::Patron::Attributes->search({
44
            code => 'TOKEN_ICAL',
45
            attribute => $token,
46
        });
47
        if ($attributes->count() == 1){
48
            my $attribute = $attributes->next;
49
            if ($attribute){
50
                my $borrowernumber = $attribute->borrowernumber;
51
                my $patron = Koha::Patrons->find( $borrowernumber );
52
                if ($patron){
53
                    $session = Koha::Auth::Shim->create_session({ patron => $patron });
54
                }
55
            }
56
        }
57
    }
58
    return $session;
59
}
60
61
1;
(-)a/Koha/Patron.pm (+33 lines)
Lines 24-29 use Carp; Link Here
24
use List::MoreUtils qw( any uniq );
24
use List::MoreUtils qw( any uniq );
25
use JSON qw( to_json );
25
use JSON qw( to_json );
26
use Unicode::Normalize;
26
use Unicode::Normalize;
27
use String::Random qw( random_string );
28
use Digest::MD5 qw( md5_hex );
27
29
28
use C4::Context;
30
use C4::Context;
29
use C4::Log;
31
use C4::Log;
Lines 1882-1887 sub queue_notice { Link Here
1882
    return \%return;
1884
    return \%return;
1883
}
1885
}
1884
1886
1887
=head3 ical_auth_token
1888
1889
    my $ical_auth_token = $patron->ical_auth_token();
1890
1891
    Fetches the patron's iCal authentication token. If token does not exist, it will be automatically generated.
1892
1893
=cut
1894
1895
sub ical_auth_token {
1896
    my ($self, $args) = @_;
1897
    my $ical_auth_token;
1898
    my $attribute_value = $self->get_extended_attribute( 'TOKEN_ICAL' );
1899
    if ( $attribute_value ){
1900
        $ical_auth_token = $attribute_value->attribute();
1901
    }
1902
    else {
1903
        my $random_string = random_string("." x 24);
1904
        if ($random_string){
1905
            my $digest = md5_hex($random_string);
1906
            if ($digest){
1907
                $self->add_extended_attribute({
1908
                    code => 'TOKEN_ICAL',
1909
                    attribute => $digest,
1910
                });
1911
                $ical_auth_token = $digest;
1912
            }
1913
        }
1914
    }
1915
    return $ical_auth_token;
1916
}
1917
1885
=head2 Internal methods
1918
=head2 Internal methods
1886
1919
1887
=head3 _type
1920
=head3 _type
(-)a/installer/data/mysql/atomicupdate/bug27305-use-app-token-for-ical.perl (+14 lines)
Line 0 Link Here
1
$DBversion = 'XXX'; # will be replaced by the RM
2
if( CheckVersion( $DBversion ) ) {
3
    my $sql = q{
4
        INSERT INTO borrower_attribute_types (code,description,unique_id)
5
        SELECT 'TOKEN_ICAL','Authentication token for iCal feed',1
6
        FROM borrower_attribute_types
7
        WHERE NOT EXISTS (
8
            SELECT * FROM borrower_attribute_types WHERE code = 'TOKEN_ICAL'
9
        )
10
    };
11
    $dbh->do($sql);
12
13
    NewVersion( $DBversion, 27305, "Add TOKEN_ICAL borrower extended attribute");
14
}
(-)a/installer/data/mysql/en/mandatory/patron_attributes.yml (+34 lines)
Line 0 Link Here
1
---
2
#
3
#  Copyright 2021 Koha Development Team
4
#
5
#  This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
description:
21
  - "Mandatory patron attribute types:"
22
  - "* TOKEN_ICAL - Authentication token for iCal feed"
23
24
tables:
25
  - borrower_attribute_types:
26
      translatable: [ description ]
27
      multiline: []
28
      rows:
29
        - code: "TOKEN_ICAL"
30
          description: "Authentication token for iCal feed"
31
          repeatable: 0
32
          unique_id: 1
33
          opac_display: 0
34
          staff_searchable: 0
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (-1 / +5 lines)
Lines 832-838 Link Here
832
    <script>
832
    <script>
833
        function tableInit( tableId ){
833
        function tableInit( tableId ){
834
            if( tableId == "checkoutst" ){
834
            if( tableId == "checkoutst" ){
835
                $(".dt-buttons").append("<a class=\"dt-button buttons-ical\" href=\"opac-ics.pl\">iCal</a> ");
835
                [% IF ( ical_auth_token ) %]
836
                    $(".dt-buttons").append("<a class=\"dt-button buttons-ical\" href=\"opac-ics.pl?token=[% ical_auth_token | uri %]\">iCal</a> ");
837
                [% ELSE %]
838
                    $(".dt-buttons").append("<a class=\"dt-button buttons-ical\" href=\"opac-ics.pl\">iCal</a> ");
839
                [% END %]
836
                [% IF ( OpacRenewalAllowed && canrenew && !userdebarred ) %]
840
                [% IF ( OpacRenewalAllowed && canrenew && !userdebarred ) %]
837
                    $(".dt-buttons").append("<button id=\"renewselected_link\" class=\"dt-button buttons-renew\"><i class=\"fa fa-check\" aria-hidden=\"true\"></i> "+_("Renew selected")+"</button> <button id=\"renewall_link\" class=\"dt-button buttons-renewall\"><span class=\"fa-stack\"><i class=\"fa fa-check fa-stack-1x\" aria-hidden=\"true\"></i><i class=\"fa fa-check fa-stack-1x\" aria-hidden=\"true\"></i></span> "+_("Renew all")+"</button>");
841
                    $(".dt-buttons").append("<button id=\"renewselected_link\" class=\"dt-button buttons-renew\"><i class=\"fa fa-check\" aria-hidden=\"true\"></i> "+_("Renew selected")+"</button> <button id=\"renewall_link\" class=\"dt-button buttons-renewall\"><span class=\"fa-stack\"><i class=\"fa fa-check fa-stack-1x\" aria-hidden=\"true\"></i><i class=\"fa fa-check fa-stack-1x\" aria-hidden=\"true\"></i></span> "+_("Renew all")+"</button>");
838
                [% END %]
842
                [% END %]
(-)a/opac/opac-ics.pl (-1 / +19 lines)
Lines 35-48 use C4::Circulation; Link Here
35
use C4::Members;
35
use C4::Members;
36
use Koha::DateUtils;
36
use Koha::DateUtils;
37
37
38
use Koha::Auth::Shim;
39
use Koha::Auth::Type::Token::Ical;
40
38
my $query = CGI->new;
41
my $query = CGI->new;
42
43
#NOTE: Allow authentication by token for iCal feed
44
my $auth_extensions = {};
45
my $is_authenticated = Koha::Auth::Shim->cgi_is_authenticated({ cgi => $query });
46
if ( ! $is_authenticated ){
47
    my $token = $query->param('token');
48
    if ($token){
49
        my $session = Koha::Auth::Type::Token::Ical->authenticate({ token => $token });
50
        if ($session){
51
            $auth_extensions->{checkauth}->{sessionID} = $session->id;
52
        }
53
    }
54
}
55
39
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
56
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
40
    {
57
    {
41
        template_name   => "opac-ics.tt",
58
        template_name   => "opac-ics.tt",
42
        query           => $query,
59
        query           => $query,
43
        type            => "opac",
60
        type            => "opac",
44
        debug           => 1,
61
        debug           => 1,
45
    }
62
    },
63
    $auth_extensions,
46
);
64
);
47
65
48
# Create Calendar
66
# Create Calendar
(-)a/opac/opac-user.pl (+5 lines)
Lines 325-330 if ($show_barcode) { Link Here
325
}
325
}
326
$template->param( show_barcode => 1 ) if $show_barcode;
326
$template->param( show_barcode => 1 ) if $show_barcode;
327
327
328
my $ical_auth_token = $patron->ical_auth_token();
329
if ($ical_auth_token){
330
    $template->param( ical_auth_token => $ical_auth_token );
331
}
332
328
# now the reserved items....
333
# now the reserved items....
329
my $reserves = Koha::Holds->search( { borrowernumber => $borrowernumber } );
334
my $reserves = Koha::Holds->search( { borrowernumber => $borrowernumber } );
330
335
(-)a/t/db_dependent/Auth.t (-1 / +33 lines)
Lines 20-25 use C4::Members; Link Here
20
use Koha::AuthUtils qw/hash_password/;
20
use Koha::AuthUtils qw/hash_password/;
21
use Koha::Database;
21
use Koha::Database;
22
use Koha::Patrons;
22
use Koha::Patrons;
23
use Koha::Auth::Shim;
23
24
24
BEGIN {
25
BEGIN {
25
    use_ok('C4::Auth');
26
    use_ok('C4::Auth');
Lines 38-44 $schema->storage->txn_begin; Link Here
38
39
39
subtest 'checkauth() tests' => sub {
40
subtest 'checkauth() tests' => sub {
40
41
41
    plan tests => 4;
42
    plan tests => 5;
42
43
43
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => undef } });
44
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => undef } });
44
45
Lines 110-115 subtest 'checkauth() tests' => sub { Link Here
110
111
111
    C4::Context->_new_userenv; # For next tests
112
    C4::Context->_new_userenv; # For next tests
112
113
114
    subtest 'checkauth with pre-authenticated session' => sub {
115
116
        plan tests => 4;
117
118
        my $patron = $builder->build_object(
119
            { class => 'Koha::Patrons', value => { flags => 1 } } );
120
        $cgi = Test::MockObject->new();
121
        $cgi->mock( 
122
            'cookie',
123
            sub { 
124
                my ($self,@data) = @_;
125
                if (scalar @data > 1){
126
                    require CGI::Cookie;
127
                    my $cookie = CGI::Cookie->new(@data);
128
                    return $cookie;
129
                }
130
            } 
131
        );
132
        $cgi->mock( 'param', sub { return; } );
133
134
        my $session = Koha::Auth::Shim->create_session({ patron => $patron });
135
        my $extensions = { sessionID => $session->id, };
136
        my ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, undef, undef, undef, $extensions );
137
        is( $userid, $patron->userid, 'checkauth completes AuthN and AuthZ using a pre-authenticated session' );
138
        is( $sessionID, $session->id, 'sessionID is correct');
139
        is( ref $flags, 'HASH', 'flags is hash ref');
140
        is( $cookie->value, $session->id, 'cookie returned with correct sessionID');
141
    };
142
143
    C4::Context->_new_userenv; # For next tests
144
113
};
145
};
114
146
115
subtest 'track_login_daily tests' => sub {
147
subtest 'track_login_daily tests' => sub {
(-)a/t/db_dependent/Koha/Auth/Shim.t (+52 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2021 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More tests => 1;
23
use Test::Exception;
24
use Test::Warn;
25
26
use Koha::Database;
27
use Koha::Auth::Shim;
28
29
use t::lib::TestBuilder;
30
use t::lib::Mocks;
31
32
my $schema  = Koha::Database->new->schema;
33
my $builder = t::lib::TestBuilder->new;
34
35
subtest 'ical_auth_token' => sub {
36
    plan tests => 2;
37
38
    $schema->storage->txn_begin;
39
40
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
41
    if ($patron){
42
43
        my $session = Koha::Auth::Shim->create_session({ patron => $patron });
44
        ok($session, 'Session created by Koha::Auth::Type::Token::Ical authenticate method');
45
        is( ref $session, 'CGI::Session', 'Session is correct object type');
46
        $session->delete();
47
48
    }
49
50
    $schema->storage->txn_rollback;
51
};
52
(-)a/t/db_dependent/Koha/Auth/Type/Token/Ical.t (+61 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2021 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More tests => 1;
23
use Test::Exception;
24
use Test::Warn;
25
26
use Koha::Database;
27
use Koha::Auth::Type::Token::Ical;
28
29
use t::lib::TestBuilder;
30
use t::lib::Mocks;
31
32
my $schema  = Koha::Database->new->schema;
33
my $builder = t::lib::TestBuilder->new;
34
35
subtest 'ical_auth_token' => sub {
36
    plan tests => 6;
37
38
    $schema->storage->txn_begin;
39
40
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
41
    if ($patron){
42
        my $ical_auth_token = $patron->ical_auth_token();
43
        ok($ical_auth_token,"Generated patron ical_auth_token");
44
        my $ical_auth_token_get = $patron->ical_auth_token();
45
        is($ical_auth_token_get,$ical_auth_token,"Patron ical_auth_token matches previous call");
46
47
        my $session = Koha::Auth::Type::Token::Ical->authenticate({ token => $ical_auth_token });
48
        ok($session, 'Session created by Koha::Auth::Type::Token::Ical authenticate method');
49
        is( ref $session, 'CGI::Session', 'Session is correct object type');
50
        $session->delete();
51
52
        my $bad_token_session = Koha::Auth::Type::Token::Ical->authenticate({ token => 'bad' });
53
        is( $bad_token_session, undef, 'Bad token returns a null session');
54
55
        my $empty_token_session = Koha::Auth::Type::Token::Ical->authenticate({ token => '' });
56
        is( $bad_token_session, undef, 'Empty token returns a null session');
57
    }
58
59
    $schema->storage->txn_rollback;
60
};
61
(-)a/t/db_dependent/Koha/Patron.t (-2 / +17 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 7;
22
use Test::More tests => 8;
23
use Test::Exception;
23
use Test::Exception;
24
use Test::Warn;
24
use Test::Warn;
25
25
Lines 34-39 use t::lib::Mocks; Link Here
34
my $schema  = Koha::Database->new->schema;
34
my $schema  = Koha::Database->new->schema;
35
my $builder = t::lib::TestBuilder->new;
35
my $builder = t::lib::TestBuilder->new;
36
36
37
subtest 'ical_auth_token' => sub {
38
    plan tests => 2;
39
40
    $schema->storage->txn_begin;
41
42
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
43
    if ($patron){
44
        my $ical_auth_token = $patron->ical_auth_token();
45
        ok($ical_auth_token,"Generated patron ical_auth_token");
46
        my $ical_auth_token_get = $patron->ical_auth_token();
47
        is($ical_auth_token_get,$ical_auth_token,"Patron ical_auth_token matches previous call");
48
    }
49
50
    $schema->storage->txn_rollback;
51
};
52
37
subtest 'add_guarantor() tests' => sub {
53
subtest 'add_guarantor() tests' => sub {
38
54
39
    plan tests => 6;
55
    plan tests => 6;
40
- 

Return to bug 27305