Subversion Repositories oidplus

Rev

Rev 702 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
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
 
20
if (!defined('INSIDE_OIDPLUS')) die();
21
 
22
class OIDplusPagePublicLogin extends OIDplusPagePluginPublic {
23
 
24
        public function action($actionID, $params) {
25
                // === RA LOGIN/LOGOUT ===
26
 
27
                if ($actionID == 'ra_login') {
28
                        if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
29
                                $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
30
                                _CheckParamExists($params, 'captcha');
31
                                $response=$params["captcha"];
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) {
35
                                        throw new OIDplusException(_L('CAPTCHA not successfully verified'));
36
                                }
37
                        }
38
 
39
                        _CheckParamExists($params, 'email');
40
                        _CheckParamExists($params, 'password');
41
 
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
 
49
                        if ($ra->checkPassword($params['password'])) {
50
                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
51
                                OIDplus::authUtils()->raLoginEx($email, $remember_me, 'Regular login');
52
 
53
                                OIDplus::db()->query("UPDATE ###ra set last_login = ".OIDplus::db()->sqlDate()." where email = ?", array($email));
54
 
55
                                return array("status" => 0);
56
                        } else {
57
                                if (OIDplus::config()->getValue('log_failed_ra_logins', false)) {
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
                                        }
63
                                }
64
                                throw new OIDplusException(_L('Wrong password or user not registered'));
65
                        }
66
 
67
                } else if ($actionID == 'ra_logout') {
68
 
69
                        _CheckParamExists($params, 'email');
70
 
71
                        $email = $params['email'];
72
 
73
                        OIDplus::authUtils()->raLogoutEx($email);
74
 
75
                        return array("status" => 0);
76
                }
77
 
78
                // === ADMIN LOGIN/LOGOUT ===
79
 
80
                else if ($actionID == 'admin_login') {
81
                        if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
82
                                $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
83
                                _CheckParamExists($params, 'captcha');
84
                                $response=$params["captcha"];
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) {
88
                                        throw new OIDplusException(_L('CAPTCHA not successfully verified'));
89
                                }
90
                        }
91
 
92
                        _CheckParamExists($params, 'password');
93
                        if (OIDplus::authUtils()->adminCheckPassword($params['password'])) {
94
                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
95
                                OIDplus::authUtils()->adminLoginEx($remember_me, 'Regular login');
96
 
97
                                // TODO: Write a "last login" entry in config table?
98
 
99
                                return array("status" => 0);
100
                        } else {
101
                                if (OIDplus::config()->getValue('log_failed_admin_logins', false)) {
102
                                        OIDplus::logger()->log("[WARN]A!", "Failed login to admin account");
103
                                }
104
                                throw new OIDplusException(_L('Wrong password'));
105
                        }
106
                }
107
                else if ($actionID == 'admin_logout') {
108
                        OIDplus::authUtils()->adminLogoutEx();
109
 
110
                        return array("status" => 0);
111
                }
112
                else {
113
                        throw new OIDplusException(_L('Unknown action ID'));
114
                }
115
        }
116
 
117
        public function init($html=true) {
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)))) {
120
                                throw new OIDplusException(_L('Valid values: 0 (off) or 1 (on).'));
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)))) {
125
                                throw new OIDplusException(_L('Valid values: 0 (off) or 1 (on).'));
126
                        }
127
                });
128
        }
129
 
130
        public function gui($id, &$out, &$handled) {
131
                $ary = explode('$', $id);
132
                $desired_ra = '';
133
                if (isset($ary[1])) {
134
                        $id = $ary[0];
135
                        $tab = $ary[1];
136
                        if (isset($ary[2])) {
137
                                $desired_ra = $ary[2];
138
                        }
139
                } else {
140
                        $tab = 'ra';
141
                }
142
                if ($id === 'oidplus:login') {
143
                        $handled = true;
144
                        $out['title'] = _L('Login');
145
                        $out['icon']  = OIDplus::webpath(__DIR__).'login_big.png';
146
 
147
                        $out['text'] = '';
148
 
149
                        $out['text'] .= '<noscript>';
150
                        $out['text'] .= '<p>'._L('You need to enable JavaScript to use the login area.').'</p>';
151
                        $out['text'] .= '</noscript>';
152
 
153
                        $out['text'] .= '<div id="loginArea" style="visibility: hidden"><div id="loginTab" class="container" style="width:100%;">';
154
                        $out['text'] .= (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false) ?
155
                                        '<p>'._L('Before logging in, please solve the following CAPTCHA').'</p>'.
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>' : '');
158
                        $out['text'] .= '<br>';
159
 
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>';
168
                        $login_list = OIDplus::authUtils()->loggedInRaList();
169
                        if (count($login_list) > 0) {
170
                                foreach ($login_list as $x) {
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>';
172
                                }
173
                                $tabcont .= '<p>'._L('If you have more accounts, you can log in with another account here.').'</p>';
174
                        } else {
175
                                $tabcont .= '<p>'._L('Enter your email address and your password to log in as Registration Authority.').'</p>';
176
                        }
177
                        $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicLogin.raLoginOnSubmit(this);">';
178
                        $tabcont .= '<div><label class="padding_label">'._L('E-Mail').':</label><input type="text" name="email" value="'.htmlentities($desired_ra).'" id="raLoginEMail"></div>';
179
                        $tabcont .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="raLoginPassword"></div>';
180
                        if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
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>';
193
                        }
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>';
197
 
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')) {
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>';
201
                        } else {
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>';
203
                        }
204
 
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>';
217
                                                }
218
                                        }
219
                                }
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>';
226
                                }
227
                        }
228
 
229
                        $out['text'] .= OIDplus::gui()->tabContentPage('ra', $tabcont, $tab === 'ra');
230
                        // ---------------- "Administrator" tab
231
                        $tabcont = '<h2>'._L('Login as administrator').'</h2>';
232
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
233
                                $tabcont .= '<p>'._L('You are logged in as administrator.').'</p>';
234
                                $tabcont .= '<a href="#" onclick="return OIDplusPagePublicLogin.adminLogout();">'._L('Logout').'</a>';
235
                        } else {
236
                                $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicLogin.adminLoginOnSubmit(this);">';
237
                                $tabcont .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="adminLoginPassword"></div>';
238
                                if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_ADMIN', true)) {
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>';
251
                                }
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>';
255
                        }
256
                        $out['text'] .= OIDplus::gui()->tabContentPage('admin', $tabcont, $tab === 'admin');
257
                        $out['text'] .= OIDplus::gui()->tabContentEnd();
258
                        // ---------------- Tab control END
259
 
260
                        $out['text'] .= '</div><br>';
261
 
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 (except if the "Remember me" option is used).', $mins);
264
                        $privacy_document_file = 'OIDplus/privacy_documentation.html';
265
                        $resourcePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.1.500'); // OIDplusPagePublicResources
266
                        if (!is_null($resourcePlugin) && file_exists(OIDplus::localpath().'res/'.$privacy_document_file)) {
267
                                $out['text'] .= ' <a '.OIDplus::gui()->link('oidplus:resources$'.$privacy_document_file.'#cookies').'>'._L('More information about the cookies used').'</a>';
268
                        }
269
                        $out['text'] .= '</font></p></div>';
270
 
271
                        $out['text'] .= '<script>$("#loginArea")[0].style.visibility = "visible";</script>';
272
                }
273
        }
274
 
275
        public function publicSitemap(&$out) {
276
                $out[] = 'oidplus:login';
277
        }
278
 
279
        public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
280
                $loginChildren = array();
281
 
282
                if (OIDplus::authUtils()->isAdminLoggedIn()) {
283
                        $ra_roots = array();
284
 
285
                        foreach (OIDplus::getPagePlugins() as $plugin) {
286
                                if (is_subclass_of($plugin, OIDplusPagePluginAdmin::class)) {
287
                                        $plugin->tree($ra_roots);
288
                                }
289
                        }
290
 
291
                        $ra_roots[] = array(
292
                                'id'       => 'oidplus:logout$admin',
293
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_logout.png',
294
                                'conditionalselect' => 'OIDplusPagePublicLogin.adminLogout(); false;',
295
                                'text'     => _L('Log out')
296
                        );
297
                        $loginChildren[] = array(
298
                                'id'       => 'oidplus:dummy$'.md5((string)rand()),
299
                                'text'     => _L("Logged in as <b>admin</b>"),
300
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_admin.png',
301
                                'conditionalselect' => 'false', // dummy node that can't be selected
302
                                'state'    => array("opened" => true),
303
                                'children' => $ra_roots
304
                        );
305
                }
306
 
307
                foreach (OIDplus::authUtils()->loggedInRaList() as $ra) {
308
                        $ra_email = $ra->raEmail();
309
                        $ra_roots = array();
310
 
311
                        foreach (OIDplus::getPagePlugins() as $plugin) {
312
                                if (is_subclass_of($plugin, OIDplusPagePluginRa::class)) {
313
                                        $plugin->tree($ra_roots, $ra_email);
314
                                }
315
                        }
316
 
317
                        $ra_roots[] = array(
318
                                'id'       => 'oidplus:logout$'.$ra_email,
319
                                'conditionalselect' => 'OIDplusPagePublicLogin.raLogout('.js_escape($ra_email).'); false;',
320
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_logout.png',
321
                                'text'     => _L('Log out')
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(),
327
                                        'text' => _L('Jump to RA root %1',$loc_root->objectTypeTitleShort().' '.$loc_root->crudShowId(OIDplusObject::parse($loc_root::root()))),
328
                                        'conditionalselect' => 'openOidInPanel('.js_escape($loc_root->nodeId()).', true); false;',
329
                                        'icon' => !is_null($ico) ? $ico : OIDplus::webpath(__DIR__).'treeicon_link.png'
330
                                );
331
                        }
332
                        $ra_email_or_name = (new OIDplusRA($ra_email))->raName();
333
                        if ($ra_email_or_name == '') {
334
                                $ra_email_html = htmlentities($ra_email);
335
                                $ra_email_or_name = '<b>'.$ra_email_html.'</b>';
336
                        } else {
337
                                $ra_email_html = htmlentities($ra_email);
338
                                $ra_email_or_name_html = htmlentities($ra_email_or_name);
339
                                $ra_email_or_name = "<b>$ra_email_or_name_html</b> ($ra_email_html)";
340
                        }
341
                        $loginChildren[] = array(
342
                                'id'       => 'oidplus:dummy$'.md5((string)rand()),
343
                                'text'     => _L('Logged in as %1',$ra_email_or_name),
344
                                'icon'     => OIDplus::webpath(__DIR__).'treeicon_ra.png',
345
                                'conditionalselect' => 'false', // dummy node that can't be selected
346
                                'state'    => array("opened" => true),
347
                                'children' => $ra_roots
348
                        );
349
                }
350
 
351
                $json[] = array(
352
                        'id'       => 'oidplus:login',
353
                        'icon'     => OIDplus::webpath(__DIR__).'treeicon_login.png',
354
                        'text'     => _L('Login'),
355
                        'state'    => array("opened" => count($loginChildren)>0),
356
                        'children' => $loginChildren
357
                );
358
 
359
                return true;
360
        }
361
 
362
        public function tree_search($request) {
363
                return false;
364
        }
365
}