Subversion Repositories oidplus

Rev

Rev 702 | Rev 801 | Go to most recent revision | Details | Compare with Previous | 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
 
702 daniel-mar 102
                        OIDplus::getActiveCaptchaPlugin()->captchaVerify($params, 'captcha');
635 daniel-mar 103
 
104
                        _CheckParamExists($params, 'email');
105
                        _CheckParamExists($params, 'password');
106
 
107
                        $upn = $params['email'];
108
                        $password = $params['password'];
109
 
110
                        $domainNumber = $this->getDomainNumber($upn);
111
                        if ($domainNumber <= 0) {
112
                                throw new OIDplusException(_L('The server is not configured to handle this domain (the part behind the at-sign)'));
113
                        }
114
                        $cfgSuffix = $domainNumber == 1 ? '' : "__$domainNumber";
115
 
116
                        if (empty($upn)) {
117
                                throw new OIDplusException(_L('Please enter a valid username'));
118
                        }
119
 
120
                        $ldap = new VtsLDAPUtils();
121
 
122
                        try {
123
 
124
                                $cfg_ldap_server      = OIDplus::baseConfig()->getValue('LDAP_SERVER'.$cfgSuffix);
125
                                $cfg_ldap_port        = OIDplus::baseConfig()->getValue('LDAP_PORT'.$cfgSuffix, 389);
126
                                $cfg_ldap_base_dn     = OIDplus::baseConfig()->getValue('LDAP_BASE_DN'.$cfgSuffix);
127
 
128
                                // Note: Will throw an Exception if connect fails
129
                                $ldap->connect($cfg_ldap_server, $cfg_ldap_port);
130
 
131
                                if (!$ldap->login($upn, $password)) {
132
                                        if (OIDplus::config()->getValue('log_failed_ra_logins', false)) {
133
                                                OIDplus::logger()->log("[WARN]A!", "Failed login to RA account '$upn' using LDAP");
134
                                        }
135
                                        throw new OIDplusException(_L('Wrong password or user not registered'));
136
                                }
137
 
138
                                $ldap_userinfo = $ldap->getUserInfo($upn, $cfg_ldap_base_dn);
139
 
140
                                if (!$ldap_userinfo) {
141
                                        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"));
142
                                }
143
 
144
                                $foundSomething = false;
145
 
146
                                // ---
147
 
148
                                $cfgAdminGroup = OIDplus::baseConfig()->getValue('LDAP_ADMIN_GROUP'.$cfgSuffix,'');
149
                                if (!empty($cfgAdminGroup)) {
150
                                        $isAdmin = $ldap->isMemberOfRec($ldap_userinfo, $cfgAdminGroup);
151
                                } else {
152
                                        $isAdmin = false;
153
                                }
154
                                if ($isAdmin) {
155
                                        $foundSomething = true;
156
                                        $remember_me = isset($params['remember_me']) && ($params['remember_me']);
157
                                        OIDplus::authUtils()->adminLoginEx($remember_me, 'LDAP login');
158
                                }
159
 
160
                                // ---
161
 
162
                                $cfgRaGroup = OIDplus::baseConfig()->getValue('LDAP_RA_GROUP'.$cfgSuffix,'');
163
                                if (!empty($cfgRaGroup)) {
164
                                        $isRA = $ldap->isMemberOfRec($ldap_userinfo, $cfgRaGroup);
165
                                } else {
166
                                        $isRA = true;
167
                                }
168
                                if ($isRA) {
169
                                        if (OIDplus::baseConfig()->getValue('LDAP_AUTHENTICATE_UPN'.$cfgSuffix,true)) {
170
                                                $mail = VtsLDAPUtils::getString($ldap_userinfo, 'userprincipalname');
171
                                                $foundSomething = true;
172
                                                $remember_me = isset($params['remember_me']) && ($params['remember_me']);
173
                                                $this->doLoginRA($remember_me, $mail, $ldap_userinfo);
174
                                        }
175
                                        if (OIDplus::baseConfig()->getValue('LDAP_AUTHENTICATE_EMAIL'.$cfgSuffix,false)) {
176
                                                $mails = VtsLDAPUtils::getArray($ldap_userinfo, 'mail');
177
                                                foreach ($mails as $mail) {
178
                                                        $foundSomething = true;
179
                                                        $remember_me = isset($params['remember_me']) && ($params['remember_me']);
180
                                                        $this->doLoginRA($remember_me, $mail, $ldap_userinfo);
181
                                                }
182
                                        }
183
                                }
184
 
185
                        } finally {
186
                                $ldap->disconnect();
187
                                $ldap = null;
188
                        }
189
 
190
                        if (!$foundSomething) {
191
                                throw new OIDplusException(_L("Error: These credentials cannot be used with OIDplus. Please check the base configuration."));
192
                        }
193
 
194
                        return array("status" => 0);
195
                } else {
196
                        throw new OIDplusException(_L('Unknown action ID'));
197
                }
198
        }
199
 
200
        public function init($html=true) {
201
                // Nothing
202
        }
203
 
204
        public function gui($id, &$out, &$handled) {
205
                if ($id === 'oidplus:login_ldap') {
206
                        $handled = true;
207
                        $out['title'] = _L('Login using LDAP / ActiveDirectory');
800 daniel-mar 208
                        $out['icon']  = OIDplus::webpath(__DIR__,true).'img/main_icon.png';
635 daniel-mar 209
 
210
                        if (!OIDplus::baseConfig()->getValue('LDAP_ENABLED', false)) {
800 daniel-mar 211
                                $out['icon'] = 'img/error.png';
635 daniel-mar 212
                                $out['text'] = _L('LDAP authentication is disabled on this system.');
213
                                return;
214
                        }
215
 
216
                        if (!function_exists('ldap_connect')) {
800 daniel-mar 217
                                $out['icon'] = 'img/error.png';
635 daniel-mar 218
                                $out['text'] = _L('PHP extension "%1" not installed','LDAP');
219
                                return;
220
                        }
221
 
222
                        $out['text'] = '';
223
 
224
                        $out['text'] .= '<noscript>';
225
                        $out['text'] .= '<p>'._L('You need to enable JavaScript to use the login area.').'</p>';
226
                        $out['text'] .= '</noscript>';
227
 
228
                        $out['text'] .= '<div id="loginLdapArea" style="visibility: hidden">';
702 daniel-mar 229
 
230
                        $out['text'] .= OIDplus::getActiveCaptchaPlugin()->captchaGenerate(_L('Before logging in, please solve the following CAPTCHA'));
635 daniel-mar 231
                        $out['text'] .= '<br>';
232
 
233
                        $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>';
234
 
235
                        $out['text'] .= '<h2>'._L('Login as RA').'</h2>';
236
 
237
                        $login_list = OIDplus::authUtils()->loggedInRaList();
238
                        if (count($login_list) > 0) {
239
                                foreach ($login_list as $x) {
240
                                        $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>';
241
                                }
242
                                $out['text'] .= '<p>'._L('If you have more accounts, you can log in with another account here.').'</p>';
243
                        } else {
244
                                $out['text'] .= '<p>'._L('Enter your domain username and your password to log in as Registration Authority.').'</p>';
245
                        }
246
                        $out['text'] .= '<form onsubmit="return OIDplusPagePublicLoginLDAP.raLoginLdapOnSubmit(this);">';
247
                        $out['text'] .= '<div><label class="padding_label">'._L('Username').':</label><input type="text" name="username" value="" id="raLoginLdapUsername">';
248
                        $out['text'] .= '&nbsp;&nbsp;';
249
                        $out['text'] .= '<select id="ldapUpnSuffix" name="upnSuffix">';
250
 
251
                        $numDomains = OIDplus::baseConfig()->getValue('LDAP_NUM_DOMAINS', 1);
252
                        for ($i=1; $i<=$numDomains; $i++) {
253
                                $cfgSuffix = $i == 1 ? '' : "__$i";
254
                                $upnSuffix = OIDplus::baseConfig()->getValue('LDAP_UPN_SUFFIX'.$cfgSuffix, '');
255
                                if ($upnSuffix == '') throw new OIDplusException(_L('Invalid base configuration setting: %1 is missing or empty', 'LDAP_UPN_SUFFIX'.$cfgSuffix));
256
                                $out['text'] .= '<option value="'.htmlentities($upnSuffix).'">'.htmlentities($upnSuffix).'</option>';
257
                        }
258
 
259
                        $out['text'] .= '</select>';
260
                        $out['text'] .= '</div>';
261
                        $out['text'] .= '<div><label class="padding_label">'._L('Password').':</label><input type="password" name="password" value="" id="raLoginLdapPassword"></div>';
262
                        if (OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
263
                                if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreJWT::class)) {
264
                                        if (OIDplus::authUtils()->getExtendedAttribute('oidplus_generator',-1) === OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN) {
265
                                                $att = 'disabled checked';
266
                                        } else {
267
                                                $att = 'disabled';
268
                                        }
269
                                } else if ((OIDplus::authUtils()->getAuthMethod() === OIDplusAuthContentStoreSession::class)) {
270
                                        $att = 'disabled';
271
                                } else {
272
                                        $att = '';
273
                                }
274
                                $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>';
275
                        }
276
                        $out['text'] .= '<br><input type="submit" value="'._L('Login').'"><br><br>';
277
                        $out['text'] .= '</form>';
278
 
279
                        $invitePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.2.92'); // OIDplusPageRaInvite
280
                        $out['text'] .= '<p><abbr title="'._L('You don\'t need to register. Just enter your Windows/Company credentials.').'">'._L('How to register?').'</abbr></p>';
281
 
282
                        $mins = ceil(OIDplus::baseConfig()->getValue('SESSION_LIFETIME', 30*60)/60);
283
                        $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);
284
                        $privacy_document_file = 'OIDplus/privacy_documentation.html';
285
                        $resourcePlugin = OIDplus::getPluginByOid('1.3.6.1.4.1.37476.2.5.2.4.1.500'); // OIDplusPagePublicResources
286
                        if (!is_null($resourcePlugin) && file_exists(OIDplus::localpath().'res/'.$privacy_document_file)) {
287
                                $out['text'] .= ' <a '.OIDplus::gui()->link('oidplus:resources$'.$privacy_document_file.'#cookies').'>'._L('More information about the cookies used').'</a>';
288
                        }
289
                        $out['text'] .= '</font></p></div>';
290
 
291
                        $out['text'] .= '<script>$("#loginLdapArea")[0].style.visibility = "visible";</script>';
292
                }
293
        }
294
 
295
        public function publicSitemap(&$out) {
296
                $out[] = 'oidplus:login_ldap';
297
        }
298
 
299
        public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
300
                return true;
301
        }
302
 
303
        public function tree_search($request) {
304
                return false;
305
        }
306
 
307
        public function implementsFeature($id) {
308
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.5') return true; // alternativeLoginMethods
309
                return false;
310
        }
311
 
312
        public function alternativeLoginMethods() {
313
                $logins = array();
314
                if (OIDplus::baseConfig()->getValue('LDAP_ENABLED', false)) {
315
                        $logins[] = array(
316
                                'oidplus:login_ldap',
317
                                _L('Login using LDAP / ActiveDirectory'),
800 daniel-mar 318
                                OIDplus::webpath(__DIR__,true).'img/main_icon16.png'
635 daniel-mar 319
                        );
320
                }
321
                return $logins;
322
        }
323
}