You are here

function _ldap_authentication_user_login_authenticate_validate in Lightweight Directory Access Protocol (LDAP) 8.2

Same name and namespace in other branches
  1. 7.2 ldap_authentication/ldap_authentication.inc \_ldap_authentication_user_login_authenticate_validate()
  2. 7 ldap_authentication/ldap_authentication.inc \_ldap_authentication_user_login_authenticate_validate()

user form validation will take care of username, pwd fields this function validates ldap authentication specific

Parameters

array $form_state array from user logon form:

Return value

null, but success or failure is indicated by: -- form_set_error() to invalidate authentication process -- setting $form_state['uid'] to indicate successful authentication

1 call to _ldap_authentication_user_login_authenticate_validate()
ldap_authentication_user_login_authenticate_validate in ldap_authentication/ldap_authentication.module
validate function for user logon forms.

File

ldap_authentication/ldap_authentication.inc, line 114
ldap_authentication helper functions

Code

function _ldap_authentication_user_login_authenticate_validate(&$form_state, $return_user) {
  $detailed_watchdog_log = config('ldap_help.settings')
    ->get('watchdog_detail');
  $authname = $form_state['values']['name'];

  // $authname is the name the user is authenticated with from the logon form // patch 1599632

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

  // $watchdog_tokens = array('%username' => $name); // patch 1599632
  if ($detailed_watchdog_log) {
    watchdog('ldap_authentication', '%username : Beginning authentification....', $watchdog_tokens, WATCHDOG_DEBUG);
  }
  if (!($auth_conf = ldap_authentication_get_valid_conf())) {
    watchdog('ldap_authentication', 'Failed to get valid ldap authentication configuration.', array(), WATCHDOG_ERROR);
    form_set_error('name', 'Server Error: Failed to get valid ldap authentication configuration.' . $error);
    return;
  }

  /**
   * I. Test for previous module authentication success.
   *
   * if already succeeded at authentication, $form_state['uid'] will be set by other authentication module.
   * - if LDAP Mixed mode is set, return and don't disrupt authentication process
   * - otherwise override other authenication by setting $form_state['uid'] = NULL
   */
  if (isset($form_state['uid']) && is_numeric($form_state['uid'])) {
    if ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_MIXED || $form_state['uid'] == 1) {
      if ($detailed_watchdog_log) {
        watchdog('ldap_authentication', '%username : Previously authenticated in mixed mode or uid=1', $watchdog_tokens, WATCHDOG_DEBUG);
      }
      return;

      // already passed a previous module's authentication validation
    }
    elseif ($auth_conf->authenticationMode == LDAP_AUTHENTICATION_EXCLUSIVE) {
      if ($detailed_watchdog_log) {
        watchdog('ldap_authentication', '%username : Previously authenticated in exclusive mode or uid is not 1.  Clear uid
        in form_state and attempt ldap authentication.', $watchdog_tokens, WATCHDOG_DEBUG);
      }
      $form_state['uid'] = NULL;

      // passed previous authentication, but only ldap should be used so override
    }
  }

  /**
   * II. Exit if no authentication servers.
   */
  if (!$auth_conf
    ->hasEnabledAuthenticationServers()) {
    watchdog('ldap_authentication', 'No LDAP servers configured.', array(), WATCHDOG_ERROR);
    form_set_error('name', 'Server Error:  No LDAP servers configured.');
    return;
  }

  /**
   * III. determine if corresponding drupal account exists for $authname
   */
  $drupal_account_is_authmapped = FALSE;
  list($drupal_account, $drupal_account_is_authmapped) = ldap_authentication_corresponding_drupal_user($authname, $auth_conf, $watchdog_tokens);
  $drupal_account_exists = is_object($drupal_account);
  if ($drupal_account_exists && $drupal_account->uid == 1) {
    return;

    // user 1 is not allowed to ldap authenticate
  }

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

  /**
   * V. if account_name_attr is set, drupal username is different than authname
   */
  if ($ldap_server_authenticated_on->account_name_attr != '') {
    $watchdog_tokens['%account_name_attr'] = $ldap_server_authenticated_on->account_name_attr;
    $drupal_accountname = $ldap_user['attr'][ldap_server_massage_text($ldap_server_authenticated_on->account_name_attr, 'attr_name', LDAP_SERVER_MASSAGE_QUERY_ARRAY)][0];
    if (!$drupal_accountname) {
      watchdog('ldap_authentication', 'Derived drupal username from attribute %account_name_attr returned no username for authname %authname.', $watchdog_tokens, WATCHDOG_ERROR);
      return;
    }
  }
  else {
    $drupal_accountname = $authname;
  }
  $watchdog_tokens['%drupal_accountname'] = $drupal_accountname;

  /**
   * VI. Find or create corresponding drupal account and set authmaps
   *
   * at this point, the following are know:
   * - a corresponding ldap account has been found
   * - user's credentials tested against it and passed
   * - their drupal accountname has been derived
   *
   */

  /**
   * VI.A: Drupal account doesn't exist with $authname used to logon,
   *  but puid exists in another Drupal account; this means username has changed
   *  and needs to be saved in Drupal account
   *
   */
  if (!$drupal_account_exists && $ldap_server_authenticated_on) {
    $puid = $ldap_server_authenticated_on
      ->userPuidFromLdapEntry($ldap_user['attr']);
    if ($puid) {
      $drupal_account = $ldap_server_authenticated_on
        ->userUserEntityFromPuid($puid);
      if ($drupal_account) {
        $drupal_account_exists = TRUE;
        $user_edit = array(
          'name' => $drupal_accountname,
        );
        $drupal_account = user_save($drupal_account, $user_edit, 'ldap_user');
        user_set_authmaps($drupal_account, array(
          "authname_ldap_user" => $authname,
        ));
        $drupal_account_is_authmapped = TRUE;
      }
    }
  }

  /**
   * VI.B: existing Drupal account but not authmapped to ldap modules,
   *   ldap authmap or disallow
   *
   */
  if ($drupal_account_exists && !$drupal_account_is_authmapped) {

    // account already exists
    if ($auth_conf->ldapUser->loginConflictResolve == LDAP_USER_CONFLICT_LOG) {
      if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {
        $watchdog_tokens['%conflict_name'] = $account_with_same_email->name;
        watchdog('ldap_authentication', 'LDAP user with DN %dn has a naming conflict with a local drupal user %conflict_name', $watchdog_tokens, WATCHDOG_ERROR);
      }
      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');
      return;
    }
    else {

      // LDAP_authen.AC.disallow.ldap.drupal
      // add ldap_authentication authmap to user.  account name is fine here, though cn could be used
      user_set_authmaps($drupal_account, array(
        'authname_ldap_user' => $authname,
      ));
      $drupal_account_is_authmapped = TRUE;
      if ($detailed_watchdog_log) {
        watchdog('ldap_authentication', 'set authmap for %username authname_ldap_user', $watchdog_tokens, WATCHDOG_DEBUG);
      }
    }
  }

  /**
   * VI.C: existing Drupal account with incorrect email.  fix email if appropriate
   *
   */
  if ($drupal_account_exists && $drupal_account->mail != $ldap_user['mail'] && ($auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY || $auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE)) {
    $user_edit = array(
      'mail' => $ldap_user['mail'],
    );
    $watchdog_tokens['%username'] = $drupal_account->name;
    if (!($updated_account = user_save($drupal_account, $user_edit))) {
      watchdog('ldap_authentication', 'Failed to make changes to user %username updated %changed.', $watchdog_tokens, WATCHDOG_ERROR);
    }
    elseif ($auth_conf->emailUpdate == LDAP_AUTHENTICATION_EMAIL_UPDATE_ON_LDAP_CHANGE_ENABLE_NOTIFY) {
      if (isset($user_edit['mail'])) {
        $watchdog_tokens['%mail'] = $user_edit['mail'];
        drupal_set_message(t('Your e-mail has been updated to match your current account (%mail).', $watchdog_tokens), 'status');
      }
      if (isset($user_edit['name'])) {
        $watchdog_tokens['%new_username'] = $user_edit['name'];
        drupal_set_message(t('Your old account username %username has been updated to %new_username.', $watchdog_tokens), 'status');
      }
    }
  }

  /**
   * VI.C: no existing Drupal account.  consider provisioning Drupal account.
   *
   */
  if (!$drupal_account_exists) {

    // VI.C.1 Do not provision Drupal account if another account has same email.
    if ($account_with_same_email = user_load_by_mail($ldap_user['mail'])) {

      /**
       * username does not exist but email does.  Since user_external_login_register does not deal with
       * mail attribute and the email conflict error needs to be caught beforehand, need to throw error here
       */
      $watchdog_tokens['%duplicate_name'] = $account_with_same_email->name;
      watchdog('ldap_authentication', 'LDAP user with DN %dn has email address
        (%mail) conflict with a drupal user %duplicate_name', $watchdog_tokens, WATCHDOG_ERROR);
      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');
      return;
    }

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

    // VI.C.3 Provision Drupal account

    /**
     *
     * new ldap_authentication provisioned account could let user_external_login_register create the account and set authmaps, but would need
     * to add mail and any other user->data data in hook_user_presave which would mean requerying ldap
     * or having a global variable.  At this point the account does not exist, so there is no
     * reason not to create it here.
     *
     * @todo create patch for core user module's user_external_login_register to deal with new external accounts
     *       a little tweak to add user->data and mail etc as parameters would make it more useful
     *       for external authentication modules
     */
    if ($auth_conf->ldapUser->acctCreation == LDAP_AUTHENTICATION_ACCT_CREATION_USER_SETTINGS_FOR_LDAP && config('user.settings')
      ->get('register') == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
      $user_edit = array(
        'name' => $drupal_accountname,
        'status' => 0,
      );

      // if admin approval required, set status to 0.
    }
    else {
      $user_edit = array(
        'name' => $drupal_accountname,
        'status' => 1,
      );
    }

    // don't pass in ldap user to provisionDrupalAccount, because want to requery with correct attributes needed
    // this may be a case where efficiency dictates querying for all attributes
    $drupal_account = $auth_conf->ldapUser
      ->provisionDrupalAccount(NULL, $user_edit, NULL, TRUE);
    if ($drupal_account === FALSE) {
      watchdog('ldap_user', 'Failed to find or create %drupal_accountname on logon.', $watchdog_tokens, WATCHDOG_ERROR);
      form_set_error('name', t('Server Error: Failed to create Drupal user account for %drupal_accountname', $watchdog_tokens));
      return;
    }
  }

  /**
   * we now have valid, ldap authenticated username with an account authmapped to ldap_authentication.
   * since user_external_login_register can't deal with user mail attribute and doesn't do much else, it is not
   * being used here.
   *
   * without doing the user_login_submit,
   * [#1009990],[#1865938]
   */
  $form_state['uid'] = $drupal_account->uid;

  // $fake_form_state = array('uid' => $drupal_account->uid);
  // user_login_submit(array(), $fake_form_state);
  // global $user;
  // $form_state['uid'] = $user->uid;
  // the uid is returned so that special login modules, namely ldap sso, can manually call this function.
  return $return_user ? $drupal_account : NULL;
}