Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 45 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
|
0.00% |
0 / 45 |
|
0.00% |
0 / 4 |
240 | |
0.00% |
0 / 1 |
|
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
authenticate | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
72 | |||
needsCsrfCheck | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
processUser | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | /** |
4 | * Email authentication module. |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) The National Library of Finland 2019. |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2, |
12 | * as published by the Free Software Foundation. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | * |
23 | * @category VuFind |
24 | * @package Authentication |
25 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
26 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
27 | * @link https://vufind.org/wiki/development:plugins:authentication_handlers Wiki |
28 | */ |
29 | |
30 | namespace VuFind\Auth; |
31 | |
32 | use VuFind\Db\Entity\UserEntityInterface; |
33 | use VuFind\Db\Service\UserServiceInterface; |
34 | use VuFind\Exception\Auth as AuthException; |
35 | |
36 | /** |
37 | * Email authentication module. |
38 | * |
39 | * @category VuFind |
40 | * @package Authentication |
41 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
42 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
43 | * @link https://vufind.org/wiki/development:plugins:authentication_handlers Wiki |
44 | */ |
45 | class Email extends AbstractBase |
46 | { |
47 | /** |
48 | * Constructor |
49 | * |
50 | * @param EmailAuthenticator $emailAuthenticator Email authenticator |
51 | * @param ILSAuthenticator $ilsAuthenticator ILS authenticator |
52 | */ |
53 | public function __construct( |
54 | protected EmailAuthenticator $emailAuthenticator, |
55 | protected ILSAuthenticator $ilsAuthenticator |
56 | ) { |
57 | } |
58 | |
59 | /** |
60 | * Attempt to authenticate the current user. Throws exception if login fails. |
61 | * |
62 | * @param \Laminas\Http\PhpEnvironment\Request $request Request object containing |
63 | * account credentials. |
64 | * |
65 | * @throws AuthException |
66 | * @return UserEntityInterface Object representing logged-in user. |
67 | */ |
68 | public function authenticate($request) |
69 | { |
70 | // This is a dual-mode method: |
71 | // First, try to find a user account with the provided email address and send |
72 | // a login link. |
73 | // Second, log the user in with the hash from the login link. |
74 | |
75 | $email = trim($request->getPost()->get('username', '')); |
76 | $hash = $request->getQuery('hash'); |
77 | if (!$email && !$hash) { |
78 | throw new AuthException('authentication_error_blank'); |
79 | } |
80 | |
81 | if (!$hash) { |
82 | // Validate the credentials: |
83 | $user = $this->getUserService()->getUserByEmail($email); |
84 | if ($user) { |
85 | $loginData = [ |
86 | 'vufind_id' => $user->getId(), |
87 | ]; |
88 | $this->emailAuthenticator->sendAuthenticationLink( |
89 | $user->getEmail(), |
90 | $loginData, |
91 | ['auth_method' => 'Email'] |
92 | ); |
93 | } |
94 | // Don't reveal the result |
95 | throw new \VuFind\Exception\AuthInProgress('email_login_link_sent'); |
96 | } |
97 | |
98 | $loginData = $this->emailAuthenticator->authenticate($hash); |
99 | if (isset($loginData['vufind_id'])) { |
100 | return $this->getUserService()->getUserById($loginData['vufind_id']); |
101 | } else { |
102 | // Check if we have more granular data available: |
103 | if (isset($loginData['userData'])) { |
104 | $userData = $loginData['userData']; |
105 | if ($loginData['rememberMe'] ?? false) { |
106 | // TODO: This is not a very nice way of carrying this information |
107 | // over to the authentication manager: |
108 | $request->getPost()->set('remember_me', '1'); |
109 | } |
110 | } else { |
111 | $userData = $loginData; |
112 | } |
113 | return $this->processUser($userData); |
114 | } |
115 | |
116 | // If we got this far, we have a problem: |
117 | throw new AuthException('authentication_error_invalid'); |
118 | } |
119 | |
120 | /** |
121 | * Whether this authentication method needs CSRF checking for the request. |
122 | * |
123 | * @param \Laminas\Http\PhpEnvironment\Request $request Request object. |
124 | * |
125 | * @return bool |
126 | */ |
127 | public function needsCsrfCheck($request) |
128 | { |
129 | // Disable CSRF if we get a hash in the request |
130 | return $request->getQuery('hash') ? false : true; |
131 | } |
132 | |
133 | /** |
134 | * Update the database using login user details, then return the User object. |
135 | * |
136 | * @param array $info User details returned by the login initiator like ILS. |
137 | * |
138 | * @throws AuthException |
139 | * @return UserEntityInterface Processed User object. |
140 | */ |
141 | protected function processUser($info) |
142 | { |
143 | // Check to see if we already have an account for this user: |
144 | if (!empty($info['id'])) { |
145 | $user = $this->getUserService()->getUserByCatId($info['id']); |
146 | if (empty($user)) { |
147 | $user = $this->getOrCreateUserByUsername($info['email']); |
148 | $user->setCatId($info['id']); |
149 | $this->getDbService(UserServiceInterface::class)->persistEntity($user); |
150 | } |
151 | } else { |
152 | $user = $this->getOrCreateUserByUsername($info['email']); |
153 | } |
154 | |
155 | // No need to store a password in VuFind's main password field: |
156 | $user->setRawPassword(''); |
157 | |
158 | // Update user information based on received data: |
159 | $fields = ['firstname', 'lastname', 'email', 'major', 'college']; |
160 | foreach ($fields as $field) { |
161 | $this->setUserValueByField($user, $field, $info[$field] ?? ' '); |
162 | } |
163 | |
164 | // Update the user in the database, then return it to the caller: |
165 | $this->ilsAuthenticator->saveUserCatalogCredentials( |
166 | $user, |
167 | $info['cat_username'] ?? ' ', |
168 | $info['cat_password'] ?? ' ' |
169 | ); |
170 | |
171 | return $user; |
172 | } |
173 | } |