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 OIDplusPagePublicLoginLdap extends OIDplusPagePluginPublic {
23
 
24
        private function registerRA($ra, $ldap_userinfo) {
25
                $email = $ra->raEmail();
26
 
27
                $ra->register_ra(null); // create a user account without password
28
 
29
                /*
30
                OIDplus DB Field          ActiveDirectory field
31
                ------------------------------------------------
32
                ra_name                   cn
33
                personal_name             displayname (or: givenname + " " + sn)
34
                organization              company
35
                office                    physicaldeliveryofficename or department
36
                street                    streetaddress
37
                zip_town                  postalcode + " " + l
38
                country                   co (human-readable) or c (ISO country code)
39
                phone                     telephonenumber or homephone
40
                mobile                    mobile
41
                fax                       facsimiletelephonenumber
42
                (none)                    wwwhomepage
43
                */
44
 
45
                $opuserdata = array();
46
                $opuserdata['ra_name'] = VtsLDAPUtils::getString($ldap_userinfo,'cn');
47
                if (!empty(VtsLDAPUtils::getString($ldap_userinfo,'displayname'))) {
48
                        $opuserdata['personal_name'] = VtsLDAPUtils::getString($ldap_userinfo,'displayname');
49
                } else {
50
                        $opuserdata['personal_name'] = trim(VtsLDAPUtils::getString($ldap_userinfo,'givenname').' '.VtsLDAPUtils::getString($ldap_userinfo,'sn'));
51
                }
52
                $opuserdata['organization'] = VtsLDAPUtils::getString($ldap_userinfo,'company');
53
                if (!empty(VtsLDAPUtils::getString($ldap_userinfo,'physicaldeliveryofficename'))) {
54
                        $opuserdata['office'] = VtsLDAPUtils::getString($ldap_userinfo,'physicaldeliveryofficename');
55
                } else {
56
                        $opuserdata['office'] = VtsLDAPUtils::getString($ldap_userinfo,'department');
57
                }
58
                $opuserdata['street'] = VtsLDAPUtils::getString($ldap_userinfo,'streetaddress');
59
                $opuserdata['zip_town'] = trim(VtsLDAPUtils::getString($ldap_userinfo,'postalcode').' '.VtsLDAPUtils::getString($ldap_userinfo,'l'));
60
                $opuserdata['country'] = VtsLDAPUtils::getString($ldap_userinfo,'co'); // ISO country code: VtsLDAPUtils::getString($ldap_userinfo,'c')
61
                $opuserdata['phone'] = VtsLDAPUtils::getString($ldap_userinfo,'telephonenumber'); // homephone for private phone number
62
                $opuserdata['mobile'] = VtsLDAPUtils::getString($ldap_userinfo,'mobile');
63
                $opuserdata['fax'] = VtsLDAPUtils::getString($ldap_userinfo,'facsimiletelephonenumber');
64
 
65
                foreach ($opuserdata as $dbfield => $val) {
66
                        if (!empty($val)) {
67
                                OIDplus::db()->query("update ###ra set ".$dbfield." = ? where email = ?", array($val, $email));
68
                        }
69
                }
70
        }
71
 
72
        private function doLoginRA($remember_me, $email, $ldap_userinfo) {
73
                $ra = new OIDplusRA($email);
74
                if (!$ra->existing()) {
75
                        $this->registerRA($ra, $ldap_userinfo);
76
                        OIDplus::logger()->log("[INFO]RA($email)!", "RA '$email' was created because of successful LDAP login");
77
                }
78
 
79
                OIDplus::authUtils()->raLoginEx($email, $remember_me, 'LDAP');
80
 
81
                OIDplus::db()->query("UPDATE ###ra set last_login = ".OIDplus::db()->sqlDate()." where email = ?", array($email));
82
        }
83
 
84
        private function getDomainNumber($upn) {
85
                $numDomains = OIDplus::baseConfig()->getValue('LDAP_NUM_DOMAINS', 1);
86
                for ($i=1; $i<=$numDomains; $i++) {
87
                        $cfgSuffix = $i == 1 ? '' : "__$i";
88
                        $upnSuffix = OIDplus::baseConfig()->getValue('LDAP_UPN_SUFFIX'.$cfgSuffix, '');
89
                        if (str_ends_with($upn, $upnSuffix)) return $i;
90
                }
91
                return -1;
92
        }
93
 
94
        public function action($actionID, $params) {
95
                if ($actionID == 'ra_login_ldap') {
96
                        if (!OIDplus::baseConfig()->getValue('LDAP_ENABLED', false)) {
97
                                throw new OIDplusException(_L('LDAP authentication is disabled on this system.'));
98
                        }
99
 
100
                        if (!function_exists('ldap_connect')) throw new OIDplusConfigInitializationException(_L('PHP extension "%1" not installed','LDAP'));
101
 
102
                        if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
103
                                $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
104
                                _CheckParamExists($params, 'captcha');
105
                                $response=$params["captcha"];
106
                                $verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
107
                                $captcha_success=json_decode($verify);
108
                                if ($captcha_success->success==false) {
109
                                        throw new OIDplusException(_L('CAPTCHA not successfully verified'));
110
                                }
111
                        }
112
 
113
                        _CheckParamExists($params, 'email');
114
                        _CheckParamExists($params, 'password');
115
 
116
                        $upn = $params['email'];
117
                        $password = $params['password'];
118
 
119
                        $domainNumber = $this->getDomainNumber($upn);
120
                        if ($domainNumber <= 0) {
121
                                throw new OIDplusException(_L('The server is not configured to handle this domain (the part behind the at-sign)'));
122
                        }
123
                        $cfgSuffix = $domainNumber == 1 ? '' : "__$domainNumber";
124
 
125
                        if (empty($upn)) {
126
                                throw new OIDplusException(_L('Please enter a valid username'));
127
                        }
128
 
129
                        $ldap = new VtsLDAPUtils();
130
 
131
                        try {
132
 
133
                                $cfg_ldap_server      = OIDplus::baseConfig()->getValue('LDAP_SERVER'.$cfgSuffix);
134
                                $cfg_ldap_port        = OIDplus::baseConfig()->getValue('LDAP_PORT'.$cfgSuffix, 389);
135
                                $cfg_ldap_base_dn     = OIDplus::baseConfig()->getValue('LDAP_BASE_DN'.$cfgSuffix);
136
 
137
                                // Note: Will throw an Exception if connect fails
138
                                $ldap->connect($cfg_ldap_server, $cfg_ldap_port);
139
 
140
                                if (!$ldap->login($upn, $password)) {
141
                                        if (OIDplus::config()->getValue('log_failed_ra_logins', false)) {
142
                                                OIDplus::logger()->log("[WARN]A!", "Failed login to RA account '$upn' using LDAP");
143
                                        }
144
                                        throw new OIDplusException(_L('Wrong password or user not registered'));
145
                                }
146
 
147
                                $ldap_userinfo = $ldap->getUserInfo($upn, $cfg_ldap_base_dn);
148
 
149
                                if (!$ldap_userinfo) {
150
                                        throw new OIDplusException(_L('The LDAP login was successful, but the own user %1 cannot be found. Please check the base configuration setting %2 and %3', $upn, "LDAP_BASE_DN$cfgSuffix", "LDAP_UPN_SUFFIX$cfgSuffix"));
151
                                }
152
 
153
                                $foundSomething = false;
154
 
155
                                // ---
156
 
157
                                $cfgAdminGroup = OIDplus::baseConfig()->getValue('LDAP_ADMIN_GROUP'.$cfgSuffix,'');
158
                                if (!empty($cfgAdminGroup)) {
159
                                        $isAdmin = $ldap->isMemberOfRec($ldap_userinfo, $cfgAdminGroup);
160
                                } else {
161
                                        $isAdmin = false;
162
                                }
163
                                if ($isAdmin) {
164
                                        $foundSomething = true;
165
                                        $remember_me = isset($params['remember_me']) && ($params['remember_me']);
166
                                        OIDplus::authUtils()->adminLoginEx($remember_me, 'LDAP login');
167
                                }
168
 
169
                                // ---
170
 
171
                                $cfgRaGroup = OIDplus::baseConfig()->getValue('LDAP_RA_GROUP'.$cfgSuffix,'');
172
                                if (!empty($cfgRaGroup)) {
173
                                        $isRA = $ldap->isMemberOfRec($ldap_userinfo, $cfgRaGroup);
174
                                } else {
175
                                        $isRA = true;
176
                                }
177
                                if ($isRA) {
178
                                        if (OIDplus::baseConfig()->getValue('LDAP_AUTHENTICATE_UPN'.$cfgSuffix,true)) {
179
                                                $mail = VtsLDAPUtils::getString($ldap_userinfo, 'userprincipalname');
180
                                                $foundSomething = true;
181
                                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
182
                                                $this->doLoginRA($remember_me, $mail, $ldap_userinfo);
183
                                        }
184
                                        if (OIDplus::baseConfig()->getValue('LDAP_AUTHENTICATE_EMAIL'.$cfgSuffix,false)) {
185
                                                $mails = VtsLDAPUtils::getArray($ldap_userinfo, 'mail');
186
                                                foreach ($mails as $mail) {
187
                                                        $foundSomething = true;
188
                                                        $remember_me = isset($params['remember_me']) && ($params['remember_me']);
189
                                                        $this->doLoginRA($remember_me, $mail, $ldap_userinfo);
190
                                                }
191
                                        }
192
                                }
193
 
194
                        } finally {
195
                                $ldap->disconnect();
196
                                $ldap = null;
197
                        }
198
 
199
                        if (!$foundSomething) {
200
                                throw new OIDplusException(_L("Error: These credentials cannot be used with OIDplus. Please check the base configuration."));
201
                        }
202
 
203
                        return array("status" => 0);
204
                } else {
205
                        throw new OIDplusException(_L('Unknown action ID'));
206
                }
207
        }
208
 
209
        public function init($html=true) {
210
                // Nothing
211
        }
212
 
213
        public function gui($id, &$out, &$handled) {
214
                if ($id === 'oidplus:login_ldap') {
215
                        $handled = true;
216
                        $out['title'] = _L('Login using LDAP / ActiveDirectory');
217
                        $out['icon']  = OIDplus::webpath(__DIR__).'icon_big.png';
218
 
219
                        if (!OIDplus::baseConfig()->getValue('LDAP_ENABLED', false)) {
220
                                $out['icon'] = 'img/error_big.png';
221
                                $out['text'] = _L('LDAP authentication is disabled on this system.');
222
                                return;
223
                        }
224
 
225
                        if (!function_exists('ldap_connect')) {
226
                                $out['icon'] = 'img/error_big.png';
227
                                $out['text'] = _L('PHP extension "%1" not installed','LDAP');
228
                                return;
229
                        }
230
 
231
                        $out['text'] = '';
232
 
233
                        $out['text'] .= '<noscript>';
234
                        $out['text'] .= '<p>'._L('You need to enable JavaScript to use the login area.').'</p>';
235
                        $out['text'] .= '</noscript>';
236
 
237
                        $out['text'] .= '<div id="loginLdapArea" style="visibility: hidden">';
238
                        $out['text'] .= (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false) ?
239
                                        '<p>'._L('Before logging in, please solve the following CAPTCHA').'</p>'.
240
                                        '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'"></div>'.
241
                                        '<script> grecaptcha.render($("#g-recaptcha")[0], { "sitekey" : "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'" }); </script>' : '');
242
                        $out['text'] .= '<br>';
243
 
244
                        $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:login').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Regular login method').'</a></p>';
245
 
246
                        $out['text'] .= '<h2>'._L('Login as RA').'</h2>';
247
 
248
                        $login_list = OIDplus::authUtils()->loggedInRaList();
249
                        if (count($login_list) > 0) {
250
                                foreach ($login_list as $x) {
251
                                        $out['text'] .= '<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>';
252
                                }
253
                                $out['text'] .= '<p>'._L('If you have more accounts, you can log in with another account here.').'</p>';
254
                        } else {
255
                                $out['text'] .= '<p>'._L('Enter your domain username and your password to log in as Registration Authority.').'</p>';
256
                        }
257
                        $out['text'] .= '<form onsubmit="return OIDplusPagePublicLoginLDAP.raLoginLdapOnSubmit(this);">';
258
                        $out['text'] .= '<div><label class="padding_label">'._L('Username').':</label><input type="text" name="username" value="" id="raLoginLdapUsername">';
259
                        $out['text'] .= '&nbsp;&nbsp;';
260
                        $out['text'] .= '<select id="ldapUpnSuffix" name="upnSuffix">';
261
 
262
                        $numDomains = OIDplus::baseConfig()->getValue('LDAP_NUM_DOMAINS', 1);
263
                        for ($i=1; $i<=$numDomains; $i++) {
264
                                $cfgSuffix = $i == 1 ? '' : "__$i";
265
                                $upnSuffix = OIDplus::baseConfig()->getValue('LDAP_UPN_SUFFIX'.$cfgSuffix, '');
266
                                if ($upnSuffix == '') throw new OIDplusException(_L('Invalid base configuration setting: %1 is missing or empty', 'LDAP_UPN_SUFFIX'.$cfgSuffix));
267
                                $out['text'] .= '<option value="'.htmlentities($upnSuffix).'">'.htmlentities($upnSuffix).'</option>';
268
                        }
269
 
270
                        $out['text'] .= '</select>';
271
                        $out['text'] .= '</div>';
272
                        $out['text'] .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="raLoginLdapPassword"></div>';
273
                        if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
274
                                if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreJWT::class)) {
275
                                        if (OIDplus::authUtils()->getExtendedAttribute('oidplus_generator',-1) === OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN) {
276
                                                $att = 'disabled checked';
277
                                        } else {
278
                                                $att = 'disabled';
279
                                        }
280
                                } else if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreSession::class)) {
281
                                        $att = 'disabled';
282
                                } else {
283
                                        $att = '';
284
                                }
285
                                $out['text'] .= '<div><input '.$att.' type="checkbox" value="1" id="remember_me_ldap" name="remember_me_ldap"> <label for="remember_me_ldap">'._L('Remember me').'</label></div>';
286
                        }
287
                        $out['text'] .= '<br><input type="submit" value="'._L('Login').'"><br><br>';
288
                        $out['text'] .= '</form>';
289
 
290
                        $invitePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.2.92'); // OIDplusPageRaInvite
291
                        $out['text'] .= '<p><abbr title="'._L('You don\'t need to register. Just enter your Windows/Company credentials.').'">'._L('How to register?').'</abbr></p>';
292
 
293
                        $mins = ceil(OIDplus::baseConfig()->getValue('SESSION_LIFETIME', 30*60)/60);
294
                        $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);
295
                        $privacy_document_file = 'OIDplus/privacy_documentation.html';
296
                        $resourcePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.1.500'); // OIDplusPagePublicResources
297
                        if (!is_null($resourcePlugin) && file_exists(OIDplus::localpath().'res/'.$privacy_document_file)) {
298
                                $out['text'] .= ' <a '.OIDplus::gui()->link('oidplus:resources$'.$privacy_document_file.'#cookies').'>'._L('More information about the cookies used').'</a>';
299
                        }
300
                        $out['text'] .= '</font></p></div>';
301
 
302
                        $out['text'] .= '<script>$("#loginLdapArea")[0].style.visibility = "visible";</script>';
303
                }
304
        }
305
 
306
        public function publicSitemap(&$out) {
307
                $out[] = 'oidplus:login_ldap';
308
        }
309
 
310
        public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
311
                return true;
312
        }
313
 
314
        public function tree_search($request) {
315
                return false;
316
        }
317
 
318
        public function implementsFeature($id) {
319
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.5') return true; // alternativeLoginMethods
320
                return false;
321
        }
322
 
323
        public function alternativeLoginMethods() {
324
                $logins = array();
325
                if (OIDplus::baseConfig()->getValue('LDAP_ENABLED', false)) {
326
                        $logins[] = array(
327
                                'oidplus:login_ldap',
328
                                _L('Login using LDAP / ActiveDirectory'),
329
                                OIDplus::webpath(__DIR__).'treeicon.png'
330
                        );
331
                }
332
                return $logins;
333
        }
334
}