1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* ldap_authentication helper functions
|
6
|
*/
|
7
|
|
8
|
/**
|
9
|
* helper function for ldap_authn_form_user_login_block_alter and ldap_authn_form_user_login_alter
|
10
|
*
|
11
|
* @todo if form is being generated on non https and is set in preferences, set warning and end form development
|
12
|
*/
|
13
|
function _ldap_authentication_login_form_alter(&$form, &$form_state, $form_id) {
|
14
|
|
15
|
if (!$auth_conf = ldap_authentication_get_valid_conf()) {
|
16
|
return;
|
17
|
}
|
18
|
elseif (!$auth_conf->hasEnabledAuthenticationServers()) {
|
19
|
return;
|
20
|
}
|
21
|
|
22
|
/**
|
23
|
*
|
24
|
* add validate function to test for ldap authentication
|
25
|
* should be placed after user_login_authenticate_validate
|
26
|
* 1. user_login_name_validate
|
27
|
* 2. user_login_authenticate_validate
|
28
|
* 3. external authentication validate functions
|
29
|
* 4. user_login_final_validate
|
30
|
*
|
31
|
* as articulated above user_login_default_validators() in user.module
|
32
|
*
|
33
|
* without any other external authentication modules, this array will start out as:
|
34
|
* array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate')
|
35
|
*/
|
36
|
|
37
|
if (@in_array('user_login_authenticate_validate', $form['#validate']) && $auth_conf->authenticationMode) {
|
38
|
$key = array_search('user_login_authenticate_validate', $form['#validate']);
|
39
|
$form['#validate'][$key] = 'ldap_authentication_core_override_user_login_authenticate_validate';
|
40
|
array_splice($form['#validate'], $key + 1, 0, 'ldap_authentication_user_login_authenticate_validate');
|
41
|
}
|
42
|
|
43
|
if ($form_id == 'user_login_block') {
|
44
|
$user_register = variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
|
45
|
$vars = array(
|
46
|
'show_reset_pwd' => ldap_authentication_show_reset_pwd(),
|
47
|
'auth_conf' => $auth_conf,
|
48
|
);
|
49
|
|
50
|
$form['links']['#markup'] = theme('ldap_authentication_user_login_block_links', $vars);
|
51
|
}
|
52
|
ldap_servers_disable_http_check($form);
|
53
|
|
54
|
// Add help information for entering in username/password
|
55
|
$auth_conf = ldap_authentication_get_valid_conf();
|
56
|
if ($auth_conf) {
|
57
|
if (isset($auth_conf->loginUIUsernameTxt)) {
|
58
|
$form['name']['#description'] = t($auth_conf->loginUIUsernameTxt);
|
59
|
}
|
60
|
if (isset($auth_conf->loginUIPasswordTxt)) {
|
61
|
$form['pass']['#description'] = t($auth_conf->loginUIPasswordTxt);
|
62
|
}
|
63
|
if ($auth_conf->templateUsageRedirectOnLogin) {
|
64
|
$form['#submit'][] = 'ldap_authentication_check_for_email_template';
|
65
|
}
|
66
|
}
|
67
|
}
|
68
|
|
69
|
|
70
|
|
71
|
/**
|
72
|
* alter user editing form (profile form) based on ldap authentication configuration
|
73
|
*
|
74
|
* @param array $form array from user profile
|
75
|
* @param array $form_state from user profile
|
76
|
*
|
77
|
* @return NULL (alters $form by reference)
|
78
|
*/
|
79
|
function _ldap_authentication_form_user_profile_form_alter(&$form, $form_state) {
|
80
|
// keep in mind admin may be editing another users profile form. don't assume current global $user
|
81
|
$auth_conf = ldap_authentication_get_valid_conf();
|
82
|
if ($auth_conf && ldap_authentication_ldap_authenticated($form['#user'])) {
|
83
|
if ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_REMOVE) {
|
84
|
$form['account']['mail']['#access'] = FALSE;
|
85
|
}
|
86
|
elseif ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_DISABLE) {
|
87
|
$form['account']['mail']['#disabled'] = TRUE;
|
88
|
$form['account']['mail']['#description'] = t('This email address is automatically set and may not be changed.');
|
89
|
}
|
90
|
elseif ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_ALLOW) {
|
91
|
// email field is functional
|
92
|
}
|
93
|
|
94
|
if (!ldap_authentication_show_reset_pwd($form['#user'])) {
|
95
|
/** If passwordOption = LDAP_AUTHENTICATION_PASSWORD_FIELD_HIDE then don't show the password fields,
|
96
|
otherwise show the fields but in a disabled state.
|
97
|
*/
|
98
|
switch ($auth_conf->passwordOption) {
|
99
|
|
100
|
case LDAP_AUTHENTICATION_PASSWORD_FIELD_HIDE:
|
101
|
$form['account']['current_pass']['#access'] = FALSE;
|
102
|
$form['account']['pass']['#access'] = FALSE;
|
103
|
break;
|
104
|
|
105
|
case LDAP_AUTHENTICATION_PASSWORD_FIELD_SHOW:
|
106
|
// Show in a disabled state since ldap_authentication_show_reset_pwd() has returned FALSE
|
107
|
$form['account']['current_pass']['#disabled'] = TRUE;
|
108
|
if ($auth_conf->ldapUserHelpLinkUrl) {
|
109
|
$form['account']['current_pass']['#description'] = l(t($auth_conf->ldapUserHelpLinkText), $auth_conf->ldapUserHelpLinkUrl);
|
110
|
}
|
111
|
else {
|
112
|
$form['account']['current_pass']['#description'] = t('The password cannot be changed using this website');
|
113
|
}
|
114
|
$form['account']['pass']['#disabled'] = TRUE;
|
115
|
break;
|
116
|
}
|
117
|
}
|
118
|
}
|
119
|
}
|
120
|
|
121
|
/**
|
122
|
* Replaces the email address in $ldap_user with one from the template in
|
123
|
* $auth_conf.
|
124
|
*
|
125
|
* @param array $ldap_user
|
126
|
* LDAP user entry
|
127
|
* @param LdapAuthenticationConf $auth_conf
|
128
|
* LDAP authentication configuration class.
|
129
|
*/
|
130
|
function _ldap_authentication_replace_user_email(&$ldap_user, $auth_conf, $tokens) {
|
131
|
// fallback template in case one was not specified.
|
132
|
$template = '@username@localhost';
|
133
|
if (!empty($auth_conf->emailTemplate)) {
|
134
|
$template = $auth_conf->emailTemplate;
|
135
|
}
|
136
|
$ldap_user['mail'] = format_string($template, $tokens);
|
137
|
}
|
138
|
|
139
|
/**
|
140
|
* user form validation will take care of username, pwd fields
|
141
|
* this function validates ldap authentication specific
|
142
|
*
|
143
|
* @param array $form_state array from user logon form
|
144
|
* @return null, but success or failure is indicated by:
|
145
|
* -- form_set_error() to invalidate authentication process
|
146
|
* -- setting $form_state['uid'] to indicate successful authentication
|
147
|
*/
|
148
|
function _ldap_authentication_user_login_authenticate_validate(&$form_state, $return_user) {
|
149
|
|
150
|
// Check if Flood control was triggered; if so, don't authenticate
|
151
|
if (isset($form_state['flood_control_triggered'])) {
|
152
|
return;
|
153
|
}
|
154
|
|
155
|
$detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
|
156
|
|
157
|
// Default to name
|
158
|
$entered_name = $form_state['values']['name'];
|
159
|
$authname_drupal_property = $form_field_name = 'name';
|
160
|
|
161
|
// Email registration module populates name even though user entered email
|
162
|
if (!empty($form_state['values']['email'])) {
|
163
|
$entered_name = $form_state['values']['email'];
|
164
|
$authname_drupal_property = 'mail';
|
165
|
$form_field_name = 'email';
|
166
|
}
|
167
|
|
168
|
// $authname is the name the user is authenticated with from the logon form // patch 1599632
|
169
|
$authname = $entered_name;
|
170
|
|
171
|
if (empty($form_state['values']['pass']) || empty ($form_state['values'][$form_field_name])) {
|
172
|
return FALSE;
|
173
|
}
|
174
|
/*
|
175
|
* If a fake form state was passed into this function from
|
176
|
* _ldap_authentication_user_login_sso(), there will be a value outside of the
|
177
|
* form_state[values] array to let us know that we are not authenticating with
|
178
|
* a password, but instead just looking up a username/dn in LDAP since the web
|
179
|
* server already authenticated the user.
|
180
|
*/
|
181
|
$sso_login = (isset($form_state['sso_login']) && $form_state['sso_login']) ? TRUE : FALSE;
|
182
|
|
183
|
$watchdog_tokens = array('%username' => $authname, '%authname' => $authname); // $watchdog_tokens = array('%username' => $name); // patch 1599632
|
184
|
if ($detailed_watchdog_log) {
|
185
|
watchdog('ldap_authentication', '%username : Beginning authentification....', $watchdog_tokens, WATCHDOG_DEBUG);
|
186
|
}
|
187
|
|
188
|
if (!$auth_conf = ldap_authentication_get_valid_conf()) {
|
189
|
watchdog('ldap_authentication', 'Failed to get valid ldap authentication configuration.', array(), WATCHDOG_ERROR);
|
190
|
form_set_error('name', 'Server Error: Failed to get valid ldap authentication configuration.' . $error);
|
191
|
return;
|
192
|
}
|
193
|
|
194
|
/**
|
195
|
* I. Test for previous module authentication success.
|
196
|
*
|
197
|
* if already succeeded at authentication, $form_state['uid'] will be set by other authentication module.
|
198
|
* - if LDAP Mixed mode is set, return and don't disrupt authentication process
|
199
|
* - otherwise override other authenication by setting $form_state['uid'] = NULL
|
200
|
*/
|
201
|
if (isset($form_state['uid']) && is_numeric($form_state['uid'])) {
|
202
|
if ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_MIXED || $form_state['uid'] == 1) {
|
203
|
if ($detailed_watchdog_log) {
|
204
|
watchdog('ldap_authentication', '%username : Previously authenticated in mixed mode or uid=1', $watchdog_tokens, WATCHDOG_DEBUG);
|
205
|
}
|
206
|
return; // already passed a previous module's authentication validation
|
207
|
}
|
208
|
elseif ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_EXCLUSIVE) {
|
209
|
if ($detailed_watchdog_log) {
|
210
|
watchdog('ldap_authentication', '%username : Previously authenticated in exclusive mode or uid is not 1. Clear uid
|
211
|
in form_state and attempt ldap authentication.', $watchdog_tokens, WATCHDOG_DEBUG);
|
212
|
}
|
213
|
$form_state['uid'] = NULL; // passed previous authentication, but only ldap should be used so override
|
214
|
}
|
215
|
}
|
216
|
|
217
|
/**
|
218
|
* II. Exit if no authentication servers.
|
219
|
*/
|
220
|
if (!$auth_conf->hasEnabledAuthenticationServers()) {
|
221
|
watchdog('ldap_authentication', 'No LDAP servers configured.', array(), WATCHDOG_ERROR);
|
222
|
form_set_error('name', 'Server Error: No LDAP servers configured.');
|
223
|
return;
|
224
|
}
|
225
|
|
226
|
/**
|
227
|
* III. determine if corresponding drupal account exists for $authname
|
228
|
*/
|
229
|
$drupal_account_is_authmapped = FALSE;
|
230
|
list($drupal_account, $drupal_account_is_authmapped) = ldap_authentication_corresponding_drupal_user($authname, $auth_conf, $watchdog_tokens);
|
231
|
$drupal_account_exists = is_object($drupal_account);
|
232
|
if ($drupal_account_exists && $drupal_account->uid == 1) {
|
233
|
return; // user 1 is not allowed to ldap authenticate
|
234
|
}
|
235
|
|
236
|
/**
|
237
|
* IV. test credentials and if available get corresponding ldap user and ldap server
|
238
|
*/
|
239
|
list($authentication_result, $ldap_user, $ldap_server_authenticated_on) = ldap_authentication_test_credentials($auth_conf, $sso_login, $authname, $form_state['values']['pass'], $watchdog_tokens);
|
240
|
drupal_alter('ldap_entry', $ldap_user);
|
241
|
if ($authentication_result != LDAP_AUTHENTICATION_RESULT_SUCCESS) {
|
242
|
ldap_authentication_fail_response($authentication_result, $auth_conf, $detailed_watchdog_log, $watchdog_tokens);
|
243
|
return;
|
244
|
}
|
245
|
|
246
|
/*
|
247
|
* IV.a Workaround for the provisioning server not always getting saved in
|
248
|
* the user object. So we save it in a session variable as a backup.
|
249
|
*/
|
250
|
if ($ldap_server_authenticated_on) {
|
251
|
$_SESSION[LDAP_USER_SESSION_PROV_SID] = $ldap_server_authenticated_on->sid;
|
252
|
}
|
253
|
|
254
|
/**
|
255
|
* V. if account_name_attr is set, drupal username is different than authname
|
256
|
*/
|
257
|
if ($ldap_server_authenticated_on->account_name_attr != '') {
|
258
|
$watchdog_tokens['%account_name_attr'] = $ldap_server_authenticated_on->account_name_attr;
|
259
|
$drupal_accountname = $ldap_user['attr'][ldap_server_massage_text($ldap_server_authenticated_on->account_name_attr, 'attr_name', LDAP_SERVER_MASSAGE_QUERY_ARRAY)][0];
|
260
|
if (!$drupal_accountname) {
|
261
|
watchdog('ldap_authentication', 'Derived drupal username from attribute %account_name_attr returned no username for authname %authname.', $watchdog_tokens, WATCHDOG_ERROR);
|
262
|
return;
|
263
|
}
|
264
|
}
|
265
|
else {
|
266
|
$drupal_accountname = $authname;
|
267
|
}
|
268
|
$watchdog_tokens['%drupal_accountname'] = $drupal_accountname;
|
269
|
|
270
|
// @todo maybe we can add more tokens?
|
271
|
$email_template_tokens = array(
|
272
|
'@username' => $drupal_accountname,
|
273
|
);
|
274
|
|
275
|
$email_template_used = FALSE;
|
276
|
|
277
|
/**
|
278
|
* Ensures that we respect the email template handling settings.
|
279
|
*/
|
280
|
if (!empty($auth_conf->emailTemplate)) {
|
281
|
switch ($auth_conf->emailTemplateHandling) {
|
282
|
case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_IF_EMPTY:
|
283
|
if (!empty($ldap_user['mail'])) {
|
284
|
break;
|
285
|
}
|
286
|
// deliberate fallthrough
|
287
|
case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_ALWAYS:
|
288
|
_ldap_authentication_replace_user_email($ldap_user, $auth_conf, $email_template_tokens);
|
289
|
if ($detailed_watchdog_log) {
|
290
|
watchdog('ldap_authentication', 'Using template generated email for %username', $watchdog_tokens, WATCHDOG_DEBUG);
|
291
|
}
|
292
|
$email_template_used = TRUE;
|
293
|
break;
|
294
|
}
|
295
|
}
|
296
|
|
297
|
/**
|
298
|
* VI. Find or create corresponding drupal account and set authmaps
|
299
|
*
|
300
|
* at this point, the following are know:
|
301
|
* - a corresponding ldap account has been found
|
302
|
* - user's credentials tested against it and passed
|
303
|
* - their drupal accountname has been derived
|
304
|
*
|
305
|
*/
|
306
|
|
307
|
|
308
|
/**
|
309
|
* VI.A: Drupal account doesn't exist with $authname used to logon,
|
310
|
* but puid exists in another Drupal account; this means username has changed
|
311
|
* and needs to be saved in Drupal account
|
312
|
*
|
313
|
*/
|
314
|
if (!$drupal_account_exists && $ldap_server_authenticated_on) {
|
315
|
$puid = $ldap_server_authenticated_on->userPuidFromLdapEntry($ldap_user['attr']);
|
316
|
if ($puid) {
|
317
|
$drupal_account = $ldap_server_authenticated_on->userUserEntityFromPuid($puid);
|
318
|
if ($drupal_account) {
|
319
|
$drupal_account_exists = TRUE;
|
320
|
if ($drupal_accountname == $authname) {
|
321
|
$user_edit = array($authname_drupal_property => $drupal_accountname);
|
322
|
}
|
323
|
else {
|
324
|
$user_edit = array('name' => $drupal_accountname);
|
325
|
}
|
326
|
$drupal_account = user_save($drupal_account, $user_edit, 'ldap_user');
|
327
|
user_set_authmaps($drupal_account, array("authname_ldap_user" => $authname));
|
328
|
$drupal_account_is_authmapped = TRUE;
|
329
|
}
|
330
|
}
|
331
|
}
|
332
|
|
333
|
/**
|
334
|
* VI.B: existing Drupal account but not authmapped to ldap modules,
|
335
|
* ldap authmap or disallow
|
336
|
*
|
337
|
*/
|
338
|
|
339
|
if ($drupal_account_exists && !$drupal_account_is_authmapped) { // account already exists
|
340
|
if ($auth_conf->ldapUser->loginConflictResolve == LDAP_USER_CONFLICT_LOG) {
|
341
|
if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
|
342
|
$watchdog_tokens['%conflict_name'] = $account_with_same_email->name;
|
343
|
watchdog('ldap_authentication', 'LDAP user with DN %dn has a naming conflict with a local drupal user %conflict_name', $watchdog_tokens, WATCHDOG_ERROR);
|
344
|
}
|
345
|
drupal_set_message(t('Another user already exists in the system with the same login name. You should contact the system administrator in order to solve this conflict.'), 'error');
|
346
|
return;
|
347
|
}
|
348
|
else { // LDAP_authen.AC.disallow.ldap.drupal
|
349
|
// add ldap_authentication authmap to user. account name is fine here, though cn could be used
|
350
|
user_set_authmaps($drupal_account, array('authname_ldap_user' => $authname));
|
351
|
$drupal_account_is_authmapped = TRUE;
|
352
|
if ($detailed_watchdog_log) {
|
353
|
watchdog('ldap_authentication', 'set authmap for %username authname_ldap_user', $watchdog_tokens, WATCHDOG_DEBUG);
|
354
|
}
|
355
|
}
|
356
|
}
|
357
|
|
358
|
/**
|
359
|
* VI.C: existing Drupal account with incorrect email. fix email if appropriate
|
360
|
*
|
361
|
*/
|
362
|
if ((!($auth_conf->templateUsageNeverUpdate && $email_template_used)) &&
|
363
|
$drupal_account_exists &&
|
364
|
$drupal_account->mail != $ldap_user['mail'] &&
|
365
|
(
|
366
|
$auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY ||
|
367
|
$auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE
|
368
|
)) {
|
369
|
$user_edit = array('mail' => $ldap_user['mail']);
|
370
|
|
371
|
$watchdog_tokens['%username'] = $drupal_account->name;
|
372
|
if (!$updated_account = user_save($drupal_account, $user_edit)) {
|
373
|
watchdog('ldap_authentication', 'Failed to make changes to user %username updated %changed.', $watchdog_tokens, WATCHDOG_ERROR);
|
374
|
}
|
375
|
elseif ($auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY ) {
|
376
|
if (isset($user_edit['mail'])) {
|
377
|
$watchdog_tokens['%mail'] = $user_edit['mail'];
|
378
|
drupal_set_message(t('Your e-mail has been updated to match your current account (%mail).', $watchdog_tokens), 'status');
|
379
|
}
|
380
|
if (isset($user_edit['name'])) {
|
381
|
$watchdog_tokens['%new_username'] = $user_edit['name'];
|
382
|
drupal_set_message(t('Your old account username %username has been updated to %new_username.', $watchdog_tokens), 'status');
|
383
|
}
|
384
|
}
|
385
|
}
|
386
|
|
387
|
/**
|
388
|
* VI.C: no existing Drupal account. consider provisioning Drupal account.
|
389
|
*
|
390
|
*/
|
391
|
if (!$drupal_account_exists) {
|
392
|
|
393
|
// VI.C.1 Do not provision Drupal account if another account has same email.
|
394
|
if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
|
395
|
$error = TRUE;
|
396
|
/**
|
397
|
* username does not exist but email does. Since user_external_login_register does not deal with
|
398
|
* mail attribute and the email conflict error needs to be caught beforehand, need to throw error here
|
399
|
*/
|
400
|
if ($auth_conf->templateUsageResolveConflict && (!$email_template_used)) {
|
401
|
if ($detailed_watchdog_log) {
|
402
|
watchdog('ldap_authentication', 'Conflict detected, using template generated email for %username', $watchdog_tokens, WATCHDOG_DEBUG);
|
403
|
}
|
404
|
_ldap_authentication_replace_user_email($ldap_user, $auth_conf, $email_template_tokens);
|
405
|
$email_template_used = TRUE;
|
406
|
// recheck with the template email to make sure it doesn't also exist.
|
407
|
if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
|
408
|
$error = TRUE;
|
409
|
}
|
410
|
}
|
411
|
if ($error) {
|
412
|
$watchdog_tokens['%duplicate_name'] = $account_with_same_email->name;
|
413
|
watchdog('ldap_authentication', 'LDAP user with DN %dn has email address
|
414
|
(%mail) conflict with a drupal user %duplicate_name', $watchdog_tokens, WATCHDOG_ERROR);
|
415
|
drupal_set_message(t('Another user already exists in the system with the same email address. You should contact the system administrator in order to solve this conflict.'), 'error');
|
416
|
return;
|
417
|
}
|
418
|
}
|
419
|
|
420
|
// VI.C.2 Do not provision Drupal account if provisioning disabled
|
421
|
if (!$auth_conf->ldapUser->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE)) {
|
422
|
watchdog('ldap_user', 'Drupal account for authname=%authname account name=%account_name_attr does not exist and provisioning of Drupal accounts on authentication is not enabled', $watchdog_tokens, WATCHDOG_INFO);
|
423
|
return;
|
424
|
}
|
425
|
|
426
|
// VI.C.3 Provision Drupal account
|
427
|
/**
|
428
|
*
|
429
|
* new ldap_authentication provisioned account could let user_external_login_register create the account and set authmaps, but would need
|
430
|
* to add mail and any other user->data data in hook_user_presave which would mean requerying ldap
|
431
|
* or having a global variable. At this point the account does not exist, so there is no
|
432
|
* reason not to create it here.
|
433
|
*
|
434
|
* @todo create patch for core user module's user_external_login_register to deal with new external accounts
|
435
|
* a little tweak to add user->data and mail etc as parameters would make it more useful
|
436
|
* for external authentication modules
|
437
|
*/
|
438
|
|
439
|
$user_register = variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
|
440
|
if ($auth_conf->ldapUser->acctCreation == LDAP_USER_ACCT_CREATION_USER_SETTINGS_FOR_LDAP &&
|
441
|
$user_register == USER_REGISTER_ADMINISTRATORS_ONLY) {
|
442
|
watchdog('ldap_user', 'Failed to create account for %drupal_accountname. Administrative user must create user.',
|
443
|
$watchdog_tokens, WATCHDOG_ERROR);
|
444
|
form_set_error('name', t('Server Error: Attempt to create account for %drupal_accountname failed. Administrative user must create user.',
|
445
|
$watchdog_tokens));
|
446
|
return;
|
447
|
}
|
448
|
|
449
|
if ($auth_conf->ldapUser->acctCreation == LDAP_AUTHENTICATION_ACCT_CREATION_USER_SETTINGS_FOR_LDAP &&
|
450
|
variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
|
451
|
$user_edit = array('name' => $drupal_accountname, 'status' => 0); // if admin approval required, set status to 0.
|
452
|
}
|
453
|
else {
|
454
|
$user_edit = array('name' => $drupal_accountname, 'status' => 1);
|
455
|
}
|
456
|
|
457
|
// If the email template was used, we want to pass in the email that was
|
458
|
// generated so that its not overridden by the provisioner.
|
459
|
if ($email_template_used) {
|
460
|
$user_edit['mail'] = $ldap_user['mail'];
|
461
|
}
|
462
|
|
463
|
// don't pass in ldap user to provisionDrupalAccount, because want to requery with correct attributes needed
|
464
|
// this may be a case where efficiency dictates querying for all attributes
|
465
|
$drupal_account = $auth_conf->ldapUser->provisionDrupalAccount(NULL, $user_edit, $ldap_user, TRUE);
|
466
|
|
467
|
if ($drupal_account === FALSE) {
|
468
|
watchdog('ldap_user', 'Failed to find or create %drupal_accountname on logon.', $watchdog_tokens, WATCHDOG_ERROR);
|
469
|
form_set_error('name', t('Server Error: Failed to create Drupal user account for %drupal_accountname', $watchdog_tokens));
|
470
|
return;
|
471
|
}
|
472
|
else {
|
473
|
user_set_authmaps($drupal_account, array('authname_ldap_user' => $authname));
|
474
|
// Using Rules allows emails to be fired and many other possible reactions
|
475
|
// to the creation of a user.
|
476
|
if (module_exists('rules')) {
|
477
|
rules_invoke_event('ldap_user_created', $drupal_account, $email_template_used);
|
478
|
}
|
479
|
}
|
480
|
}
|
481
|
|
482
|
/**
|
483
|
* we now have valid, ldap authenticated username with an account authmapped to ldap_authentication.
|
484
|
* since user_external_login_register can't deal with user mail attribute and doesn't do much else, it is not
|
485
|
* being used here.
|
486
|
*
|
487
|
* without doing the user_login_submit,
|
488
|
* [#1009990],[#1865938]
|
489
|
*/
|
490
|
|
491
|
$form_state['uid'] = $drupal_account->uid;
|
492
|
// $fake_form_state = array('uid' => $drupal_account->uid);
|
493
|
// user_login_submit(array(), $fake_form_state);
|
494
|
// global $user;
|
495
|
// $form_state['uid'] = $user->uid;
|
496
|
|
497
|
|
498
|
// the uid is returned so that special login modules, namely ldap sso, can manually call this function.
|
499
|
return ($return_user) ? $drupal_account : NULL;
|
500
|
}
|
501
|
|
502
|
/**
|
503
|
* given authname, determine if corresponding drupal account exists and is authmapped
|
504
|
*/
|
505
|
function ldap_authentication_corresponding_drupal_user($authname, $auth_conf, &$watchdog_tokens) {
|
506
|
$detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
|
507
|
if (!($drupal_account = user_load_by_name($authname)) && !($drupal_account = user_load_by_mail($authname))) {
|
508
|
$uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname AND module = 'ldap_user'", array(':authname' => $authname))->fetchColumn();
|
509
|
$drupal_account = $uid ? user_load($uid) : FALSE;
|
510
|
}
|
511
|
|
512
|
if (is_object($drupal_account)) {
|
513
|
$authmaps = user_get_authmaps($authname); // $authmaps = user_get_authmaps($name); // patch 1599632
|
514
|
$drupal_account_is_authmapped = isset($authmaps['ldap_user']);
|
515
|
$user_data = $drupal_account->data;
|
516
|
if ($drupal_account->uid == 1 && $detailed_watchdog_log) {
|
517
|
watchdog('ldap_authentication', '%username : Drupal username maps to user 1, so do not authenticate with ldap', $watchdog_tokens, WATCHDOG_DEBUG);
|
518
|
}
|
519
|
elseif ($detailed_watchdog_log) {
|
520
|
watchdog('ldap_authentication', '%username : Drupal User Account found. Continuing on to attempt ldap authentication', $watchdog_tokens, WATCHDOG_DEBUG);
|
521
|
}
|
522
|
}
|
523
|
else { // account does not exist
|
524
|
$drupal_account_is_authmapped = FALSE;
|
525
|
if ($auth_conf->ldapUser->createLDAPAccounts == FALSE) {
|
526
|
if ($detailed_watchdog_log) {
|
527
|
watchdog('ldap_authentication', '%username : Drupal User Account not found and configuration is set to not create new accounts.', $watchdog_tokens, WATCHDOG_DEBUG);
|
528
|
}
|
529
|
}
|
530
|
if ($detailed_watchdog_log) {
|
531
|
watchdog('ldap_authentication', '%username : Existing Drupal User Account not found. Continuing on to attempt ldap authentication', $watchdog_tokens, WATCHDOG_DEBUG);
|
532
|
}
|
533
|
}
|
534
|
return array($drupal_account, $drupal_account_is_authmapped);
|
535
|
}
|
536
|
|
537
|
function ldap_authentication_test_credentials($auth_conf, $sso_login, $authname, $password, &$watchdog_tokens) {
|
538
|
$detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
|
539
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC;
|
540
|
$ldap_user = FALSE;
|
541
|
$ldap_server = NULL;
|
542
|
foreach ($auth_conf->enabledAuthenticationServers as $sid => $ldap_server) {
|
543
|
$watchdog_tokens['%sid'] = $sid;
|
544
|
$watchdog_tokens['%bind_method'] = $ldap_server->bind_method;
|
545
|
if ($detailed_watchdog_log) {
|
546
|
watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method', $watchdog_tokens, WATCHDOG_DEBUG);
|
547
|
}
|
548
|
|
549
|
// #1 CONNECT TO SERVER
|
550
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC;
|
551
|
$result = $ldap_server->connect();
|
552
|
if ($result != LDAP_SUCCESS) {
|
553
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_CONNECT;
|
554
|
$watchdog_tokens['%err_msg'] = $ldap_server->errorMsg('ldap');
|
555
|
if ($detailed_watchdog_log) {
|
556
|
watchdog('ldap_authentication', '%username : Failed connecting to %sid. Error: %err_msg', $watchdog_tokens, WATCHDOG_DEBUG);
|
557
|
}
|
558
|
$watchdog_tokens['%err_msg'] = NULL;
|
559
|
continue; // next server, please
|
560
|
}
|
561
|
elseif ($detailed_watchdog_log) {
|
562
|
watchdog('ldap_authentication', '%username : Success at connecting to %sid', $watchdog_tokens, WATCHDOG_DEBUG);
|
563
|
}
|
564
|
|
565
|
$bind_success = FALSE;
|
566
|
if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT) {
|
567
|
$bind_success = ($ldap_server->bind(NULL, NULL, FALSE) == LDAP_SUCCESS);
|
568
|
}
|
569
|
elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON ||
|
570
|
$ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
|
571
|
$bind_success = ($ldap_server->bind(NULL, NULL, TRUE) == LDAP_SUCCESS);
|
572
|
}
|
573
|
elseif ($sso_login) {
|
574
|
watchdog('ldap_authentication', 'Trying to use SSO with LDAP_SERVERS_BIND_METHOD_USER bind method.', $watchdog_tokens, WATCHDOG_ERROR);
|
575
|
}
|
576
|
elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER && $sso_login == FALSE) {
|
577
|
// with sso enabled this method of binding isn't valid
|
578
|
foreach ($ldap_server->basedn as $basedn) {
|
579
|
$search = array('%basedn', '%username');
|
580
|
$transformname = $ldap_server->userUsernameToLdapNameTransform($authname, $watchdog_tokens);
|
581
|
$replace = array($basedn, $transformname);
|
582
|
$userdn = str_replace($search, $replace, $ldap_server->user_dn_expression);
|
583
|
$bind_success = ($ldap_server->bind($userdn, $password, FALSE) == LDAP_SUCCESS);
|
584
|
if ($bind_success) {
|
585
|
break;
|
586
|
}
|
587
|
}
|
588
|
}
|
589
|
else {
|
590
|
watchdog('ldap_authentication', 'No bind method set in ldap_server->bind_method in _ldap_authentication_user_login_authenticate_validate.', $watchdog_tokens, WATCHDOG_ERROR);
|
591
|
}
|
592
|
|
593
|
if (!$bind_success) {
|
594
|
if ($detailed_watchdog_log) {
|
595
|
$watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
|
596
|
watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method. Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
|
597
|
$watchdog_tokens['%err_text'] = NULL;
|
598
|
}
|
599
|
$authentication_result = ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER) ? LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS : LDAP_AUTHENTICATION_RESULT_FAIL_BIND;
|
600
|
continue; // if bind fails, onto next server
|
601
|
}
|
602
|
|
603
|
// #3 DOES USER EXIST IN SERVER'S LDAP
|
604
|
if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
|
605
|
$ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
|
606
|
}
|
607
|
elseif ($sso_login) {
|
608
|
$ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
|
609
|
if ($detailed_watchdog_log) {
|
610
|
$watchdog_tokens['%result'] = var_export($result, TRUE);
|
611
|
watchdog('ldap_authentication', '%username : attempting single sign-on
|
612
|
login in bind_method of LDAP_SERVERS_BIND_METHOD_USER. Result of
|
613
|
userUserNameToExistingLdapEntry: <pre>%result</pre>', $watchdog_tokens, WATCHDOG_DEBUG);
|
614
|
}
|
615
|
}
|
616
|
else {
|
617
|
$ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
|
618
|
}
|
619
|
|
620
|
if (!$ldap_user) {
|
621
|
if ($detailed_watchdog_log) {
|
622
|
$watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
|
623
|
watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method. Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
|
624
|
$watchdog_tokens['%err_text'] = NULL;
|
625
|
}
|
626
|
if ($ldap_server->ldapErrorNumber()) {
|
627
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_SERVER;
|
628
|
break;
|
629
|
}
|
630
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_FIND;
|
631
|
continue; // next server, please
|
632
|
}
|
633
|
|
634
|
$watchdog_tokens['%dn'] = $ldap_user['dn'];
|
635
|
$watchdog_tokens['%mail'] = $ldap_user['mail'];
|
636
|
|
637
|
/**
|
638
|
* #4 CHECK ALLOWED AND EXCLUDED LIST AND PHP FOR ALLOWED USERS
|
639
|
*/
|
640
|
|
641
|
if (!$auth_conf->allowUser($authname, $ldap_user)) {
|
642
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED;
|
643
|
break; // regardless of how many servers, disallowed user fails
|
644
|
}
|
645
|
|
646
|
/**
|
647
|
* #5 TEST PASSWORD
|
648
|
*/
|
649
|
$credentials_pass = FALSE;
|
650
|
if ($sso_login) {
|
651
|
/** If we have $sso_login passed in as true from the fake form state in
|
652
|
* passed from _ldap_authentication_user_login_sso(), we will be relying
|
653
|
* on the webserver for actually authenticating the user, either by NTLM
|
654
|
* or user/password if configured as a fallback. Since the webserver has
|
655
|
* already authenticated the user, and the web server only contains the
|
656
|
* user's LDAP user name, instead of binding on the username/pass, we
|
657
|
* simply look up the user's account in LDAP, and make sure it matches
|
658
|
* what is contained in the global $_SERVER array populated by the web
|
659
|
* server authentication.
|
660
|
*/
|
661
|
$credentials_pass = (boolean)($ldap_user);
|
662
|
}
|
663
|
elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER) {
|
664
|
/**
|
665
|
* With user bind method, the only way we can reach this part of the
|
666
|
* code is when the pw has already been checked and $ldap_user could be
|
667
|
* loaded, so we're good to go.
|
668
|
*/
|
669
|
$credentials_pass = true;
|
670
|
}
|
671
|
else {
|
672
|
$credentials_pass = ($ldap_server->bind($ldap_user['dn'], $password, FALSE) == LDAP_SUCCESS);
|
673
|
}
|
674
|
if (!$credentials_pass) {
|
675
|
if ($detailed_watchdog_log) {
|
676
|
$watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
|
677
|
watchdog('ldap_authentication', '%username : Testing user credentials on server %sid where bind_method = %bind_method. Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
|
678
|
$watchdog_tokens['%err_text'] = NULL;
|
679
|
}
|
680
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS;
|
681
|
continue; // next server, please
|
682
|
}
|
683
|
else {
|
684
|
$authentication_result = LDAP_AUTHENTICATION_RESULT_SUCCESS;
|
685
|
if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
|
686
|
$ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname); // after successful bind, lookup user again to get private attributes
|
687
|
$watchdog_tokens['%mail'] = $ldap_user['mail'];
|
688
|
}
|
689
|
if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT ||
|
690
|
$ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
|
691
|
$ldap_server->disconnect();
|
692
|
}
|
693
|
// Update ldapUser with the sid of the server that the user authenticated
|
694
|
// on if that option was enabled in the LDAP user configuration.
|
695
|
if ($auth_conf->ldapUser->drupalAcctProvisionServer == LDAP_USER_AUTH_SERVER_SID) {
|
696
|
$auth_conf->ldapUser->drupalAcctProvisionServer = $ldap_server->sid;
|
697
|
}
|
698
|
break; //success
|
699
|
}
|
700
|
|
701
|
} // end loop through servers
|
702
|
|
703
|
$watchdog_tokens['%result'] = $result;
|
704
|
$watchdog_tokens['%auth_result'] = $authentication_result;
|
705
|
$watchdog_tokens['%err_text'] = _ldap_authentication_err_text($authentication_result) ;
|
706
|
if ($detailed_watchdog_log) {
|
707
|
watchdog('ldap_authentication', '%username : Authentication result id=%result auth_result=%auth_result (%err_text)', $watchdog_tokens, WATCHDOG_DEBUG);
|
708
|
}
|
709
|
|
710
|
return array($authentication_result, $ldap_user, $ldap_server);
|
711
|
}
|
712
|
|
713
|
function ldap_authentication_fail_response($authentication_result, $auth_conf, $detailed_watchdog_log, &$watchdog_tokens) {
|
714
|
$watchdog_tokens['%err_text'] = _ldap_authentication_err_text($authentication_result);
|
715
|
// fail scenario 1. ldap auth exclusive and failed throw error so no other authentication methods are allowed
|
716
|
if ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_EXCLUSIVE) {
|
717
|
if ($detailed_watchdog_log) {
|
718
|
watchdog('ldap_authentication', '%username : setting error because failed at ldap and
|
719
|
LDAP_AUTHENTICATION_EXCLUSIVE is set to true. So need to stop authentication of Drupal user that is not user 1.
|
720
|
error message: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
|
721
|
}
|
722
|
form_set_error('name', $watchdog_tokens['%err_text']);
|
723
|
}
|
724
|
else {
|
725
|
// fail scenario 2. simply fails ldap. return false, but don't throw form error
|
726
|
// don't show user message, may be using other authentication after this that may succeed.
|
727
|
if ($detailed_watchdog_log) {
|
728
|
watchdog('ldap_authentication',
|
729
|
'%username : Failed ldap authentication.
|
730
|
User may have authenticated successfully by other means in a mixed authentication site.
|
731
|
LDAP Authentication Error #: %auth_result error message: %err_text',
|
732
|
$watchdog_tokens,
|
733
|
WATCHDOG_DEBUG
|
734
|
);
|
735
|
}
|
736
|
}
|
737
|
}
|
738
|
|
739
|
/**
|
740
|
* get human readable authentication error string
|
741
|
*
|
742
|
* @param int $error as LDAP_AUTHENTICATION_RESULT_* constant defined in ldap_authentication.module
|
743
|
* @return string human readable error text
|
744
|
*/
|
745
|
function _ldap_authentication_err_text($error) {
|
746
|
|
747
|
$msg = t('unknown error: ' . $error);
|
748
|
switch ($error) {
|
749
|
case LDAP_AUTHENTICATION_RESULT_FAIL_CONNECT:
|
750
|
$msg = t('Failed to connect to ldap server');
|
751
|
break;
|
752
|
|
753
|
case LDAP_AUTHENTICATION_RESULT_FAIL_BIND:
|
754
|
$msg = t('Failed to bind to ldap server');
|
755
|
break;
|
756
|
|
757
|
case LDAP_AUTHENTICATION_RESULT_FAIL_FIND:
|
758
|
$msg = t('Sorry, unrecognized username or password.');
|
759
|
break;
|
760
|
|
761
|
case LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED:
|
762
|
$msg = t('User disallowed');
|
763
|
break;
|
764
|
|
765
|
case LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS:
|
766
|
$msg = t('Sorry, unrecognized username or password.');
|
767
|
break;
|
768
|
|
769
|
case LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC:
|
770
|
$msg = t('Sorry, unrecognized username or password.');
|
771
|
break;
|
772
|
|
773
|
case LDAP_AUTHENTICATION_RESULT_FAIL_SERVER:
|
774
|
$msg = t('Authentication Server or Configuration Error.');
|
775
|
break;
|
776
|
|
777
|
}
|
778
|
|
779
|
return $msg;
|
780
|
}
|
781
|
|