2

I'm in a project where the main login form must not have a password field. The user will login with a username and selecting a Country. This country field is configured within the user profile. So far, I can manage to log in users checking their username and the selected countries, but I can't find anything not to require a password for login.

This is my code.

function hdp_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'user_login_block') {
    // Add country field to login form
    $form['pais'] = array(
      '#type' => 'select',
      '#title' => t('Pais'),
      '#options' => array(
        'Argentina' => t('Argentina'),
        'Chile' => t('Chile'),
        'Peru' => t('Peru'),
      ),
      '#required' => TRUE,
    );
    // Add validation to check country-username
    $form['#validate'][] = 'validacion';
  }
}

function validacion(&$form, &$form_state) {
  // Variables.
  $usuario_nombre = $form_state['values']['name'];
  $usuario_pais_seleccionado = $form_state['values']['pais'];

  // Search user countries by username. Username must not be duplicated.
  $uid = db_query("SELECT uid FROM {users} WHERE name IN ('$usuario_nombre')")->fetchField();
  if (!empty($uid)) {
    $paises = db_query("SELECT field_paises_value FROM {field_data_field_paises} WHERE entity_id IN ($uid)")->fetchAll();
    $paises_habilitados = NULL;
    foreach ($paises as $pais) {
    $paises_habilitados .= $pais->field_paises_value;
  }

  // Check if selected country is one of the user profile selected countries.
  $habilitado = strpos($paises_habilitados, $usuario_pais_seleccionado);
  if ($habilitado === false) {
    form_set_error('pais', 'Acceso denegado. Por favor revise su nombre de usuario y el país seleccionado.');
  }
}
4

If you don't require a password from your users, then you should:

  • Make the password form field not visible to the users (it is enough to set #access to FALSE)

  • Remove the form validation handlers that are not necessary

The form validation handlers that the user login block uses are the following:

What you need to do is removing 'user_login_authenticate_validate' and 'user_login_final_validate' from the array $form['#validate'].

Remember also that your form validation handler needs to set $form_state['uid'], since that is the value used from user_login_submit() to load the user object from the database.

As additional notes:

  • Your code is making assumptions about where/how the field data are saved; in particular, it is assuming the field data are saved in the database currently used by the Drupal site, which is not necessary true, since field data could be saved in MongoDB. I would rather use the following code.

    $uid = db_query("SELECT uid FROM {users} WHERE name = :account_name", array(':account_name' => $usuario_nombre))->fetchField();
    if (!empty($uid)) {
      $account = user_load($uid);
      if ($countries = field_get_items('user', $account, 'field_paises')) {
        // I assume users can just select a single country.
        $country = array_shift($countries);
        if ($country != $usuario_pais_seleccionado) {
          // Show the error message.
        }
      }
    }
    
  • You cannot use user_authenticate(), since that requires the account password, which is not saved in the database. The database contains the password hash.

  • The string passed to t() should contain words in English, since the function is used to translate from English to the language currently set for the site. (Pais is not an English word; probably you meant Country.)
  • Instead of WHERE name IN ('$usuario_nombre'), you should use WHERE name = :username. Input from users should not be used directly in SQL queries, as that is a security issue. (See SQL injection.)
  • Functions implemented by a module should always have their names prefixed by the module name.

Talking of security issues, I hope you are using the authentication method you described in a very restricted, controlled environment. I would not use it in a public site where everybody can create an account, especially if the username and the country selected from users are visible to everybody. Even in the case the country is not visible, getting the right username/country combination is much easier than finding the right username/password combination that allows you to log in.

  • Thanks Kiamlaluno. I manage to add $form['pass']['#access'] = FALSE and it worked. And i tried $form['#validate'] = array('user_login_name_validate', 'validacion'); and it does not work and i think its because i don't know what to do with this line $form_state['uid']. I get 5 errors like Undefined property: stdClass::$uid.... Plus Drupal "login" a user without name... – Federico Arena May 21 '13 at 16:51
  • $form_state['uid'] is the user ID of the account that Drupal will load. It is used from user_login_submit(). – kiamlaluno May 21 '13 at 17:30
  • kiamlaluno, i searched about login_submit, handler and $form_state and i can't understand too much. I tried $form['#submit'] = 'kbza';function kbza($form, &$form_state) { global $user; $user = user_load($form_state['uid']); $form_state['redirect'] = 'user/' . $user->uid; user_login_finalize($form_state); } as in user.module but it does not work. This is my first module and i'm not a developer, do you know any good tutorial about it? Thanks in advance. – Federico Arena May 21 '13 at 18:40
  • You don't need to replace the form submission handler with another that does the same thing: If there is code that doesn't work, that is in your validation handler. – kiamlaluno May 21 '13 at 18:46
  • I have been reading, learning from and analysing the extra code you just put and i works fine. Even it works fine, Drupal won't log me in so i ended up erasing the validation function. Even if i erase it, Drupal logs the same error: Notice: Undefined index: uid in user_login_submit() (line 2269 of \modules\user\user.module). That line is $user = user_load($form_state['uid']); so i presume something about $form_state['uid'] is missing somewhere. Plus when you mention i have to remove 'user_login_name_validate', i think you meant 'user_login_authenticate_validate()'. Thanks 4 ur patience – Federico Arena May 21 '13 at 20:09

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.