1

I wrote a custom user_login form validation function that calls user_external_login_register() to register and login the user, but the last validation function for the form calls form_set_error().

The form's #validate array looks like this:

validate (Array, 4 elements)

    * 0 (String, 32 characters ) vtiger_portal_user_form_validate
    * 1 (String, 24 characters ) user_login_name_validate
    * 2 (String, 32 characters ) user_login_authenticate_validate
    * 3 (String, 25 characters ) user_login_final_validate

user_login_final_validate() is here: http://api.drupal.org/api/drupal/modules--user--user.module/function/user_login_final_validate

Here is the code for vtiger_portal_user_form_validate() and the authentication function that it calls:

function vtiger_portal_user_form_validate($form, &$form_state) {
  if (!vtiger_portal_authenticate($form_state)) {
    // Not a portal user. Let the other validation handlers run.
  } else {
    global $user;
    if($user->uid) {
      dpm($user);
    }
  }
}

/**
 * Custom user authentication function
 */
function vtiger_portal_authenticate($form_state) {  
  $username = $form_state['input']['name'];
  $password = $form_state['input']['pass'];
  $testname = drupal_substr(drupal_strtolower($username),0,4);
  if ($testname == "dave") {
    user_external_login_register($username, 'vtiger_portal');
    return TRUE;
  } else {
    return FALSE;
  }
}

I'm Seeing the "Sorry, unrecognized username or password. Have you forgotten your password?" error and at the same time, being successfully logged in. I have printed the $user object after calling user_external_login_register() and it shows that the uid is 9.

Can anyone help me figure out why I'm seeing an error from user_login_final_validate() when the user has obviously logged in successfully?

Update: I've found the root of the problem.

From the line 2121, user.module contains the following code.

// We are not limited by flood control, so try to authenticate.
// Set $form_state['uid'] as a flag for user_login_final_validate().
$form_state['uid'] = user_authenticate($form_state['values']['name'], $password);

user_login_authenticate_validate() sets $form_state['uid'] to FALSE so that later user_login_final_validate() sends it's error message.

  • Hello Arosboro, and welcome on Drupal Answers. May you report the code of vtiger_portal_user_form_validate(), which I think it is your custom form validation handler? – kiamlaluno Mar 24 '11 at 19:00
  • kiamlaluno, I've updated the post with the code you requested – Arosboro Mar 24 '11 at 19:43
  • Thank you. That code is useful to understand why you get that error message. – kiamlaluno Mar 24 '11 at 20:10
2

The OP mistakenly pasted user_login_final_validate() from D6 instead of D7. In D7, you avoid that error message by simply setting $form_state['uid'] = [a number]. You do that from within your custom #validate callback. Once you have done that, user_login_final_validate() will not throw an error and your form submission proceeds and thus login proceeds.

  • moshe, thanks for your help in #drupal-contribute. I am going to work on re-ordering the validation array so that my validation function can set $form_state['uid'] to true after user_login_authenticate_validate runs. – Arosboro Mar 24 '11 at 21:22
  • I added my validation function after the first two functions and before user_login_final_validate. I added $form_state['uid'] = TRUE to my function as you suggested and the error message pertaining to the wrong username or password went away... Unfortunately now there is another error from array_flip() in includes/entity.inc: Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->load() line 178 and Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->cacheGet() line 354. Why so many errors?! – Arosboro Mar 24 '11 at 22:09
  • the array_flip() errors were caused by setting $form_state['uid'] to true. I had to set it to the actual uid from $user->uid. – Arosboro Mar 25 '11 at 16:44
0

It would appear that the user_login_authenticate_validate() function will actually log the user in. The workaround is to unset the user_login_authenticate_validate() callback, and call user_authenticate() from vtiger_portal_authenticate() once you have performed your additional validation.

In order to unset the user_login_authenticate_validate() callback, you'll need to implement hook_form_alter():

vtiger_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'user_login') {
    $key = array_search('user_login_authenticate_validate', $form['#validate']);
    if ($key !== FALSE) {
      unset($form['#validate'][$key]);
    }
  }
}
  • jhedstrom, is there a way to get both to co-operate? Perhaps if I could put my custom validation function second to last. – Arosboro Mar 24 '11 at 21:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.