Projet

Général

Profil

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

root / htmltest / sites / all / modules / ldap / ldap_authentication / ldap_authentication.inc @ dd54aff9

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']['#type'] = 'hidden';
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 = '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
  }
166

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

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

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

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

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

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

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

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

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

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

    
265
  // @todo maybe we can add more tokens?
266
  $email_template_tokens = array(
267
    '@username' => $drupal_accountname,
268
  );
269
  
270
  $email_template_used = FALSE;
271
  
272
  /**
273
   * Ensures that we respect the email template handling settings.
274
   */
275
  if (!empty($auth_conf->emailTemplate)) {
276
    switch ($auth_conf->emailTemplateHandling) {
277
      case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_IF_EMPTY:
278
        if (!empty($ldap_user['mail'])) {
279
          break;
280
        }
281
        // deliberate fallthrough
282
      case LDAP_AUTHENTICATION_EMAIL_TEMPLATE_ALWAYS:
283
        _ldap_authentication_replace_user_email($ldap_user, $auth_conf, $email_template_tokens);
284
        if ($detailed_watchdog_log) {
285
          watchdog('ldap_authentication', 'Using template generated email for %username', $watchdog_tokens, WATCHDOG_DEBUG);
286
        }
287
        $email_template_used = TRUE;
288
        break;
289
    }
290
  }
291
  
292
  /**
293
   * VI. Find or create corresponding drupal account and set authmaps
294
   *
295
   * at this point, the following are know:
296
   * - a corresponding ldap account has been found
297
   * - user's credentials tested against it and passed
298
   * - their drupal accountname has been derived
299
   *
300
   */
301

    
302

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

    
328
  /**
329
   * VI.B: existing Drupal account but not authmapped to ldap modules,
330
   *   ldap authmap or disallow
331
   *
332
   */
333

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

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

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

    
382
  /**
383
   * VI.C: no existing Drupal account.  consider provisioning Drupal account.
384
   *
385
   */
386
  if (!$drupal_account_exists) {
387

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

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

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

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

    
444
    if ($auth_conf->ldapUser->acctCreation == LDAP_AUTHENTICATION_ACCT_CREATION_USER_SETTINGS_FOR_LDAP &&
445
        variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
446
      $user_edit = array('name' => $drupal_accountname, 'status' => 0); // if admin approval required, set status to 0.
447
    }
448
    else {
449
      $user_edit = array('name' => $drupal_accountname, 'status' => 1);
450
    }
451
    
452
    // If the email template was used, we want to pass in the email that was
453
    // generated so that its not overridden by the provisioner.
454
    if ($email_template_used) {
455
      $user_edit['mail'] = $ldap_user['mail'];
456
    }
457

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

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

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

    
486
  $form_state['uid'] = $drupal_account->uid;
487
 // $fake_form_state = array('uid' => $drupal_account->uid);
488
 // user_login_submit(array(), $fake_form_state);
489
 // global $user;
490
 // $form_state['uid'] = $user->uid;
491

    
492

    
493
  // the uid is returned so that special login modules, namely ldap sso, can manually call this function.
494
  return ($return_user) ? $drupal_account : NULL;
495
}
496

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

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

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

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

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

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

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

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

    
629
    $watchdog_tokens['%dn'] = $ldap_user['dn'];
630
    $watchdog_tokens['%mail'] = $ldap_user['mail'];
631

    
632
    /**
633
    * #4 CHECK ALLOWED AND EXCLUDED LIST AND PHP FOR ALLOWED USERS
634
    */
635

    
636
    if (!$auth_conf->allowUser($authname, $ldap_user)) {
637
      $authentication_result = LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED;
638
      break;  // regardless of how many servers, disallowed user fails
639
    }
640

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

    
688
  }  // end loop through servers
689

    
690
  $watchdog_tokens['%result'] = $result;
691
  $watchdog_tokens['%auth_result'] = $authentication_result;
692
  $watchdog_tokens['%err_text'] =  _ldap_authentication_err_text($authentication_result) ;
693
  if ($detailed_watchdog_log) {
694
    watchdog('ldap_authentication',  '%username : Authentication result id=%result auth_result=%auth_result (%err_text)', $watchdog_tokens, WATCHDOG_DEBUG);
695
  }
696

    
697
  return array($authentication_result, $ldap_user, $ldap_server);
698
}
699

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

    
726
/**
727
 * get human readable authentication error string
728
 *
729
 * @param int $error as LDAP_AUTHENTICATION_RESULT_* constant defined in ldap_authentication.module
730
 * @return string human readable error text
731
 */
732
function _ldap_authentication_err_text($error) {
733

    
734
  $msg = t('unknown error: ' . $error);
735
  switch ($error) {
736
    case LDAP_AUTHENTICATION_RESULT_FAIL_CONNECT:
737
    $msg = t('Failed to connect to ldap server');
738
    break;
739

    
740
    case LDAP_AUTHENTICATION_RESULT_FAIL_BIND:
741
    $msg = t('Failed to bind to ldap server');
742
    break;
743

    
744
    case LDAP_AUTHENTICATION_RESULT_FAIL_FIND:
745
    $msg =  t('Sorry, unrecognized username or password.');
746
    break;
747

    
748
    case LDAP_AUTHENTICATION_RESULT_FAIL_DISALLOWED:
749
    $msg = t('User disallowed');
750
    break;
751

    
752
    case LDAP_AUTHENTICATION_RESULT_FAIL_CREDENTIALS:
753
    $msg =  t('Sorry, unrecognized username or password.');
754
    break;
755

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

    
760
    case LDAP_AUTHENTICATION_RESULT_FAIL_SERVER:
761
    $msg = t('Authentication Server or Configuration Error.');
762
    break;
763

    
764
  }
765

    
766
  return $msg;
767
}
768