You are here

ga_login.module in Google Authenticator login 6

Same filename and directory in other branches
  1. 7 ga_login.module

File

ga_login.module
View source
<?php

// $Id

/**
 * Implementation of hook_menu().
 *
 * @see: http://api.drupal.org/api/function/hook_menu/6
 */
function ga_login_menu() {
  $items = array();
  $items['ga_login/create'] = array(
    'type' => MENU_NORMAL_ITEM,
    'title' => 'Create GA login',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ga_login_create_form',
    ),
    'access arguments' => array(
      'administer users',
    ),
  );
  $items['ga_login/test'] = array(
    'type' => MENU_NORMAL_ITEM,
    'title' => 'Test GA login',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ga_login_test_form',
    ),
    'access arguments' => array(
      'administer users',
    ),
  );
  $items['admin/user/ga_login'] = array(
    'type' => MENU_NORMAL_ITEM,
    'title' => 'GA login',
    'description' => 'Administer Google Authenticator login settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ga_login_admin_settings_form',
    ),
    'access arguments' => array(
      'administer ga_login settings',
    ),
    'file' => 'ga_login.admin.inc',
  );
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function ga_login_perm() {
  return array(
    'login without code',
    'administer ga_login settings',
  );
}
function ga_login_create_form() {
  $result = db_query("SELECT uid, name FROM {users}");
  while ($account = db_fetch_object($result)) {
    $options[$account->uid] = check_plain($account->name);
  }
  $form['info'] = array(
    '#type' => 'markup',
    '#value' => '<p>' . t('Everytime you use this form a new key will be generated!') . '</p>',
  );
  $form['uid'] = array(
    '#title' => t('User'),
    '#type' => 'select',
    '#options' => $options,
    '#required' => TRUE,
  );
  $form['tokentype'] = array(
    '#title' => t('Code type'),
    '#type' => 'select',
    '#options' => array(
      'TOTP' => t('Time-based code'),
      'HOTP' => t('Counter-based code'),
    ),
    '#default_value' => 'TOTP',
    '#required' => TRUE,
    '#description' => t('Select the type of code you want to create.'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Create code'),
  );
  return $form;
}
function ga_login_test_form() {
  $result = db_query("SELECT uid, name FROM {users}");
  while ($account = db_fetch_object($result)) {
    $options[$account->uid] = check_plain($account->name);
  }
  $form['uid'] = array(
    '#title' => t('User'),
    '#type' => 'select',
    '#options' => $options,
    '#required' => TRUE,
  );
  $form['code'] = array(
    '#title' => t('Code'),
    '#type' => 'textfield',
    '#required' => TRUE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Check code'),
  );
  return $form;
}
function ga_login_create_form_submit($form, $form_state) {
  $uid = $form_state['values']['uid'];
  $account = user_load($uid);
  module_load_include('php', 'ga_login', 'ga_login.class');
  $ga = new ga_loginGA(variable_get('ga_login_totp_skew', 10), variable_get('ga_login_hotp_skew', 10));
  $username = _ga_login_username($account);
  if (!$ga
    ->hasToken($username)) {
    $key = $ga
      ->setUser($username, $form_state['values']['tokentype']);
  }
  $url = $ga
    ->createUrl($username);
  drupal_set_message($url);
  drupal_set_message(theme_qr_codes($url));
}
function ga_login_test_form_submit($form, $form_state) {
  $uid = $form_state['values']['uid'];
  $code = $form_state['values']['code'];
  $account = user_load($uid);
  module_load_include('php', 'ga_login', 'ga_login.class');
  $ga = new ga_loginGA(variable_get('ga_login_totp_skew', 10), variable_get('ga_login_hotp_skew', 10));
  $username = _ga_login_username($account);
  $keyok = $ga
    ->authenticateUser($username, $code);
  if ($keyok) {
    drupal_set_message('Authentication OK');
  }
  else {
    drupal_set_message('Authentication failed');
    drupal_set_message($ga
      ->getErrorText());
  }
}
function ga_login_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'user_login_block' || $form_id == 'user_login') {

    // Re-arrange and add validation handlers.
    array_unshift($form['#validate'], $form['#validate'][0]);
    $form['#validate'][1] = 'ga_login_user_login_validate';
    $form['#validate'][] = 'ga_login_user_login_validate_code_needed';
    $form['gacode'] = array(
      '#type' => 'textfield',
      '#title' => 'Code',
      '#maxlength' => 6,
      '#size' => 6,
      '#required' => FALSE,
    );
    $form['name']['#weight'] = 1;
    $form['pass']['#weight'] = 2;
    $form['gacode']['#weight'] = 3;
    $form['submit']['#weight'] = 4;
    if (isset($form['links'])) {
      $form['links']['#weight'] = 5;
    }
  }
  elseif ($form_id == 'user_profile_form') {
    $account = user_load($form['#uid']);
    $register = $account->uid > 0 ? FALSE : TRUE;

    // Add some more settings to the user profile form.
    $form['ga_login'] = array(
      '#type' => 'fieldset',
      '#title' => t('Two factor authentication'),
      '#weight' => 1,
      '#access' => !$register && user_access('login without code', $account),
    );
    $data = unserialize($account->data);
    $form['ga_login']['ga_login_force_tfa'] = array(
      '#type' => 'checkbox',
      '#title' => t('Protect my account with two-factor-authentication'),
      '#default_value' => isset($data['ga_login_force_tfa']) ? $data['ga_login_force_tfa'] : FALSE,
      '#description' => t('Check this box to force two-factor-authentication during login. If you decide to do so and haven\'t yet created your key, then please also refer to <a href="@url">GA Login</a>.', array(
        '@url' => url('ga_login/create'),
      )),
    );
  }
}

/**
 * Validate callback for login form.
 *
 * Checks if the ga_login code is needed and valid.
 *
 * @see ga_login_form_alter()
 */
function ga_login_user_login_validate($form, &$form_state) {
  $name = $form_state['values']['name'];
  $code = $form_state['values']['gacode'];
  $account = user_load(array(
    'name' => $name,
  ));
  $form_state['uid'] = $account->uid;
  if (_ga_login_force_tfa($account) || !empty($code) || $account->uid == 1 && variable_get('ga_login_always_for_uid1', 0)) {
    module_load_include('php', 'ga_login', 'ga_login.class');
    $ga = new ga_loginGA(variable_get('ga_login_totp_skew', 10), variable_get('ga_login_hotp_skew', 10));
    $username = _ga_login_username($account);
    if ($ga
      ->hasToken($username)) {
      $keyok = $ga
        ->authenticateUser($username, $code);
      if (!$keyok) {
        form_set_error('gacode', t("Your code isn't valid."));
        $form_state['ga_code'] = 'invalid';
      }
      else {
        $form_state['ga_code'] = 'valid';
      }
    }
  }
}

/**
 * Validate callback for login form.
 *
 * Checks if the user has to use ga_login, but doesn't yet have a code.
 *
 * @see ga_login_form_alter()
 */
function ga_login_user_login_validate_code_needed($form, &$form_state) {
  $name = $form_state['values']['name'];
  $code = $form_state['values']['gacode'];
  $account = user_load(array(
    'name' => $name,
  ));
  if (_ga_login_force_tfa($account) || !empty($code) || $account->uid == 1 && variable_get('ga_login_always_for_uid1', 0)) {

    // The username and password are valid, check if the user has a token.
    if ($form_state['uid'] && !isset($form_state['ga_code'])) {
      form_set_error('gacode');
      unset($_GET['destination']);
      drupal_set_message(t('You don\'t have a login code yet. This login will only work once. After you log in, you can go to your profile page to generate the GA login code.'), 'warning');
      drupal_goto(user_pass_reset_url($account));
    }
  }
}

/**
 * Check if the given account wants to be forced to use tfa.
 */
function _ga_login_force_tfa($account) {
  if (user_access('login without code', $account)) {
    $data = unserialize($account->data);
    return isset($data['ga_login_force_tfa']) ? $data['ga_login_force_tfa'] : FALSE;
  }
  return TRUE;
}

/**
 * Create a site specific username.
 */
function _ga_login_username($account, $encode = TRUE) {
  $realm = variable_get('ga_login_textname', variable_get('site_name', 'Drupal'));
  $suffix = variable_get('ga_login_textid', '');
  $username = $account->name . '@' . $realm . $suffix;
  return $encode ? rawurlencode($username) : $username;
}

Functions

Namesort descending Description
ga_login_create_form
ga_login_create_form_submit
ga_login_form_alter
ga_login_menu Implementation of hook_menu().
ga_login_perm Implementation of hook_perm().
ga_login_test_form
ga_login_test_form_submit
ga_login_user_login_validate Validate callback for login form.
ga_login_user_login_validate_code_needed Validate callback for login form.
_ga_login_force_tfa Check if the given account wants to be forced to use tfa.
_ga_login_username Create a site specific username.