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 @ 05237dd8

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