Subversion Repositories oidplus

Rev

Rev 583 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
104 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
511 daniel-mar 5
 * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
104 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
511 daniel-mar 20
if (!defined('INSIDE_OIDPLUS')) die();
21
 
256 daniel-mar 22
class OIDplusPagePublicLogin extends OIDplusPagePluginPublic {
104 daniel-mar 23
 
321 daniel-mar 24
        public function action($actionID, $params) {
104 daniel-mar 25
                // === RA LOGIN/LOGOUT ===
26
 
321 daniel-mar 27
                if ($actionID == 'ra_login') {
261 daniel-mar 28
                        if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
29
                                $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
552 daniel-mar 30
                                _CheckParamExists($params, 'captcha');
321 daniel-mar 31
                                $response=$params["captcha"];
104 daniel-mar 32
                                $verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
33
                                $captcha_success=json_decode($verify);
34
                                if ($captcha_success->success==false) {
360 daniel-mar 35
                                        throw new OIDplusException(_L('CAPTCHA not successfully verified'));
104 daniel-mar 36
                                }
37
                        }
38
 
552 daniel-mar 39
                        _CheckParamExists($params, 'email');
40
                        _CheckParamExists($params, 'password');
41
 
430 daniel-mar 42
                        $email = $params['email'];
43
                        $ra = new OIDplusRA($email);
44
 
45
                        if (empty($email)) {
46
                                throw new OIDplusException(_L('Please enter a valid email address'));
47
                        }
48
 
321 daniel-mar 49
                        if ($ra->checkPassword($params['password'])) {
585 daniel-mar 50
                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
51
                                OIDplus::authUtils()->raLoginEx($email, $remember_me, 'Regular login');
104 daniel-mar 52
 
264 daniel-mar 53
                                OIDplus::db()->query("UPDATE ###ra set last_login = ".OIDplus::db()->sqlDate()." where email = ?", array($email));
104 daniel-mar 54
 
328 daniel-mar 55
                                return array("status" => 0);
104 daniel-mar 56
                        } else {
300 daniel-mar 57
                                if (OIDplus::config()->getValue('log_failed_ra_logins', false)) {
298 daniel-mar 58
                                        if ($ra->existing()) {
59
                                                OIDplus::logger()->log("[WARN]A!", "Failed login to RA account '$email' (wrong password)");
60
                                        } else {
61
                                                OIDplus::logger()->log("[WARN]A!", "Failed login to RA account '$email' (RA not existing)");
62
                                        }
295 daniel-mar 63
                                }
355 daniel-mar 64
                                throw new OIDplusException(_L('Wrong password or user not registered'));
104 daniel-mar 65
                        }
150 daniel-mar 66
 
321 daniel-mar 67
                } else if ($actionID == 'ra_logout') {
119 daniel-mar 68
 
552 daniel-mar 69
                        _CheckParamExists($params, 'email');
559 daniel-mar 70
 
321 daniel-mar 71
                        $email = $params['email'];
72
 
585 daniel-mar 73
                        OIDplus::authUtils()->raLogoutEx($email);
579 daniel-mar 74
 
328 daniel-mar 75
                        return array("status" => 0);
104 daniel-mar 76
                }
77
 
78
                // === ADMIN LOGIN/LOGOUT ===
79
 
321 daniel-mar 80
                else if ($actionID == 'admin_login') {
261 daniel-mar 81
                        if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
82
                                $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
552 daniel-mar 83
                                _CheckParamExists($params, 'captcha');
321 daniel-mar 84
                                $response=$params["captcha"];
104 daniel-mar 85
                                $verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
86
                                $captcha_success=json_decode($verify);
87
                                if ($captcha_success->success==false) {
360 daniel-mar 88
                                        throw new OIDplusException(_L('CAPTCHA not successfully verified'));
104 daniel-mar 89
                                }
90
                        }
91
 
552 daniel-mar 92
                        _CheckParamExists($params, 'password');
549 daniel-mar 93
                        if (OIDplus::authUtils()->adminCheckPassword($params['password'])) {
585 daniel-mar 94
                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
95
                                OIDplus::authUtils()->adminLoginEx($remember_me, 'Regular login');
579 daniel-mar 96
 
97
                                // TODO: Write a "last login" entry in config table?
98
 
328 daniel-mar 99
                                return array("status" => 0);
104 daniel-mar 100
                        } else {
300 daniel-mar 101
                                if (OIDplus::config()->getValue('log_failed_admin_logins', false)) {
298 daniel-mar 102
                                        OIDplus::logger()->log("[WARN]A!", "Failed login to admin account");
103
                                }
360 daniel-mar 104
                                throw new OIDplusException(_L('Wrong password'));
104 daniel-mar 105
                        }
106
                }
321 daniel-mar 107
                else if ($actionID == 'admin_logout') {
585 daniel-mar 108
                        OIDplus::authUtils()->adminLogoutEx();
579 daniel-mar 109
 
328 daniel-mar 110
                        return array("status" => 0);
104 daniel-mar 111
                }
321 daniel-mar 112
                else {
360 daniel-mar 113
                        throw new OIDplusException(_L('Unknown action ID'));
321 daniel-mar 114
                }
104 daniel-mar 115
        }
116
 
117
        public function init($html=true) {
295 daniel-mar 118
                OIDplus::config()->prepareConfigKey('log_failed_ra_logins', 'Log failed RA logins', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
119
                        if (!is_numeric($value) || (($value != 0) && (($value != 1)))) {
360 daniel-mar 120
                                throw new OIDplusException(_L('Valid values: 0 (off) or 1 (on).'));
295 daniel-mar 121
                        }
122
                });
123
                OIDplus::config()->prepareConfigKey('log_failed_admin_logins', 'Log failed Admin logins', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
124
                        if (!is_numeric($value) || (($value != 0) && (($value != 1)))) {
360 daniel-mar 125
                                throw new OIDplusException(_L('Valid values: 0 (off) or 1 (on).'));
295 daniel-mar 126
                        }
127
                });
104 daniel-mar 128
        }
129
 
130
        public function gui($id, &$out, &$handled) {
382 daniel-mar 131
                $ary = explode('$', $id);
559 daniel-mar 132
                $desired_ra = '';
382 daniel-mar 133
                if (isset($ary[1])) {
134
                        $id = $ary[0];
135
                        $tab = $ary[1];
559 daniel-mar 136
                        if (isset($ary[2])) {
137
                                $desired_ra = $ary[2];
138
                        }
382 daniel-mar 139
                } else {
140
                        $tab = 'ra';
141
                }
104 daniel-mar 142
                if ($id === 'oidplus:login') {
143
                        $handled = true;
360 daniel-mar 144
                        $out['title'] = _L('Login');
241 daniel-mar 145
                        $out['icon']  = OIDplus::webpath(__DIR__).'login_big.png';
104 daniel-mar 146
 
431 daniel-mar 147
                        $out['text'] = '';
148
 
104 daniel-mar 149
                        $out['text'] .= '<noscript>';
355 daniel-mar 150
                        $out['text'] .= '<p>'._L('You need to enable JavaScript to use the login area.').'</p>';
104 daniel-mar 151
                        $out['text'] .= '</noscript>';
152
 
219 daniel-mar 153
                        $out['text'] .= '<div id="loginArea" style="visibility: hidden"><div id="loginTab" class="container" style="width:100%;">';
261 daniel-mar 154
                        $out['text'] .= (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false) ?
360 daniel-mar 155
                                        '<p>'._L('Before logging in, please solve the following CAPTCHA').'</p>'.
561 daniel-mar 156
                                        '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'"></div>'.
157
                                        '<script> grecaptcha.render($("#g-recaptcha")[0], { "sitekey" : "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'" }); </script>' : '');
104 daniel-mar 158
                        $out['text'] .= '<br>';
159
 
420 daniel-mar 160
                        // ---------------- Tab control
161
                        $out['text'] .= OIDplus::gui()->tabBarStart();
162
                        $out['text'] .= OIDplus::gui()->tabBarElement('ra',    _L('Login as RA'),            $tab === 'ra');
163
                        $out['text'] .= OIDplus::gui()->tabBarElement('admin', _L('Login as administrator'), $tab === 'admin');
164
                        $out['text'] .= OIDplus::gui()->tabBarEnd();
165
                        $out['text'] .= OIDplus::gui()->tabContentStart();
166
                        // ---------------- "RA" tab
167
                        $tabcont = '<h2>'._L('Login as RA').'</h2>';
104 daniel-mar 168
                        $login_list = OIDplus::authUtils()->loggedInRaList();
169
                        if (count($login_list) > 0) {
115 daniel-mar 170
                                foreach ($login_list as $x) {
549 daniel-mar 171
                                        $tabcont .= '<p>'._L('You are logged in as %1','<b>'.$x->raEmail().'</b>').' (<a href="#" onclick="return OIDplusPagePublicLogin.raLogout('.js_escape($x->raEmail()).');">'._L('Logout').'</a>)</p>';
104 daniel-mar 172
                                }
420 daniel-mar 173
                                $tabcont .= '<p>'._L('If you have more accounts, you can log in with another account here.').'</p>';
104 daniel-mar 174
                        } else {
420 daniel-mar 175
                                $tabcont .= '<p>'._L('Enter your email address and your password to log in as Registration Authority.').'</p>';
104 daniel-mar 176
                        }
549 daniel-mar 177
                        $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicLogin.raLoginOnSubmit(this);">';
559 daniel-mar 178
                        $tabcont .= '<div><label class="padding_label">'._L('E-Mail').':</label><input type="text" name="email" value="'.htmlentities($desired_ra).'" id="raLoginEMail"></div>';
420 daniel-mar 179
                        $tabcont .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="raLoginPassword"></div>';
579 daniel-mar 180
                        if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
585 daniel-mar 181
                                if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreJWT::class)) {
182
                                        if (OIDplus::authUtils()->getExtendedAttribute('oidplus_generator',-1) === OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN) {
183
                                                $att = 'disabled checked';
184
                                        } else {
185
                                                $att = 'disabled';
186
                                        }
187
                                } else if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreSession::class)) {
188
                                        $att = 'disabled';
189
                                } else {
190
                                        $att = '';
191
                                }
192
                                $tabcont .= '<div><input '.$att.' type="checkbox" value="1" id="remember_me_ra" name="remember_me_ra"> <label for="remember_me_ra">'._L('Remember me').'</label></div>';
579 daniel-mar 193
                        }
420 daniel-mar 194
                        $tabcont .= '<br><input type="submit" value="'._L('Login').'"><br><br>';
195
                        $tabcont .= '</form>';
196
                        $tabcont .= '<p><a '.OIDplus::gui()->link('oidplus:forgot_password').'>'._L('Forgot password?').'</a><br>';
104 daniel-mar 197
 
380 daniel-mar 198
                        $invitePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.2.92'); // OIDplusPageRaInvite
199
                        if (!is_null($invitePlugin) && OIDplus::config()->getValue('ra_invitation_enabled')) {
420 daniel-mar 200
                                $tabcont .= '<abbr title="'._L('To receive login data, the superior RA needs to send you an invitation. After creating or updating your OID, the system will ask them if they want to send you an invitation. If they accept, you will receive an email with an activation link. Alternatively, the system admin can create your account manually in the administrator control panel.').'">'._L('How to register?').'</abbr></p>';
156 daniel-mar 201
                        } else {
420 daniel-mar 202
                                $tabcont .= '<abbr title="'._L('Since invitations are disabled at this OIDplus system, the system administrator needs to create your account manually in the administrator control panel.').'">'._L('How to register?').'</abbr></p>';
156 daniel-mar 203
                        }
430 daniel-mar 204
 
431 daniel-mar 205
                        if ($tab === 'ra') {
206
                                $alt_logins_html = array();
207
                                foreach (OIDplus::getPagePlugins() as $plugin) {
208
                                        if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.5')) {
209
                                                $logins = $plugin->alternativeLoginMethods();
210
                                                foreach ($logins as $data) {
211
                                                        if (isset($data[2]) && !empty($data[2])) {
212
                                                                $img = '<img src="'.$data[2].'" alt="'.htmlentities($data[1]).'"> ';
213
                                                        } else {
214
                                                                $img = '';
215
                                                        }
216
                                                        $alt_logins_html[] = $img.'<a '.OIDplus::gui()->link($data[0]).'>'.htmlentities($data[1]).'</a>';
430 daniel-mar 217
                                                }
218
                                        }
219
                                }
431 daniel-mar 220
                                if (count($alt_logins_html) > 0) {
221
                                        $tabcont .= '<p>'._L('Alternative login methods').':<br>';
222
                                        foreach ($alt_logins_html as $alt_login) {
223
                                                $tabcont .= $alt_login.'<br>';
224
                                        }
225
                                        $tabcont .= '</p>';
430 daniel-mar 226
                                }
227
                        }
228
 
431 daniel-mar 229
                        $out['text'] .= OIDplus::gui()->tabContentPage('ra', $tabcont, $tab === 'ra');
420 daniel-mar 230
                        // ---------------- "Administrator" tab
231
                        $tabcont = '<h2>'._L('Login as administrator').'</h2>';
549 daniel-mar 232
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
420 daniel-mar 233
                                $tabcont .= '<p>'._L('You are logged in as administrator.').'</p>';
549 daniel-mar 234
                                $tabcont .= '<a href="#" onclick="return OIDplusPagePublicLogin.adminLogout();">'._L('Logout').'</a>';
104 daniel-mar 235
                        } else {
549 daniel-mar 236
                                $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicLogin.adminLoginOnSubmit(this);">';
420 daniel-mar 237
                                $tabcont .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="adminLoginPassword"></div>';
579 daniel-mar 238
                                if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_ADMIN', true)) {
585 daniel-mar 239
                                        if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreJWT::class)) {
240
                                                if (OIDplus::authUtils()->getExtendedAttribute('oidplus_generator',-1) === OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN) {
241
                                                        $att = 'disabled checked';
242
                                                } else {
243
                                                        $att = 'disabled';
244
                                                }
245
                                        } else if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreSession::class)) {
246
                                                $att = 'disabled';
247
                                        } else {
248
                                                $att = '';
249
                                        }
250
                                        $tabcont .= '<div><input '.$att.' type="checkbox" value="1" id="remember_me_admin" name="remember_me_admin"> <label for="remember_me_admin">'._L('Remember me').'</label></div>';
579 daniel-mar 251
                                }
420 daniel-mar 252
                                $tabcont .= '<br><input type="submit" value="'._L('Login').'"><br><br>';
253
                                $tabcont .= '</form>';
254
                                $tabcont .= '<p><a '.OIDplus::gui()->link('oidplus:forgot_password_admin').'>'._L('Forgot password?').'</a><br>';
104 daniel-mar 255
                        }
420 daniel-mar 256
                        $out['text'] .= OIDplus::gui()->tabContentPage('admin', $tabcont, $tab === 'admin');
257
                        $out['text'] .= OIDplus::gui()->tabContentEnd();
258
                        // ---------------- Tab control END
104 daniel-mar 259
 
420 daniel-mar 260
                        $out['text'] .= '</div><br>';
261
 
360 daniel-mar 262
                        $mins = ceil(OIDplus::baseConfig()->getValue('SESSION_LIFETIME', 30*60)/60);
263
                        $out['text'] .= '<p><font size="-1">'._L('<i>Privacy information</i>: By using the login functionality, you are accepting that a "session cookie" is temporarily stored in your browser. The session cookie is a small text file that is sent to this website every time you visit it, to identify you as an already logged in user. It does not track any of your online activities outside OIDplus. The cookie will be destroyed when you log out or after an inactivity of %1 minutes.', $mins);
296 daniel-mar 264
                        $privacy_document_file = 'OIDplus/privacy_documentation.html';
380 daniel-mar 265
                        $resourcePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.1.500'); // OIDplusPagePublicResources
496 daniel-mar 266
                        if (!is_null($resourcePlugin) && file_exists(OIDplus::localpath().'res/'.$privacy_document_file)) {
470 daniel-mar 267
                                $out['text'] .= ' <a '.OIDplus::gui()->link('oidplus:resources$'.$privacy_document_file.'#cookies').'>'._L('More information about the cookies used').'</a>';
219 daniel-mar 268
                        }
269
                        $out['text'] .= '</font></p></div>';
107 daniel-mar 270
 
561 daniel-mar 271
                        $out['text'] .= '<script>$("#loginArea")[0].style.visibility = "visible";</script>';
104 daniel-mar 272
                }
273
        }
295 daniel-mar 274
 
282 daniel-mar 275
        public function publicSitemap(&$out) {
360 daniel-mar 276
                $out[] = 'oidplus:login';
282 daniel-mar 277
        }
104 daniel-mar 278
 
106 daniel-mar 279
        public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
104 daniel-mar 280
                $loginChildren = array();
281
 
549 daniel-mar 282
                if (OIDplus::authUtils()->isAdminLoggedIn()) {
104 daniel-mar 283
                        $ra_roots = array();
284
 
281 daniel-mar 285
                        foreach (OIDplus::getPagePlugins() as $plugin) {
286
                                if (is_subclass_of($plugin, OIDplusPagePluginAdmin::class)) {
287
                                        $plugin->tree($ra_roots);
288
                                }
104 daniel-mar 289
                        }
290
 
291
                        $ra_roots[] = array(
292
                                'id'       => 'oidplus:logout$admin',
241 daniel-mar 293
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_logout.png',
549 daniel-mar 294
                                'conditionalselect' => 'OIDplusPagePublicLogin.adminLogout(); false;',
355 daniel-mar 295
                                'text'     => _L('Log out')
104 daniel-mar 296
                        );
297
                        $loginChildren[] = array(
298
                                'id'       => 'oidplus:dummy$'.md5(rand()),
355 daniel-mar 299
                                'text'     => _L("Logged in as admin"),
241 daniel-mar 300
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_admin.png',
104 daniel-mar 301
                                'conditionalselect' => 'false', // dummy node that can't be selected
302
                                'state'    => array("opened" => true),
303
                                'children' => $ra_roots
304
                        );
305
                }
306
 
549 daniel-mar 307
                foreach (OIDplus::authUtils()->loggedInRaList() as $ra) {
115 daniel-mar 308
                        $ra_email = $ra->raEmail();
104 daniel-mar 309
                        $ra_roots = array();
310
 
281 daniel-mar 311
                        foreach (OIDplus::getPagePlugins() as $plugin) {
312
                                if (is_subclass_of($plugin, OIDplusPagePluginRa::class)) {
313
                                        $plugin->tree($ra_roots, $ra_email);
314
                                }
104 daniel-mar 315
                        }
316
 
317
                        $ra_roots[] = array(
318
                                'id'       => 'oidplus:logout$'.$ra_email,
549 daniel-mar 319
                                'conditionalselect' => 'OIDplusPagePublicLogin.raLogout('.js_escape($ra_email).'); false;',
241 daniel-mar 320
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_logout.png',
355 daniel-mar 321
                                'text'     => _L('Log out')
104 daniel-mar 322
                        );
323
                        foreach (OIDplusObject::getRaRoots($ra_email) as $loc_root) {
324
                                $ico = $loc_root->getIcon();
325
                                $ra_roots[] = array(
326
                                        'id' => 'oidplus:raroot$'.$loc_root->nodeId(),
360 daniel-mar 327
                                        'text' => _L('Jump to RA root %1',$loc_root->objectTypeTitleShort().' '.$loc_root->crudShowId(OIDplusObject::parse($loc_root::root()))),
512 daniel-mar 328
                                        'conditionalselect' => 'openOidInPanel('.js_escape($loc_root->nodeId()).', true); false;',
241 daniel-mar 329
                                        'icon' => !is_null($ico) ? $ico : OIDplus::webpath(__DIR__).'treeicon_link.png'
104 daniel-mar 330
                                );
331
                        }
332
                        $ra_email_or_name = (new OIDplusRA($ra_email))->raName();
333
                        if ($ra_email_or_name == '') $ra_email_or_name = $ra_email;
334
                        $loginChildren[] = array(
335
                                'id'       => 'oidplus:dummy$'.md5(rand()),
360 daniel-mar 336
                                'text'     => _L('Logged in as %1',htmlentities($ra_email_or_name)),
241 daniel-mar 337
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_ra.png',
104 daniel-mar 338
                                'conditionalselect' => 'false', // dummy node that can't be selected
339
                                'state'    => array("opened" => true),
340
                                'children' => $ra_roots
341
                        );
342
                }
343
 
344
                $json[] = array(
345
                        'id'       => 'oidplus:login',
241 daniel-mar 346
                        'icon'     => OIDplus::webpath(__DIR__).'treeicon_login.png',
355 daniel-mar 347
                        'text'     => _L('Login'),
104 daniel-mar 348
                        'state'    => array("opened" => count($loginChildren)>0),
349
                        'children' => $loginChildren
350
                );
351
 
352
                return true;
353
        }
108 daniel-mar 354
 
355
        public function tree_search($request) {
356
                return false;
357
        }
382 daniel-mar 358
}