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

(-)a/C4/Auth.pm (-1 / +9 lines)
Lines 34-40 use POSIX qw/strftime/; Link Here
34
use List::MoreUtils qw/ any /;
34
use List::MoreUtils qw/ any /;
35
35
36
# use utf8;
36
# use utf8;
37
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout);
37
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $googleoauth2 $ldap $cas $caslogout);
38
38
39
BEGIN {
39
BEGIN {
40
    sub psgi_env { any { /^psgi\./ } keys %ENV }
40
    sub psgi_env { any { /^psgi\./ } keys %ENV }
Lines 52-57 BEGIN { Link Here
52
                      ParseSearchHistoryCookie
52
                      ParseSearchHistoryCookie
53
                   );
53
                   );
54
    %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
54
    %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
55
    $googleoauth2= C4::Context->preference('GoogleOAuth2');
55
    $ldap        = C4::Context->config('useldapserver') || 0;
56
    $ldap        = C4::Context->config('useldapserver') || 0;
56
    $cas         = C4::Context->preference('casAuthentication');
57
    $cas         = C4::Context->preference('casAuthentication');
57
    $caslogout   = C4::Context->preference('casLogout');
58
    $caslogout   = C4::Context->preference('casLogout');
Lines 394-399 sub get_template_and_user { Link Here
394
            BranchesLoop              => GetBranchesLoop($opac_name),
395
            BranchesLoop              => GetBranchesLoop($opac_name),
395
            BranchCategoriesLoop      => GetBranchCategories( 'searchdomain', 1, $opac_name ),
396
            BranchCategoriesLoop      => GetBranchCategories( 'searchdomain', 1, $opac_name ),
396
            CalendarFirstDayOfWeek    => (C4::Context->preference("CalendarFirstDayOfWeek") eq "Sunday")?0:1,
397
            CalendarFirstDayOfWeek    => (C4::Context->preference("CalendarFirstDayOfWeek") eq "Sunday")?0:1,
398
            GoogleOAuth2              => (C4::Context->preference("GoogleOAuth2")),
397
            LibraryName               => "" . C4::Context->preference("LibraryName"),
399
            LibraryName               => "" . C4::Context->preference("LibraryName"),
398
            LibraryNameTitle          => "" . $LibraryNameTitle,
400
            LibraryNameTitle          => "" . $LibraryNameTitle,
399
            LoginBranchname           => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
401
            LoginBranchname           => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
Lines 1078-1083 sub checkauth { Link Here
1078
            invalidCasLogin => $info{'invalidCasLogin'}
1080
            invalidCasLogin => $info{'invalidCasLogin'}
1079
        );
1081
        );
1080
    }
1082
    }
1083
    if ($googleoauth2) {
1084
        if ($query->param("OAuth2Failed")) {
1085
            my $reason = $query->param('OAuth2Failed');
1086
            $template->param(invalidOAuth2Login => $reason);
1087
        }
1088
    }
1081
1089
1082
    my $self_url = $query->url( -absolute => 1 );
1090
    my $self_url = $query->url( -absolute => 1 );
1083
    $template->param(
1091
    $template->param(
(-)a/installer/data/mysql/atomicupdate/bug_10988_add_GoogleOAuth.sql (+3 lines)
Line 0 Link Here
1
-- Adding GoogleOAuth2 support
2
INSERT INTO `systempreferences` (`variable`, `value`, `options`, `explanation`, `type`) VALUES ('GoogleOAuth2', '0', NULL, 'if ON, allows the use of Google OAuth2 for login', 'YesNo'), ('GoogleOAuth2ClientID', '', NULL, 'Client ID for the web app registered with google', 'Free'), ('GoogleOAuth2ClientSecret', '', NULL, 'Client Secret for the web app registered with google', 'Free');
3
 
(-)a/installer/data/mysql/sysprefs.sql (+3 lines)
Lines 115-120 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
115
('FRBRizeEditions','0','','If ON, Koha will query one or more ISBN web services for associated ISBNs and display an Editions tab on the details pages','YesNo'),
115
('FRBRizeEditions','0','','If ON, Koha will query one or more ISBN web services for associated ISBNs and display an Editions tab on the details pages','YesNo'),
116
('gist','0','','Default Goods and Services tax rate NOT in %, but in numeric form (0.12 for 12%), set to 0 to disable GST','Integer'),
116
('gist','0','','Default Goods and Services tax rate NOT in %, but in numeric form (0.12 for 12%), set to 0 to disable GST','Integer'),
117
('GoogleJackets','0',NULL,'if ON, displays jacket covers from Google Books API','YesNo'),
117
('GoogleJackets','0',NULL,'if ON, displays jacket covers from Google Books API','YesNo'),
118
('GoogleOAuth2', '0', NULL, 'if ON, allows the use of Google OAuth2 for login', 'YesNo'),
119
('GoogleOAuth2ClientID', '', NULL, 'Client ID for the web app registered with google', 'Free'),
120
('GoogleOAuth2ClientSecret', '', NULL, 'Client Secret for the web app registered with google', 'Free'),
118
('hidelostitems','0','','If ON, disables display of\"lost\" items in OPAC.','YesNo'),
121
('hidelostitems','0','','If ON, disables display of\"lost\" items in OPAC.','YesNo'),
119
('HidePatronName','0','','If this is switched on, patron\'s cardnumber will be shown instead of their name on the holds and catalog screens','YesNo'),
122
('HidePatronName','0','','If this is switched on, patron\'s cardnumber will be shown instead of their name on the holds and catalog screens','YesNo'),
120
('hide_marc','0',NULL,'If ON, disables display of MARC fields, subfield codes & indicators (still shows data)','YesNo'),
123
('hide_marc','0',NULL,'If ON, disables display of MARC fields, subfield codes & indicators (still shows data)','YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref (+15 lines)
Lines 113-115 Administration: Link Here
113
                Solr: Solr
113
                Solr: Solr
114
                Zebra: Zebra
114
                Zebra: Zebra
115
            - is the search engine used.
115
            - is the search engine used.
116
    Google OAuth2:
117
        -
118
            - pref: GoogleOAuth2
119
              choices:
120
                yes: Use
121
                no: "Don't Use"
122
            - Google OAuth2 login.
123
            - You will need to select OAuth2 when creating an app in the google cloud console, and set the web origin to your_opac_url and the redirect url to your_opac_url/cgi-bin/koha/svc/oauthlogin .
124
125
        -
126
            - Google OAuth2 Client ID
127
            - pref: GoogleOAuth2ClientID
128
        -
129
            - Google OAuth2 Client Secret
130
            - pref: GoogleOAuth2ClientSecret
(-)a/koha-tmpl/opac-tmpl/ccsr/en/includes/top-bar.inc (-1 / +5 lines)
Lines 55-61 Link Here
55
      [% IF ( opacuserlogin ) %]
55
      [% IF ( opacuserlogin ) %]
56
        <ul>
56
        <ul>
57
    [% UNLESS ( loggedinusername ) %]
57
    [% UNLESS ( loggedinusername ) %]
58
                   <li><a href="/cgi-bin/koha/opac-user.pl">Log in to your account</a></li>[% END %]
58
        [% IF ( GoogleOAuth2 ) %]
59
               <li><a href="/cgi-bin/koha/svc/googleoauth2">Log in to your account</a></li>
60
        [% ELSE %]
61
               <li><a href="/cgi-bin/koha/opac-user.pl">Log in to your account</a></li>
62
        [% END %][% END %]
59
                [% IF ( loggedinusername ) %]
63
                [% IF ( loggedinusername ) %]
60
                    <li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername">[% FOREACH USER_INF IN USER_INFO %][% USER_INF.title %] [% USER_INF.firstname %] [% USER_INF.surname %][% END %]</span></a></span></li>
64
                    <li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername">[% FOREACH USER_INF IN USER_INFO %][% USER_INF.title %] [% USER_INF.firstname %] [% USER_INF.surname %][% END %]</span></a></span></li>
61
65
(-)a/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc (-1 / +5 lines)
Lines 2-8 Link Here
2
  [% IF ( opacuserlogin ) %]
2
  [% IF ( opacuserlogin ) %]
3
	<ul>
3
	<ul>
4
[% UNLESS ( loggedinusername ) %]
4
[% UNLESS ( loggedinusername ) %]
5
               <li><a href="/cgi-bin/koha/opac-user.pl">Log in to your account</a></li>[% END %]
5
        [% IF ( GoogleOAuth2 ) %]
6
               <li><a href="/cgi-bin/koha/svc/googleoauth2">Log in to your account</a></li>
7
        [% ELSE %]
8
               <li><a href="/cgi-bin/koha/opac-user.pl">Log in to your account</a></li>
9
        [% END %][% END %]
6
            [% IF ( loggedinusername ) %]
10
            [% IF ( loggedinusername ) %]
7
                <li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername">[% FOREACH USER_INF IN USER_INFO %][% USER_INF.title %] [% USER_INF.firstname %] [% USER_INF.surname %][% END %]</span></a></span></li>
11
                <li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername">[% FOREACH USER_INF IN USER_INFO %][% USER_INF.title %] [% USER_INF.firstname %] [% USER_INF.surname %][% END %]</span></a></span></li>
8
12
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt (+9 lines)
Lines 73-78 please choose against which one you would like to authenticate: </p> Link Here
73
73
74
[% END %]
74
[% END %]
75
75
76
[% IF ( invalidOAuth2Login ) %]
77
<h4>Automatic Login</h4>
78
<p>Sorry, your automatic login failed. <span class="error">[% invalidOAuth2Login %]</span></p>
79
<p>Please note that automatic login will only work if you are using the email address registered with this library.</p>
80
<p>If you want to, you can try to <a href="/cgi-bin/koha/svc/googleoauth2?reauthenticate=select_account">login using a differen account</a>
81
<h4>Local login</h4>
82
<p>If you can't login automatically, you can still login in manually: </p>
83
84
[% END %]
76
<form action="[% url %]" name="auth" id="auth" method="post">
85
<form action="[% url %]" name="auth" id="auth" method="post">
77
  <input type="hidden" name="koha_login_context" value="opac" />
86
  <input type="hidden" name="koha_login_context" value="opac" />
78
<fieldset class="brief">[% FOREACH INPUT IN INPUTS %]
87
<fieldset class="brief">[% FOREACH INPUT IN INPUTS %]
(-)a/opac/svc/googleoauth2 (-1 / +127 lines)
Line 0 Link Here
0
- 
1
#!/bin/perl -w
2
# Copyright chris@bigballofwax.co.nz 2013
3
# 
4
# This file is part of Koha.
5
# 
6
# Koha is free software; you can redistribute it and/or modify it under the
7
# terms of the GNU General Public License as published by the Free Software
8
# Foundation; either version 3 of the License, or (at your option) any later
9
# version.
10
# 
11
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
# 
15
# You should have received a copy of the GNU General Public License along
16
# with Koha; if not, write to the Free Software Foundation, Inc.,
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
#
19
#
20
# Basic OAuth2 authentication for google goes like this
21
# First: get your clientid, clientsecret from google. At this stage, tell google that
22
# your redirect url is /cgi-bin/koha/svc/oauthlogin
23
#
24
# The first thing that happens when this script is called is that one gets redirected
25
# to an authentication url from google
26
#
27
# If successful, that then redirects back to this script, setting a CODE parameter
28
# which we use to look up a json authentication token. This token includes an encrypted 
29
# json id_token, which we round-trip back to google to decrypt. Finally, we can extract
30
# the email address from this.
31
#
32
# There is LOTS of room for improvement here.
33
# 1. move the clientid, clientsecret to systempreferences
34
# 2. use the OPACBaseURL preference to compute the redirecturl
35
# 4. Google recommends verifying and decrypting the id_token locally, which means caching
36
# some information and updating it daily. But that would make things a lot faster
37
38
use strict;
39
use warnings;
40
use CGI qw/escape/;
41
use C4::Auth;
42
use C4::Context;
43
use C4::Output;
44
45
use LWP::UserAgent; 
46
use HTTP::Request::Common qw{ POST };
47
use JSON;
48
49
my $scope="openid email";
50
my $host = C4::Context->preference('OPACBaseURL');
51
my $redirecturl = 'http://' . $host . '/cgi-bin/koha/svc/oauthlogin';
52
my $issuer = 'accounts.google.com';
53
my $clientid = C4::Context->preference('GoogleOAuth2ClientID');
54
my $clientsecret = C4::Context->preference('GoogleOAuth2ClientSecret');
55
56
my $query = new CGI;
57
58
sub loginfailed {
59
  my $query = shift;
60
  my $reason = shift;
61
  $query->delete('code');
62
  $query->param('OAuth2Failed'=>$reason);
63
  my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
64
    {
65
        template_name   => 'opac-user.tmpl',
66
        query           => $query,
67
        type            => 'opac',
68
        authnotrequired => 0,
69
        flagsrequired   => { borrow => 1 },
70
    }
71
  );
72
  $template->param( 'invalidOAuth2Login' => $reason );
73
  $template->param( 'loginprompt' => 1);
74
  output_html_with_http_headers $query, $cookie, $template->output;
75
}
76
#die $query->param('code');
77
if (defined $query->param('error')) {
78
	loginfailed($query, 'An authentication error occurred. (Error:' . $query->param('error') . ')');
79
} elsif (defined $query->param('code')) {
80
	my $code=$query->param('code');
81
	my $ua = LWP::UserAgent->new();
82
	my $request = POST('https://accounts.google.com/o/oauth2/token', [
83
                        code => $code,
84
                        client_id => $clientid,
85
                        client_secret => $clientsecret,
86
    	            	redirect_uri => $redirecturl,
87
                		grant_type => 'authorization_code',
88
                        $scope => $scope
89
    ]);
90
	my $response =  $ua->request($request)->decoded_content ;
91
	my $json = decode_json ( $response);
92
	if ( exists($json->{'id_token'}) ) {
93
		$request = POST('https://www.googleapis.com/oauth2/v1/tokeninfo', [
94
			id_token => $json->{'id_token'}
95
		]);
96
		$response = $ua->request($request)->decoded_content;
97
		$json = decode_json ( $response);
98
		# Confirm (as google suggests) that the issuer and audience are what we expect them to be
99
		if (($json->{'issuer'} eq $issuer) && ($json->{'audience'} eq $clientid) && exists($json->{'email'})) {
100
			my $email = $json->{'email'};
101
			my ( $userid, $cookie, $sessionID ) =
102
                            checkauth( $query, 1,  { borrow => 1 }, 'opac', $email );
103
			if ($userid) { # A valid user has logged in
104
				print $query->redirect( -uri => '/cgi-bin/koha/opac-user.pl', -cookie => $cookie );
105
			} else {
106
				loginfailed($query, 'The email address you are trying to use is not associated with a borrower in this library.');
107
			}
108
		} else { # something went wrong with getting appropriate credentials
109
			loginfailed($query, 'Failed to get proper credentials from google.');
110
		}
111
	} else { # Failed to get ID Token
112
		loginfailed($query, 'An authentication error occurred. (Error: No ID Token was supplied)');
113
	}	
114
115
} else {
116
    my  $prompt = '';
117
    $prompt = $query->param('reauthenticate') unless not (defined $query->param('reauthenticate'));
118
119
    my $authorisationurl =  'https://accounts.google.com/o/oauth2/auth?' .
120
                            'response_type=code&' .
121
                            'redirect_uri=' . escape ( $redirecturl ) . '&' .
122
                            'client_id=' . escape ( $clientid ) . '&' .
123
                            'scope=' . escape ( $scope ) . '&';
124
    $authorisationurl .=    'prompt=' . escape ( $query->param('reauthenticate') );
125
	print $query->redirect($authorisationurl);
126
}
127

Return to bug 10988