Projet

Général

Profil

Paste
Télécharger (33,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_authentication / ldap_authentication.inc @ b42754b9

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

    
53
  // Add help information for entering in username/password
54
  $auth_conf = ldap_authentication_get_valid_conf();
55
  if ($auth_conf) {
56
    if (isset($auth_conf->loginUIUsernameTxt)) {
57
      $form['name']['#description'] = t($auth_conf->loginUIUsernameTxt);
58
    }
59
    if (isset($auth_conf->loginUIPasswordTxt)) {
60
      $form['pass']['#description'] = t($auth_conf->loginUIPasswordTxt);
61
    }
62
    if ($auth_conf->templateUsageRedirectOnLogin) {
63
      $form['#submit'][] = 'ldap_authentication_check_for_email_template';
64
    }
65
  }
66
}
67

    
68

    
69

    
70
/**
71
  * alter user editing form (profile form) based on ldap authentication configuration
72
  *
73
  * @param array $form array from user profile
74
  * @param array $form_state from user profile
75
  *
76
  * @return NULL (alters $form by reference)
77
  */
78
function _ldap_authentication_form_user_profile_form_alter(&$form, $form_state) {
79
  // keep in mind admin may be editing another users profile form.  don't assume current global $user
80
  $auth_conf = ldap_authentication_get_valid_conf();
81
  if ($auth_conf && ldap_authentication_ldap_authenticated($form['#user'])) {
82
    if ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_REMOVE) {
83
      $form['account']['mail']['#access'] = FALSE;
84
    }
85
    elseif ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_DISABLE) {
86
      $form['account']['mail']['#disabled'] = TRUE;
87
      $form['account']['mail']['#description'] = t('This email address is automatically set and may not be changed.');
88
    }
89
    elseif ($auth_conf->emailOption == LDAP_AUTHENTICATION_EMAIL_FIELD_ALLOW) {
90
      // email field is functional
91
    }
92

    
93
    if (!ldap_authentication_show_reset_pwd($form['#user'])) {
94
      /**  If passwordOption = LDAP_AUTHENTICATION_PASSWORD_FIELD_HIDE then don't show the password fields,
95
        otherwise show the fields but in a disabled state.
96
       */
97
        switch ($auth_conf->passwordOption) {
98

    
99
          case LDAP_AUTHENTICATION_PASSWORD_FIELD_HIDE:
100
            $form['account']['current_pass']['#access'] = FALSE;
101
            $form['account']['pass']['#access'] = FALSE;
102
            break;
103

    
104
          case LDAP_AUTHENTICATION_PASSWORD_FIELD_SHOW:
105
                    // Show in a disabled state since ldap_authentication_show_reset_pwd() has returned FALSE
106
            $form['account']['current_pass']['#disabled'] = TRUE;
107
            if ($auth_conf->ldapUserHelpLinkUrl) {
108
              $form['account']['current_pass']['#description'] = l(t($auth_conf->ldapUserHelpLinkText), $auth_conf->ldapUserHelpLinkUrl);
109
            }
110
            else {
111
              $form['account']['current_pass']['#description'] = t('The password cannot be changed using this website');
112
            }
113
            $form['account']['pass']['#disabled'] = TRUE;
114
            break;
115
      }
116
    }
117
  }
118
}
119

    
120
/**
121
 * Replaces the email address in $ldap_user with one from the template in
122
 * $auth_conf.
123
 *
124
 * @param array $ldap_user
125
 *   LDAP user entry
126
 * @param LdapAuthenticationConf $auth_conf
127
 *   LDAP authentication configuration class.
128
 */
129
function _ldap_authentication_replace_user_email(&$ldap_user, $auth_conf, $tokens) {
130
  // fallback template in case one was not specified.
131
  $template = '@username@localhost';
132
  if (!empty($auth_conf->emailTemplate)) {
133
    $template = $auth_conf->emailTemplate;
134
  }
135
  $ldap_user['mail'] = format_string($template, $tokens);
136
}
137

    
138
/**
139
  * user form validation will take care of username, pwd fields
140
  * this function validates ldap authentication specific
141
  *
142
  * @param array $form_state array from user logon form
143
  * @return null, but success or failure is indicated by:
144
  * -- form_set_error() to invalidate authentication process
145
  * -- setting $form_state['uid'] to indicate successful authentication
146
  */
147
function _ldap_authentication_user_login_authenticate_validate(&$form_state, $return_user) {
148

    
149
  // Check if Flood control was triggered; if so, don't authenticate
150
  if (isset($form_state['flood_control_triggered'])) {
151
    return;
152
  }
153

    
154
  $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
155

    
156
  // Default to name
157
  $entered_name = $form_state['values']['name'];
158
  $authname_drupal_property = $form_field_name = 'name';
159

    
160
  // Email registration module populates name even though user entered email
161
  if (!empty($form_state['values']['email'])) {
162
    $entered_name = $form_state['values']['email'];
163
    $authname_drupal_property = 'mail';
164
    $form_field_name = 'email';
165
  }
166

    
167
  // $authname is the name the user is authenticated with from the logon form // patch 1599632
168
  $authname = $entered_name;
169

    
170
  if (empty($form_state['values']['pass']) || empty ($form_state['values'][$form_field_name])) {
171
    return FALSE;
172
  }
173
  /*
174
   * If a fake form state was passed into this function from
175
   * _ldap_authentication_user_login_sso(), there will be a value outside of the
176
   * form_state[values] array to let us know that we are not authenticating with
177
   * a password, but instead just looking up a username/dn in LDAP since the web
178
   * server already authenticated the user.
179
   */
180
  $sso_login = (isset($form_state['sso_login']) && $form_state['sso_login']) ? TRUE : FALSE;
181

    
182
  $watchdog_tokens = array('%username' => $authname, '%authname' => $authname); // $watchdog_tokens = array('%username' => $name); // patch 1599632
183
  if ($detailed_watchdog_log) {
184
    watchdog('ldap_authentication', '%username : Beginning authentification....', $watchdog_tokens, WATCHDOG_DEBUG);
185
  }
186

    
187
  if (!$auth_conf = ldap_authentication_get_valid_conf()) {
188
    watchdog('ldap_authentication', 'Failed to get valid ldap authentication configuration.', array(), WATCHDOG_ERROR);
189
    form_set_error('name', 'Server Error: Failed to get valid ldap authentication configuration.' . $error);
190
    return;
191
  }
192

    
193
 /**
194
  * I. Test for previous module authentication success.
195
  *
196
  * if already succeeded at authentication, $form_state['uid'] will be set by other authentication module.
197
  * - if LDAP Mixed mode is set, return and don't disrupt authentication process
198
  * - otherwise override other authenication by setting $form_state['uid'] = NULL
199
  */
200
  if (isset($form_state['uid']) && is_numeric($form_state['uid'])) {
201
    if ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_MIXED || $form_state['uid'] == 1) {
202
      if ($detailed_watchdog_log) {
203
      watchdog('ldap_authentication', '%username : Previously authenticated in mixed mode or uid=1', $watchdog_tokens, WATCHDOG_DEBUG);
204
      }
205
      return;  // already passed a previous module's authentication validation
206
    }
207
    elseif ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_EXCLUSIVE) {
208
      if ($detailed_watchdog_log) {
209
        watchdog('ldap_authentication', '%username : Previously authenticated in exclusive mode or uid is not 1.  Clear uid
210
        in form_state and attempt ldap authentication.',  $watchdog_tokens, WATCHDOG_DEBUG);
211
      }
212
      $form_state['uid'] = NULL;  // passed previous authentication, but only ldap should be used so override
213
    }
214
  }
215

    
216
 /**
217
  * II. Exit if no authentication servers.
218
  */
219
  if (!$auth_conf->hasEnabledAuthenticationServers()) {
220
    watchdog('ldap_authentication',  'No LDAP servers configured.', array(), WATCHDOG_ERROR);
221
    form_set_error('name', 'Server Error:  No LDAP servers configured.');
222
    return;
223
  }
224

    
225
  /**
226
   * III. determine if corresponding drupal account exists for $authname
227
   */
228
  $drupal_account_is_authmapped = FALSE;
229
  list($drupal_account, $drupal_account_is_authmapped) = ldap_authentication_corresponding_drupal_user($authname, $auth_conf, $watchdog_tokens);
230
  $drupal_account_exists = is_object($drupal_account);
231
  if ($drupal_account_exists && $drupal_account->uid == 1) {
232
    return; // user 1 is not allowed to ldap authenticate
233
  }
234

    
235
  /**
236
   * IV. test credentials and if available get corresponding ldap user and ldap server
237
   */
238
  list($authentication_result, $ldap_user, $ldap_server_authenticated_on) = ldap_authentication_test_credentials($auth_conf, $sso_login, $authname, $form_state['values']['pass'], $watchdog_tokens);
239
  drupal_alter('ldap_entry', $ldap_user);
240
  if ($authentication_result != LDAP_AUTHENTICATION_RESULT_SUCCESS) {
241
    ldap_authentication_fail_response($authentication_result, $auth_conf, $detailed_watchdog_log, $watchdog_tokens);
242
    return;
243
  }
244

    
245
  /*
246
   * IV.a Workaround for the provisioning server not always getting saved in
247
   *      the user object.  So we save it in a session variable as a backup.
248
   */
249
  if ($ldap_server_authenticated_on) {
250
    $_SESSION[LDAP_USER_SESSION_PROV_SID] = $ldap_server_authenticated_on->sid;
251
  }
252

    
253
  /**
254
   * V. if account_name_attr is set, drupal username is different than authname
255
   */
256
  if ($ldap_server_authenticated_on->account_name_attr != '') {
257
    $watchdog_tokens['%account_name_attr'] = $ldap_server_authenticated_on->account_name_attr;
258
    $drupal_accountname = $ldap_user['attr'][ldap_server_massage_text($ldap_server_authenticated_on->account_name_attr, 'attr_name', LDAP_SERVER_MASSAGE_QUERY_ARRAY)][0];
259
    if (!$drupal_accountname) {
260
      watchdog('ldap_authentication',  'Derived drupal username from attribute %account_name_attr returned no username for authname %authname.', $watchdog_tokens, WATCHDOG_ERROR);
261
      return;
262
    }
263
  }
264
  else {
265
    $drupal_accountname = $authname;
266
  }
267
  $watchdog_tokens['%drupal_accountname'] = $drupal_accountname;
268

    
269
  // @todo maybe we can add more tokens?
270
  $email_template_tokens = array(
271
    '@username' => $drupal_accountname,
272
  );
273

    
274
  $email_template_used = FALSE;
275

    
276
  /**
277
   * Ensures that we respect the email template handling settings.
278
   */
279
  if (!empty($auth_conf->emailTemplate)) {
280
    switch ($auth_conf->emailTemplateHandling) {
281
      case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_IF_EMPTY:
282
        if (!empty($ldap_user['mail'])) {
283
          break;
284
        }
285
        // deliberate fallthrough
286
      case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_ALWAYS:
287
        _ldap_authentication_replace_user_email($ldap_user, $auth_conf, $email_template_tokens);
288
        if ($detailed_watchdog_log) {
289
          watchdog('ldap_authentication', 'Using template generated email for %username', $watchdog_tokens, WATCHDOG_DEBUG);
290
        }
291
        $email_template_used = TRUE;
292
        break;
293
    }
294
  }
295

    
296
  /**
297
   * VI. Find or create corresponding drupal account and set authmaps
298
   *
299
   * at this point, the following are know:
300
   * - a corresponding ldap account has been found
301
   * - user's credentials tested against it and passed
302
   * - their drupal accountname has been derived
303
   *
304
   */
305

    
306

    
307
  /**
308
   * VI.A: Drupal account doesn't exist with $authname used to logon,
309
   *  but puid exists in another Drupal account; this means username has changed
310
   *  and needs to be saved in Drupal account
311
   *
312
   */
313
  if (!$drupal_account_exists && $ldap_server_authenticated_on) {
314
    $puid = $ldap_server_authenticated_on->userPuidFromLdapEntry($ldap_user['attr']);
315
    if ($puid) {
316
      $drupal_account = $ldap_server_authenticated_on->userUserEntityFromPuid($puid);
317
      if ($drupal_account) {
318
        $drupal_account_exists = TRUE;
319
        if ($drupal_accountname == $authname) {
320
          $user_edit = array($authname_drupal_property => $drupal_accountname);
321
        }
322
        else {
323
          $user_edit = array('name' => $drupal_accountname);
324
        }
325
        $drupal_account = user_save($drupal_account, $user_edit, 'ldap_user');
326
        user_set_authmaps($drupal_account, array("authname_ldap_user" => $authname));
327
        $drupal_account_is_authmapped = TRUE;
328
      }
329
    }
330
  }
331

    
332
  /**
333
   * VI.B: existing Drupal account but not authmapped to ldap modules,
334
   *   ldap authmap or disallow
335
   *
336
   */
337

    
338
  if ($drupal_account_exists && !$drupal_account_is_authmapped) {  // account already exists
339
    if ($auth_conf->ldapUser->loginConflictResolve == LDAP_USER_CONFLICT_LOG) {
340
      if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
341
        $watchdog_tokens['%conflict_name'] = $account_with_same_email->name;
342
        watchdog('ldap_authentication', 'LDAP user with DN %dn has a naming conflict with a local drupal user %conflict_name', $watchdog_tokens, WATCHDOG_ERROR);
343
      }
344
      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');
345
      return;
346
    }
347
    else { // LDAP_authen.AC.disallow.ldap.drupal
348
    // add ldap_authentication authmap to user.  account name is fine here, though cn could be used
349
      user_set_authmaps($drupal_account, array('authname_ldap_user' => $authname));
350
      $drupal_account_is_authmapped = TRUE;
351
      if ($detailed_watchdog_log) {
352
        watchdog('ldap_authentication', 'set authmap for %username authname_ldap_user', $watchdog_tokens, WATCHDOG_DEBUG);
353
      }
354
    }
355
  }
356

    
357
  /**
358
   * VI.C: existing Drupal account with incorrect email.  fix email if appropriate
359
   *
360
   */
361
  if ((!($auth_conf->templateUsageNeverUpdate && $email_template_used)) &&
362
      $drupal_account_exists &&
363
      $drupal_account->mail != $ldap_user['mail'] &&
364
      (
365
        $auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY ||
366
        $auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE
367
      )) {
368
    $user_edit = array('mail' => $ldap_user['mail']);
369

    
370
    $watchdog_tokens['%username'] = $drupal_account->name;
371
    if (!$updated_account = user_save($drupal_account, $user_edit)) {
372
      watchdog('ldap_authentication', 'Failed to make changes to user %username updated %changed.', $watchdog_tokens,  WATCHDOG_ERROR);
373
    }
374
    elseif ($auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY ) {
375
      if (isset($user_edit['mail'])) {
376
        $watchdog_tokens['%mail'] = $user_edit['mail'];
377
        drupal_set_message(t('Your e-mail has been updated to match your current account (%mail).', $watchdog_tokens), 'status');
378
      }
379
      if (isset($user_edit['name'])) {
380
        $watchdog_tokens['%new_username'] = $user_edit['name'];
381
        drupal_set_message(t('Your old account username %username has been updated to %new_username.', $watchdog_tokens), 'status');
382
      }
383
    }
384
  }
385

    
386
  /**
387
   * VI.C: no existing Drupal account.  consider provisioning Drupal account.
388
   *
389
   */
390
  if (!$drupal_account_exists) {
391

    
392
    // VI.C.1 Do not provision Drupal account if another account has same email.
393
    if (($auth_conf->ldapUser->acctCreation == LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED) && ($account_with_same_email = user_load_by_mail($ldap_user['mail']))) {
394
      $error = TRUE;
395
      /**
396
       * username does not exist but email does.  Since user_external_login_register does not deal with
397
       * mail attribute and the email conflict error needs to be caught beforehand, need to throw error here
398
       */
399
      if ($auth_conf->templateUsageResolveConflict && (!$email_template_used)) {
400
        if ($detailed_watchdog_log) {
401
          watchdog('ldap_authentication', 'Conflict detected, using template generated email for %username', $watchdog_tokens, WATCHDOG_DEBUG);
402
        }
403
        _ldap_authentication_replace_user_email($ldap_user, $auth_conf, $email_template_tokens);
404
        $email_template_used = TRUE;
405
        // recheck with the template email to make sure it doesn't also exist.
406
        if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
407
          $error = TRUE;
408
        }
409
      }
410
      if ($error) {
411
        $watchdog_tokens['%duplicate_name'] = $account_with_same_email->name;
412
        watchdog('ldap_authentication', 'LDAP user with DN %dn has email address
413
          (%mail) conflict with a drupal user %duplicate_name', $watchdog_tokens, WATCHDOG_ERROR);
414
        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');
415
        return;
416
      }
417
    }
418

    
419
    // VI.C.2 Do not provision Drupal account if provisioning disabled
420
    if (!$auth_conf->ldapUser->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE)) {
421
      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);
422
      return;
423
    }
424

    
425
    // VI.C.3 Provision Drupal account
426
    /**
427
     *
428
     * new ldap_authentication provisioned account could let user_external_login_register create the account and set authmaps, but would need
429
     * to add mail and any other user->data data in hook_user_presave which would mean requerying ldap
430
     * or having a global variable.  At this point the account does not exist, so there is no
431
     * reason not to create it here.
432
     *
433
     * @todo create patch for core user module's user_external_login_register to deal with new external accounts
434
     *       a little tweak to add user->data and mail etc as parameters would make it more useful
435
     *       for external authentication modules
436
     */
437

    
438
      $user_register = variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
439
      if ($auth_conf->ldapUser->acctCreation == LDAP_USER_ACCT_CREATION_USER_SETTINGS_FOR_LDAP &&
440
            $user_register == USER_REGISTER_ADMINISTRATORS_ONLY) {
441
          watchdog('ldap_user', 'Failed to create account for %drupal_accountname. Administrative user must create user.',
442
              $watchdog_tokens, WATCHDOG_ERROR);
443
          form_set_error('name', t('Server Error: Attempt to create account for %drupal_accountname failed. Administrative user must create user.',
444
              $watchdog_tokens));
445
          return;
446
    }
447

    
448
    if ($auth_conf->ldapUser->acctCreation == LDAP_AUTHENTICATION_ACCT_CREATION_USER_SETTINGS_FOR_LDAP &&
449
        variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
450
      $user_edit = array('name' => $drupal_accountname, 'status' => 0); // if admin approval required, set status to 0.
451
    }
452
    else {
453
      $user_edit = array('name' => $drupal_accountname, 'status' => 1);
454
    }
455

    
456
    // If the email template was used, we want to pass in the email that was
457
    // generated so that its not overridden by the provisioner.
458
    if ($email_template_used) {
459
      $user_edit['mail'] = $ldap_user['mail'];
460
    }
461

    
462
    // don't pass in ldap user to provisionDrupalAccount, because want to requery with correct attributes needed
463
    // this may be a case where efficiency dictates querying for all attributes
464
    $drupal_account = $auth_conf->ldapUser->provisionDrupalAccount(NULL, $user_edit, $ldap_user, TRUE);
465

    
466
    if ($drupal_account === FALSE) {
467
      watchdog('ldap_user', 'Failed to find or create %drupal_accountname on logon.', $watchdog_tokens, WATCHDOG_ERROR);
468
      form_set_error('name', t('Server Error: Failed to create Drupal user account for %drupal_accountname', $watchdog_tokens));
469
      return;
470
    }
471
    else {
472
      user_set_authmaps($drupal_account, array('authname_ldap_user' => $authname));
473
      // Using Rules allows emails to be fired and many other possible reactions
474
      // to the creation of a user.
475
      if (module_exists('rules')) {
476
        rules_invoke_event('ldap_user_created', $drupal_account, $email_template_used);
477
      }
478
    }
479
  }
480

    
481
  /**
482
  * we now have valid, ldap authenticated username with an account authmapped to ldap_authentication.
483
  * since user_external_login_register can't deal with user mail attribute and doesn't do much else, it is not
484
  * being used here.
485
  *
486
  * without doing the user_login_submit,
487
  * [#1009990],[#1865938]
488
  */
489

    
490
  $form_state['uid'] = $drupal_account->uid;
491
 // $fake_form_state = array('uid' => $drupal_account->uid);
492
 // user_login_submit(array(), $fake_form_state);
493
 // global $user;
494
 // $form_state['uid'] = $user->uid;
495

    
496

    
497
  // the uid is returned so that special login modules, namely ldap sso, can manually call this function.
498
  return ($return_user) ? $drupal_account : NULL;
499
}
500

    
501
/**
502
 * given authname, determine if corresponding drupal account exists and is authmapped
503
 */
504
function ldap_authentication_corresponding_drupal_user($authname, $auth_conf, &$watchdog_tokens) {
505
  $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
506
  if (!($drupal_account = user_load_by_name($authname)) && !($drupal_account = user_load_by_mail($authname))) {
507
    $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname AND module = 'ldap_user'", array(':authname' => $authname))->fetchColumn();
508
    $drupal_account = $uid ? user_load($uid) : FALSE;
509
  }
510

    
511
  if (is_object($drupal_account)) {
512
    $authmaps = user_get_authmaps($authname); // $authmaps = user_get_authmaps($name); // patch 1599632
513
    $drupal_account_is_authmapped = isset($authmaps['ldap_user']);
514
    $user_data = $drupal_account->data;
515
    if ($drupal_account->uid == 1 && $detailed_watchdog_log) {
516
      watchdog('ldap_authentication',  '%username : Drupal username maps to user 1, so do not authenticate with ldap', $watchdog_tokens, WATCHDOG_DEBUG);
517
    }
518
    elseif ($detailed_watchdog_log) {
519
      watchdog('ldap_authentication',  '%username : Drupal User Account found.  Continuing on to attempt ldap authentication', $watchdog_tokens, WATCHDOG_DEBUG);
520
    }
521
  }
522
  else {  // account does not exist
523
    $drupal_account_is_authmapped = FALSE;
524
    if ($auth_conf->ldapUser->createLDAPAccounts == FALSE) {
525
      if ($detailed_watchdog_log) {
526
        watchdog('ldap_authentication', '%username : Drupal User Account not found and configuration is set to not create new accounts.', $watchdog_tokens, WATCHDOG_DEBUG);
527
      }
528
    }
529
    if ($detailed_watchdog_log) {
530
      watchdog('ldap_authentication', '%username : Existing Drupal User Account not found.  Continuing on to attempt ldap authentication', $watchdog_tokens, WATCHDOG_DEBUG);
531
    }
532
  }
533
  return array($drupal_account, $drupal_account_is_authmapped);
534
}
535

    
536
function ldap_authentication_test_credentials($auth_conf, $sso_login, $authname, $password, &$watchdog_tokens) {
537
  $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
538
  $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC;
539
  $ldap_user = FALSE;
540
  $ldap_server = NULL;
541
  foreach ($auth_conf->enabledAuthenticationServers as $sid => $ldap_server) {
542
    $watchdog_tokens['%sid'] = $sid;
543
    $watchdog_tokens['%bind_method'] = $ldap_server->bind_method;
544
    if ($detailed_watchdog_log) {
545
      watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method', $watchdog_tokens, WATCHDOG_DEBUG);
546
    }
547

    
548
    // #1 CONNECT TO SERVER
549
    $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC;
550
    $result = $ldap_server->connect();
551
    if ($result != LDAP_SUCCESS) {
552
      $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_CONNECT;
553
      $watchdog_tokens['%err_msg'] = $ldap_server->errorMsg('ldap');
554
      if ($detailed_watchdog_log) {
555
        watchdog('ldap_authentication',  '%username : Failed connecting to %sid.  Error: %err_msg', $watchdog_tokens, WATCHDOG_DEBUG);
556
      }
557
      $watchdog_tokens['%err_msg'] = NULL;
558
      continue; // next server, please
559
    }
560
    elseif ($detailed_watchdog_log) {
561
      watchdog('ldap_authentication',  '%username : Success at connecting to %sid', $watchdog_tokens, WATCHDOG_DEBUG);
562
    }
563

    
564
    $bind_success = FALSE;
565
    if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT) {
566
      $bind_success = ($ldap_server->bind(NULL, NULL, FALSE) == LDAP_SUCCESS);
567
    }
568
    elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON ||
569
        $ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
570
      $bind_success = ($ldap_server->bind(NULL, NULL, TRUE) == LDAP_SUCCESS);
571
    }
572
    elseif ($sso_login) {
573
      watchdog('ldap_authentication', 'Trying to use SSO with LDAP_SERVERS_BIND_METHOD_USER bind method.', $watchdog_tokens, WATCHDOG_ERROR);
574
    }
575
    elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER && $sso_login == FALSE) {
576
      // with sso enabled this method of binding isn't valid
577
      foreach ($ldap_server->basedn as $basedn) {
578
        $search = array('%basedn', '%username');
579
        $transformname =  $ldap_server->userUsernameToLdapNameTransform($authname, $watchdog_tokens);
580
        $replace = array($basedn, $transformname);
581
        $userdn = str_replace($search, $replace, $ldap_server->user_dn_expression);
582
        $bind_success = ($ldap_server->bind($userdn, $password, FALSE) == LDAP_SUCCESS);
583
        if ($bind_success) {
584
          break;
585
        }
586
      }
587
    }
588
    else {
589
      watchdog('ldap_authentication', 'No bind method set in ldap_server->bind_method in _ldap_authentication_user_login_authenticate_validate.', $watchdog_tokens, WATCHDOG_ERROR);
590
    }
591

    
592
    if (!$bind_success) {
593
      if ($detailed_watchdog_log) {
594
        $watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
595
        watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method.  Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
596
        $watchdog_tokens['%err_text'] = NULL;
597
      }
598
      $authentication_result = ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER) ? LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS : LDAP_AUTHENTICATION_RESULT_FAIL_BIND;
599
      continue; // if bind fails, onto next server
600
    }
601

    
602
    // #3 DOES USER EXIST IN SERVER'S LDAP
603
    if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
604
      $ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
605
    }
606
    elseif ($sso_login) {
607
      $ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
608
      if ($detailed_watchdog_log) {
609
        $watchdog_tokens['%result'] = var_export($result, TRUE);
610
        watchdog('ldap_authentication', '%username : attempting single sign-on
611
          login in bind_method of LDAP_SERVERS_BIND_METHOD_USER. Result of
612
          userUserNameToExistingLdapEntry: <pre>%result</pre>', $watchdog_tokens, WATCHDOG_DEBUG);
613
      }
614
    }
615
    else {
616
      $ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname);
617
    }
618

    
619
    if (!$ldap_user) {
620
      if ($detailed_watchdog_log) {
621
        $watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
622
        watchdog('ldap_authentication', '%username : Trying server %sid where bind_method = %bind_method.  Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
623
        $watchdog_tokens['%err_text'] = NULL;
624
      }
625
      if ($ldap_server->ldapErrorNumber()) {
626
        $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_SERVER;
627
        break;
628
      }
629
      $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_FIND;
630
      continue; // next server, please
631
    }
632

    
633
    $watchdog_tokens['%dn'] = $ldap_user['dn'];
634
    $watchdog_tokens['%mail'] = $ldap_user['mail'];
635

    
636
    /**
637
    * #4 CHECK ALLOWED AND EXCLUDED LIST AND PHP FOR ALLOWED USERS
638
    */
639

    
640
    if (!$auth_conf->allowUser($authname, $ldap_user)) {
641
      $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED;
642
      break;  // regardless of how many servers, disallowed user fails
643
    }
644

    
645
    /**
646
    * #5 TEST PASSWORD
647
    */
648
    $credentials_pass = FALSE;
649
    if ($sso_login) {
650
      /** If we have $sso_login passed in as true from the fake form state in
651
        * passed from _ldap_authentication_user_login_sso(), we will be relying
652
        * on the webserver for actually authenticating the user, either by NTLM
653
        * or user/password if configured as a fallback. Since the webserver has
654
        * already authenticated the user, and the web server only contains the
655
        * user's LDAP user name, instead of binding on the username/pass, we
656
        * simply look up the user's account in LDAP, and make sure it matches
657
        * what is contained in the global $_SERVER array populated by the web
658
        * server authentication.
659
        */
660
      $credentials_pass = (boolean)($ldap_user);
661
    }
662
    elseif ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_USER) {
663
       /**
664
        * With user bind method, the only way we can reach this part of the
665
        * code is when the pw has already been checked and $ldap_user could be
666
        * loaded, so we're good to go.
667
        */
668
      $credentials_pass = true;
669
    }
670
    else {
671
      $credentials_pass = ($ldap_server->bind($ldap_user['dn'], $password, FALSE) == LDAP_SUCCESS);
672
    }
673
    if (!$credentials_pass) {
674
      if ($detailed_watchdog_log) {
675
        $watchdog_tokens['%err_text'] = $ldap_server->errorMsg('ldap');
676
        watchdog('ldap_authentication', '%username : Testing user credentials on server %sid where bind_method = %bind_method.  Error: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
677
        $watchdog_tokens['%err_text'] = NULL;
678
      }
679
      $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS;
680
      continue; // next server, please
681
    }
682
    else {
683
      $authentication_result = LDAP_AUTHENTICATION_RESULT_SUCCESS;
684
      if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
685
        $ldap_user = $ldap_server->userUserNameToExistingLdapEntry($authname); // after successful bind, lookup user again to get private attributes
686
        $watchdog_tokens['%mail'] = $ldap_user['mail'];
687
      }
688
      if ($ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT ||
689
          $ldap_server->bind_method == LDAP_SERVERS_BIND_METHOD_ANON_USER) {
690
          $ldap_server->disconnect();
691
      }
692
      // Update ldapUser with the sid of the server that the user authenticated
693
      // on if that option was enabled in the LDAP user configuration.
694
      if ($auth_conf->ldapUser->drupalAcctProvisionServer == LDAP_USER_AUTH_SERVER_SID) {
695
        $auth_conf->ldapUser->drupalAcctProvisionServer = $ldap_server->sid;
696
      }
697
      break; //success
698
    }
699

    
700
  }  // end loop through servers
701

    
702
  $watchdog_tokens['%result'] = $result;
703
  $watchdog_tokens['%auth_result'] = $authentication_result;
704
  $watchdog_tokens['%err_text'] =  _ldap_authentication_err_text($authentication_result) ;
705
  if ($detailed_watchdog_log) {
706
    watchdog('ldap_authentication',  '%username : Authentication result id=%result auth_result=%auth_result (%err_text)', $watchdog_tokens, WATCHDOG_DEBUG);
707
  }
708

    
709
  return array($authentication_result, $ldap_user, $ldap_server);
710
}
711

    
712
function ldap_authentication_fail_response($authentication_result, $auth_conf, $detailed_watchdog_log, &$watchdog_tokens) {
713
  $watchdog_tokens['%err_text'] =  _ldap_authentication_err_text($authentication_result);
714
 // fail scenario 1.  ldap auth exclusive and failed  throw error so no other authentication methods are allowed
715
  if ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_EXCLUSIVE) {
716
    if ($detailed_watchdog_log) {
717
      watchdog('ldap_authentication', '%username : setting error because failed at ldap and
718
        LDAP_AUTHENTICATION_EXCLUSIVE is set to true.  So need to stop authentication of Drupal user that is not user 1.
719
        error message: %err_text', $watchdog_tokens, WATCHDOG_DEBUG);
720
    }
721
    form_set_error('name', $watchdog_tokens['%err_text']);
722
  }
723
  else {
724
 // fail scenario 2.  simply fails ldap.  return false, but don't throw form error
725
 // don't show user message, may be using other authentication after this that may succeed.
726
    if ($detailed_watchdog_log) {
727
      watchdog('ldap_authentication',
728
        '%username : Failed ldap authentication.
729
        User may have authenticated successfully by other means in a mixed authentication site.
730
        LDAP Authentication Error #: %auth_result  error message: %err_text',
731
        $watchdog_tokens,
732
        WATCHDOG_DEBUG
733
        );
734
    }
735
  }
736
}
737

    
738
/**
739
 * get human readable authentication error string
740
 *
741
 * @param int $error as LDAP_AUTHENTICATION_RESULT_* constant defined in ldap_authentication.module
742
 * @return string human readable error text
743
 */
744
function _ldap_authentication_err_text($error) {
745

    
746
  $msg = t('unknown error: ' . $error);
747
  switch ($error) {
748
    case LDAP_AUTHENTICATION_RESULT_FAIL_CONNECT:
749
    $msg = t('Failed to connect to ldap server');
750
    break;
751

    
752
    case LDAP_AUTHENTICATION_RESULT_FAIL_BIND:
753
    $msg = t('Failed to bind to ldap server');
754
    break;
755

    
756
    case LDAP_AUTHENTICATION_RESULT_FAIL_FIND:
757
    $msg =  t('Sorry, unrecognized username or password.');
758
    break;
759

    
760
    case LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED:
761
    $msg = t('User disallowed');
762
    break;
763

    
764
    case LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS:
765
    $msg =  t('Sorry, unrecognized username or password.');
766
    break;
767

    
768
    case LDAP_AUTHENTICATION_RESULT_FAIL_GENERIC:
769
    $msg = t('Sorry, unrecognized username or password.');
770
    break;
771

    
772
    case LDAP_AUTHENTICATION_RESULT_FAIL_SERVER:
773
    $msg = t('Authentication Server or Configuration Error.');
774
    break;
775

    
776
  }
777

    
778
  return $msg;
779
}
780