diff --git a/contrib/password_tab/password_policy_password_tab.info b/contrib/password_tab/password_policy_password_tab.info index 22e4f67..b207456 100644 --- a/contrib/password_tab/password_policy_password_tab.info +++ b/contrib/password_tab/password_policy_password_tab.info @@ -2,5 +2,10 @@ name = Password change tab description = Implements a separate password change tab. package = Other dependencies[] = password_policy -core = 6.x +core = 7.x +files[] = password_policy_password_tab.module +files[] = password_policy_password_tab.install +files[] = password_policy_password_tab.admin.inc +files[] = password_policy_password_tab.pages.inc +files[] = password_policy_password_tab.test diff --git a/contrib/password_tab/password_policy_password_tab.module b/contrib/password_tab/password_policy_password_tab.module index 81dba6c..71a0b41 100644 --- a/contrib/password_tab/password_policy_password_tab.module +++ b/contrib/password_tab/password_policy_password_tab.module @@ -5,43 +5,55 @@ * The password policy password tab module adds a separate tab to change password. */ -////////////////////////////////////////////////////////////////////////////// -// Core API hooks - /** * Implementation of hook_menu(). */ function password_policy_password_tab_menu() { - return array( - 'admin/settings/password_policy/password_tab' => array( - 'title' => 'Password tab', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('password_policy_password_tab_admin_settings'), - 'access arguments' => array('administer site configuration'), - 'file' => 'password_policy_password_tab.admin.inc', - ), - 'user/%user/password' => array( - 'title' => 'Password', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('password_policy_password_tab', 1), - 'access callback' => 'user_edit_access', - 'access arguments' => array(1), - 'type' => MENU_LOCAL_TASK, - 'file' => 'password_policy_password_tab.pages.inc', - ), + $items = array(); + + $items['user/%user/password'] = array( + 'title' => 'Password', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('password_policy_password_tab', 1), + 'access callback' => 'user_edit_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'file' => 'password_policy_password_tab.pages.inc', + ); + $items['admin/config/people/password_policy/password_tab'] = array( + 'title' => 'Password tab', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('password_policy_password_tab_admin_settings'), + 'access arguments' => array('administer site configuration'), + 'file' => 'password_policy_password_tab.admin.inc', + 'type' => MENU_LOCAL_TASK, + 'weight' => 10, + ); + + return $items; +} + +/** + * Implementation of hook_admin_paths(). + */ +function password_policy_password_tab_admin_paths() { + $paths = array( + 'user/*/password' => TRUE, ); + return $paths; } /** - * Implementation of hook_form_alter(). + * Implementation of hook_form_FORM_ID_alter(). */ -function password_policy_password_tab_form_alter(&$form, $form_state, $form_id) { - switch ($form_id) { - case "user_profile_form": - // Hide core password field from user edit form. - unset($form['account']['pass']); - break; +function password_policy_password_tab_form_user_profile_form_alter(&$form, &$form_state) { + if (isset($form['account']['current_pass_required_values']['#value']['pass'])) { + unset($form['account']['current_pass']); + unset($form['account']['current_pass_required_values']['#value']['pass']); } + + // Hide core password field from user edit form. + unset($form['account']['pass']); } /** @@ -66,9 +78,15 @@ function password_policy_password_tab_exit($destination = NULL) { $processed = TRUE; // Change the drupal_goto to our change password tab. $path .= '/password'; - $query = isset($url_parts['query']) ? $url_parts['query'] : NULL; - $fragment = isset($url_parts['fragment']) ? $url_parts['fragment'] : NULL; - drupal_goto($path, array('query' => $query, 'fragment' => $fragment)); + $opts = array(); + if (!empty($url_parts['fragment'])) { + $opts['fragment'] = $url_parts['fragment']; + } + if (!empty($url_parts['query'])) { + parse_str($url_parts['query'], $params); + $opts['query'] = $params; + } + drupal_goto($path, $opts); } } } diff --git a/contrib/password_tab/password_policy_password_tab.pages.inc b/contrib/password_tab/password_policy_password_tab.pages.inc index 66ac4ba..d05602e 100644 --- a/contrib/password_tab/password_policy_password_tab.pages.inc +++ b/contrib/password_tab/password_policy_password_tab.pages.inc @@ -9,17 +9,69 @@ * Password change form. */ function password_policy_password_tab($form, &$form_state, $account) { - $form['account']['pass'] = array( + global $user; + + // During initial form build, add the entity to the form state for use during + // form building and processing. During a rebuild, use what is in the form + // state. + if (!isset($form_state['user'])) { + $form_state['user'] = $account; + } + else { + $account = $form_state['user']; + } + + if ($user->uid == $account->uid) { + // To skip the current password field, the user must have logged in via a + // one-time link and have the token in the URL. + $pass_reset = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]); + $protected_values = array(); + $current_pass_description = ''; + // The user may only change their own password without their current + // password if they logged in via a one-time login link. + if (!$pass_reset) { + $protected_values['mail'] = t('E-mail address'); + $protected_values['pass'] = t('Password'); + $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); + $current_pass_description = t('Enter your current password to change the %mail or %pass. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new)); + } + // The user must enter their current password to change to a new one. + $form['current_pass_required_values'] = array( + '#type' => 'value', + '#value' => array('pass' => $protected_values['pass']), + ); + $form['account']['current_pass'] = array( + '#type' => 'password', + '#title' => t('Current password'), + '#size' => 25, + '#access' => !empty($protected_values), + '#description' => $current_pass_description, + '#weight' => -5, + '#attributes' => array('autocomplete' => 'off'), + ); + + $form['#validate'][] = 'user_validate_current_pass'; + } + + $form['pass'] = array( '#type' => 'password_confirm', - '#description' => t('To change the current user password, enter the new password in both fields.'), '#size' => 25, + '#required' => TRUE, + '#description' => t('To change the current user password, enter the new password in both fields.'), ); + + // @TODO Remove this as it supports a D6-style of interacting with a user form + // In the future, this data should be stored in $form_state. $form['#uid'] = $account->uid; + $form['#user'] = $account; $form['_account'] = array('#type' => 'value', '#value' => $account); - $form['submit'] = array('#type' => 'submit', '#value' => t('Change')); - $form['#validate'] = array('password_policy_password_tab_validate'); - $form['#submit'] = array('password_policy_password_tab_submit'); - password_policy_form_alter($form, array(), 'user_profile_form'); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + return $form; } @@ -27,9 +79,7 @@ function password_policy_password_tab($form, &$form_state, $account) { * Password change form validation. */ function password_policy_password_tab_validate($form, &$form_state) { - $values = $form_state['values']; - - $pass = trim($values['pass']); + $pass = trim($form_state['values']['pass']); if (empty($pass)) { form_set_error('pass', t('Your password cannot be empty.')); } @@ -39,14 +89,26 @@ function password_policy_password_tab_validate($form, &$form_state) { * Password change form submit. */ function password_policy_password_tab_submit($form, &$form_state) { + global $user; + $account = $form['_account']['#value']; + $account = $form_state['user']; + user_module_invoke('submit', $form_state['values'], $account, 'account'); user_save($account, array('pass' => $form_state['values']['pass'])); drupal_set_message(t('Password has been changed.')); + if (variable_get('password_policy_password_tab_redirect', '') && !preg_match('/[?&]destination=/', $form['#action'])) { - global $user; - $redirect = parse_url(urldecode(strtr(variable_get('password_policy_password_tab_redirect', ''), array('%uid' => $user->uid)))); - $form_state['redirect'] = array($redirect['path'], isset($redirect['query']) ? $redirect['query'] : NULL, isset($redirect['fragment']) ? $redirect['fragment'] : NULL); + $redirect = drupal_parse_url(format_string(variable_get('password_policy_password_tab_redirect', ''), array('%uid' => $user->uid))); + $opts = array(); + + if (!empty($redirect['fragment'])) { + $opts['fragment'] = $redirect['fragment']; + } + if (!empty($redirect['query'])) { + parse_str($redirect['query'], $params); + $opts['query'] = $params; + } + drupal_goto($redirect['path'], $redirect); } } - diff --git a/contrib/password_tab/password_policy_password_tab.test b/contrib/password_tab/password_policy_password_tab.test new file mode 100644 index 0000000..b0f87b4 --- /dev/null +++ b/contrib/password_tab/password_policy_password_tab.test @@ -0,0 +1,36 @@ + 'Password tab test', + 'description' => t('Assure that password change tab works.'), + 'group' => 'Password Policy', + ); + } + + public function setUp() { + parent::setUp('password_policy', 'password_policy_password_tab'); + $this->user = $this->drupalCreateUser(); + } + + function testPasswordTab() { + $this->drupalLogin($this->user); + + // Check tab is working + $this->drupalGet('user/' . $this->user->uid . '/password'); + + // Attempt password change + $edit = array( + 'current_pass' => $this->user->pass_raw, + 'pass[pass1]' => $this->user->pass_raw . $this->user->pass_raw, + 'pass[pass2]' => $this->user->pass_raw . $this->user->pass_raw, + ); + $this->drupalPost('user/' . $this->user->uid . '/password', $edit, 'Save'); + $this->assertText(t('Password has been changed.')); + } +} diff --git a/password_policy.module b/password_policy.module index 7504ddb..6de256a 100644 --- a/password_policy.module +++ b/password_policy.module @@ -423,6 +423,7 @@ function password_policy_form_alter(&$form, $form_state, $form_id) { switch ($form_id) { case 'user_profile_form': case 'user_register_form': + case 'password_policy_password_tab': // Force password change on user account. if (user_access('force password change')) { if (isset($form['#user_category']) && $form['#user_category'] == 'account') {