/** * Restore a Phorum user session. * * This function will check for a valid user session for either the * forum or the admin interface (based on the $type parameter). If a valid * session is found, then the user session will be restored. * * Before calling this function, the variable $PHORUM['use_cookies'] * should be set to one of {@link PHORUM_NO_COOKIES}, * {@link PHORUM_USE_COOKIES} or {@link PHORUM_REQUIRE_COOKIES}. * * @param string $type * The type of session to check for. This must be one of * {@link PHORUM_FORUM_SESSION} or {@link PHORUM_ADMIN_SESSION}. * See the documentation for {@link phorum_api_user_session_create()} * for more information on Phorum user sessions. * * @return boolean * TRUE in case a valid session is detected, otherwise FALSE. * Note that a {@link PHORUM_FORUM_SESSION} will return TRUE if * a long term session is detected and that the sort term session * might be missing. Code which depends on short term sessions should * investigate the $PHORUM["DATA"]["FULLY_LOGGEDIN"] variable. */ function phorum_api_user_session_restore($type) { $PHORUM = $GLOBALS['PHORUM']; // ---------------------------------------------------------------------- // Determine which session cookie(s) to check. // ---------------------------------------------------------------------- // A list of session cookies to lookup. // The possible values for the items in this array are: // // 0: this cookie does not have to be checked // 1: a check has to be done or failed for this cookie // 2: the check for this cookie was successful // $check_session = array(PHORUM_SESSION_LONG_TERM => 0, PHORUM_SESSION_SHORT_TERM => 0, PHORUM_SESSION_ADMIN => 0); if ($type == PHORUM_FORUM_SESSION) { // Lookup the long term cookie. $check_session[PHORUM_SESSION_LONG_TERM] = 1; // Lookup the short term cookie if tight security is enabled. if (!empty($PHORUM['tight_security'])) { $check_session[PHORUM_SESSION_SHORT_TERM] = 1; } } elseif ($type == PHORUM_ADMIN_SESSION) { // Lookup the admin cookie. $check_session[PHORUM_SESSION_ADMIN] = 1; } else { trigger_error('phorum_api_user_session_restore(): Illegal session type: ' . htmlspecialchars($type), E_USER_ERROR); return NULL; } // ---------------------------------------------------------------------- // Check the session cookie(s). // ---------------------------------------------------------------------- // Now we decided what session cookie(s) we want to check, we allow // modules to hook into the session system to do the check for us. // This can for example be used to let Phorum inherit an already // running authenticated session in some external system. /** * [hook] * user_session_restore * * [description] * Allow modules to override Phorum's session restore management. * This hook is the designated hook if you need to let Phorum * inherit an authenticated session from some external system.<sbr/> * <sbr/> * The array that is passed to this hook, * contains a key for each of the Phorum session types: * <ul> * <li>PHORUM_SESSION_LONG_TERM</li> * <li>PHORUM_SESSION_SHORT_TERM</li> * <li>PHORUM_SESSION_ADMIN</li> * </ul> * What the module has to do, is fill the values for each of these * keys with the user_id of the Phorum user for which the session that * the key represents should be considered active. Other options * are FALSE to indicate that no session is active and NULL to * tell Phorum to handle session restore on its own.<sbr/> * <sbr/> * Note that the user for which a user_id is provided through this * hook must exist in the Phorum system before returning from this * hook. One option to take care of that constraint is letting * this hook create the user on-the-fly if needed. A cleaner way * would be to synchronize the user data from the main system at those * times when the user data changes (create, update and delete user). * Of course it is highly dependent on the other system whether * you can implement that kind of Phorum user management in the main * application.<sbr/> * <sbr/> * Hint: Creating users can be done using the * <literal> phorum_api_user_save()</literal> user API function. * * [category] * User authentication and session handling * * [when] * Just before Phorum runs its own session restore code * in the user API function * <literal>phorum_api_user_session_restore()</literal>. * * [input] * An array containing three keys: * <ul> * <li>PHORUM_SESSION_LONG_TERM</li> * <li>PHORUM_SESSION_SHORT_TERM</li> * <li>PHORUM_SESSION_ADMIN</li> * </ul> * By default, all values for these keys are NULL. * * [output] * Same as input, possibly with updated array values. * * [example] * See the <hook>user_session_create</hook> hook for an example * of how to let Phorum setup the PHP session that is picked up * in this example hook. * <hookcode> * function phorum_mod_foo_user_session_restore($sessions) * { * // Override the session handling for front end forum sessions. * // We could for example retrieve a session from a standard PHP * // session by first starting a PHP session if that was * // not done yet... * if (!session_id()) session_start(); * * // ...and then retrieving the user_id of the current user * // from the PHP session data. The user_id is really the * // only thing that needs to be remembered for a Phorum * // session, because all other data for the user is stored * // in the database. If no user id was set in the session, * // then use FALSE to flag this to Phorum. * $phorum_user_id = empty($_SESSION['phorum_user_id']) * ? FALSE : $_SESSION['phorum_user_id']; * * // If we only use session inheritance for the front end * // forum session (highly recommended for security), then * // We keep PHORUM_SESSION_ADMIN at NULL (default value). * // The other two need to be updated. If the main system does * // not use the concept of one long and one short term cookie * // (named "tight security" by Phorum), then simply assign * // the user_id to both PHORUM_SESSION_LONG_TERM and * // PHORUM_SESSION_SHORT_TERM. * $sessions[PHORUM_SESSION_SHORT_TERM] = $phorum_user_id; * $sessions[PHORUM_SESSION_LONG_TERM] = $phorum_user_id; * * return $sessions; * } * </hookcode> */ $hook_sessions = array(PHORUM_SESSION_LONG_TERM => NULL, PHORUM_SESSION_SHORT_TERM => NULL, PHORUM_SESSION_ADMIN => NULL); if (isset($PHORUM['hooks']['user_session_restore'])) { $hook_sessions = phorum_hook('user_session_restore', $hook_sessions); } $real_cookie = FALSE; $session_user = NULL; foreach ($check_session as $cookie => $do_check) { if (!$do_check) { continue; } // Check if a module did provide a user_id for the checked session. $user_id_from_hook_session = FALSE; if ($hook_sessions[$cookie] !== NULL) { // Continue with the next cookie, if a module specified the // session cookie as invalid. if ($hook_sessions[$cookie] === FALSE) { continue; } // Pass on the user_id that was set by the module. // We add a fake a session id to the user_id here, // to make the split from below work. $value = $hook_sessions[$cookie] . ':dummy'; $user_id_from_hook_session = TRUE; // To not let Phorum fall back to URI authentication. $real_cookie = TRUE; } elseif (($cookie != PHORUM_SESSION_LONG_TERM || isset($PHORUM['use_cookies']) && $PHORUM['use_cookies'] > PHORUM_NO_COOKIES) && isset($_COOKIE[$cookie])) { $value = $_COOKIE[$cookie]; $real_cookie = TRUE; } elseif ($PHORUM['use_cookies'] < PHORUM_REQUIRE_COOKIES && isset($PHORUM['args'][$cookie])) { $value = urldecode($PHORUM['args'][$cookie]); } elseif ($PHORUM['use_cookies'] < PHORUM_REQUIRE_COOKIES && isset($_POST[$cookie])) { $value = $_POST[$cookie]; } elseif ($PHORUM['use_cookies'] < PHORUM_REQUIRE_COOKIES && isset($_GET[$cookie])) { $value = $_GET[$cookie]; } else { continue; } // Cookie incorrectly formatted. Continue with the next one. if (strstr($value, ':') === FALSE) { continue; } // The cookie value is formatted as <user id>:<session id>. // Split these into separate parts. list($user_id, $sessid) = explode(':', $value, 2); // The user_id should be numerical at all times. if (!is_numeric($user_id)) { continue; } // Find the data for the session user by its user_id. If the user // cannot be found, then the session is destroyed and the // anonymous user is setup. if ($session_user === NULL) { $session_user = phorum_api_user_get($user_id, TRUE); if (empty($session_user) || $session_user['active'] != PHORUM_USER_ACTIVE) { phorum_api_user_session_destroy($type); return FALSE; } } else { // The user_id should be the same for all cookies. // If a different user_id is found, then the cookie // that we're currently looking at is ignored. It could // be an old cookie for a different user. if ($session_user['user_id'] != $user_id) { continue; } } // Check if the session id from the cookie is valid for the user. $valid_session = $user_id_from_hook_session || $cookie == PHORUM_SESSION_LONG_TERM && !empty($session_user['sessid_lt']) && $session_user['sessid_lt'] == $sessid || $cookie == PHORUM_SESSION_SHORT_TERM && !empty($session_user['sessid_st']) && $session_user['sessid_st'] == $sessid || $cookie == PHORUM_SESSION_ADMIN && !empty($session_user['sessid_lt']) && md5($session_user['sessid_lt'] . $PHORUM['admin_session_salt']) == $sessid; // Keep track of valid session cookies. if ($valid_session) { $check_session[$cookie] = 2; } } // No real cookie found for a long term session? Then we will ignore // short term sessions (short term sessions are not implemented for URI // authentication) and update the "use_cookies" setting accordingly. if ($check_session[PHORUM_SESSION_LONG_TERM] == 2 && !$real_cookie) { $check_session[PHORUM_SESSION_SHORT_TERM] = 0; $GLOBALS['PHORUM']['use_cookies'] = PHORUM_NO_COOKIES; } // ---------------------------------------------------------------------- // Check if a user session needs to be restored. // ---------------------------------------------------------------------- $do_restore_session = FALSE; $do_restore_short_term_session = FALSE; if ($type == PHORUM_FORUM_SESSION) { // Valid long term forum session found. if ($check_session[PHORUM_SESSION_LONG_TERM] == 2) { $do_restore_session = TRUE; if ($check_session[PHORUM_SESSION_SHORT_TERM] == 1) { // Checked short term session, but no valid session found. $do_restore_short_term_session = FALSE; } else { // Short term session not checked (0) or valid (2). $do_restore_short_term_session = TRUE; } } } elseif ($type == PHORUM_ADMIN_SESSION) { // Valid admin session found. Note that the function // phorum_api_user_set_active_user() might still reject the user // if it's not an admin user (anymore). if ($check_session[PHORUM_SESSION_ADMIN] == 2) { $do_restore_session = TRUE; } } // ---------------------------------------------------------------------- // Restore the user session. // ---------------------------------------------------------------------- // No session to restore? Then destroy the session // and setup the anonymous user. if (!$do_restore_session) { phorum_api_user_session_destroy($type); return FALSE; } else { // Setup the Phorum user. $flags = 0; if ($do_restore_short_term_session) { $flags |= PHORUM_FLAG_SESSION_ST; } phorum_api_user_set_active_user($type, $session_user, $flags); // Refresh and keep the session alive for the user. phorum_api_user_session_create($type); return TRUE; } }
} else { // See if the temporary cookie was found. If yes, then the // browser does support cookies. If not, then we disable // the use of cookies. if (!isset($_COOKIE['phorum_tmp_cookie'])) { $PHORUM['use_cookies'] = PHORUM_NO_COOKIES; } // Check if the login credentials are right. $user_id = phorum_api_user_authenticate(PHORUM_FORUM_SESSION, $_POST['username'], $_POST['password']); // They are. Setup the active user and start a Phorum session. if ($user_id) { // Make the authenticated user the active Phorum user // and start a Phorum user session. Because this is a fresh // login, we can enable the short term session and we request // refreshing of the session id(s). if (phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, $user_id, PHORUM_FLAG_SESSION_ST) && phorum_api_user_session_create(PHORUM_FORUM_SESSION, PHORUM_SESSID_RESET_LOGIN)) { // Destroy the temporary cookie that is used for testing // for cookie compatibility. if (isset($_COOKIE['phorum_tmp_cookie'])) { setcookie('phorum_tmp_cookie', '', 0, $PHORUM['session_path'], $PHORUM['session_domain']); } // Determine the URL to redirect the user to. // If redir is a number, it is a URL constant. $php = PHORUM_FILE_EXTENSION; if (is_numeric($_POST['redir'])) { $redir = phorum_api_url((int) $_POST['redir']); } elseif (!empty($PHORUM['use_cookies']) && !strstr($_POST['redir'], "register.{$php}") && !strstr($_POST['redir'], "login.{$php}")) { $redir = $_POST['redir']; } else { $redir = phorum_api_url(PHORUM_LIST_URL); }
/** * A common function which is used to save the userdata from the post-data. * @param panel - The panel for which to save data. * @return array - An array containing $error and $okmsg. */ function phorum_controlcenter_user_save($panel) { $PHORUM = $GLOBALS['PHORUM']; $error = ""; $okmsg = ""; // Setup the default userdata fields that can be changed // from the control panel interface. $userdata = array('signature' => NULL, 'hide_email' => NULL, 'hide_activity' => NULL, 'password' => NULL, 'password_temp' => NULL, 'tz_offset' => NULL, 'is_dst' => NULL, 'user_language' => NULL, 'threaded_list' => NULL, 'threaded_read' => NULL, 'email_notify' => NULL, 'show_signature' => NULL, 'pm_email_notify' => NULL, 'email' => NULL, 'email_temp' => NULL, 'user_template' => NULL, 'moderation_email' => NULL, 'real_name' => NULL); // Add custom profile fields as acceptable fields. foreach ($PHORUM["PROFILE_FIELDS"] as $id => $field) { if ($id === "num_fields" || !empty($field['deleted'])) { continue; } $userdata[$field["name"]] = NULL; } // Update userdata with $_POST information. foreach ($_POST as $key => $val) { if (array_key_exists($key, $userdata)) { $userdata[$key] = $val; } } // Remove unused profile fields. foreach ($userdata as $key => $val) { if (is_null($val)) { unset($userdata[$key]); } } // Set static userdata. $userdata["user_id"] = $PHORUM["user"]["user_id"]; /** * [hook] * cc_save_user * * [description] * This hook works the same way as the <hook>before_register</hook> * hook, so you can also use it for changing and checking the user data * that will be saved in the database. There's one difference. If you * want to check a custom field, you'll also need to check the panel * which you are on, because this hook is called from multiple panels. * The panel that you are on will be stored in the * <literal>panel</literal> field of the user data.<sbr/> * <sbr/> * The example hook belows demonstrates code which could be used if you * have added a custom field to the template for the option * <literal>Edit My Profile</literal> in the control panel. * * [category] * Control center * * [when] * In <filename>control.php</filename>, right before data for a user is * saved in the control panel. * * [input] * An array containing the user data to save. * <ul> * <li>error: * modules can fill this field with an error message to show.</li> * </ul> * * [output] * The same array as the one that was used for the hook call * argument, possibly with the "error" field updated in it. * * [example] * <hookcode> * function phorum_mod_foo_cc_save_user ($data) * { * // Only check data for the panel "user". * if ($data['panel'] != "user") return $data; * * $myfield = trim($data['your_custom_field']); * if (empty($myfield)) { * $data['error'] = 'You need to fill in my custom field'; * } * * return $data; * } * </hookcode> */ if (isset($PHORUM["hooks"]["cc_save_user"])) { $userdata = phorum_hook("cc_save_user", $userdata); } // Set $error, in case the cc_save_user hook did set an error. if (isset($userdata['error'])) { $error = $userdata['error']; unset($userdata['error']); // Try to update the userdata in the database. } elseif (!phorum_api_user_save($userdata)) { // Updating the user failed. $error = $PHORUM["DATA"]["LANG"]["ErrUserAddUpdate"]; } else { // Updating the user was successful. $okmsg = $PHORUM["DATA"]["LANG"]["ProfileUpdatedOk"]; // Let the userdata be reloaded. phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, $userdata["user_id"]); // If a new password was set, then reset all session id(s), so // other computers or browser will lose any active session that // they are running. if (isset($userdata["password"]) && $userdata["password"] != '') { phorum_api_user_session_create(PHORUM_FORUM_SESSION, PHORUM_SESSID_RESET_ALL); } // Copy data from the updated user back into the user template data. $formatted = phorum_api_user_format(array($GLOBALS['PHORUM']['user'])); foreach ($formatted[0] as $key => $val) { $GLOBALS['PHORUM']['DATA']['USER'][$key] = $val; } // Copy data from the updated user back into the template data. // Leave PANEL and forum_id alone (these are injected into the // userdata in the template from this script). foreach ($GLOBALS["PHORUM"]["DATA"]["PROFILE"] as $key => $val) { if ($key == "PANEL" || $key == "forum_id") { continue; } if (isset($GLOBALS["PHORUM"]["user"][$key])) { $GLOBALS["PHORUM"]["DATA"]["PROFILE"][$key] = $GLOBALS["PHORUM"]["user"][$key]; } else { $GLOBALS["PHORUM"]["DATA"]["PROFILE"][$key] = ""; } } } return array($error, $okmsg); }
function testUserApiSetActiveUser() { $user_id = phorum_api_user_search('username', 'testuser' . $this->sharedFixture, '='); $ret = phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, $user_id); $this->assertTrue($ret, 'Setting given user_id active again.'); $ret = phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, array('foo' => 'bar')); $this->assertFalse($ret, 'set_active_user with invalid array given.'); $ret = phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, array('foo')); $this->assertFalse($ret, 'set_active_user with invalid user-input.'); // set active user $GLOBALS['PHORUM']['user'] = phorum_api_user_get($user_id); // create session $ret = phorum_api_user_session_create(PHORUM_FORUM_SESSION); $this->assertTrue($ret, 'Creating user-session'); }
// but WITHOUT ANY WARRANTY, without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // // // // You should have received a copy of the Phorum License // // along with this program. // // // //////////////////////////////////////////////////////////////////////////////// // don't allow this page to be loaded directly if (!defined("PHORUM_ADMIN")) { exit; } require_once PHORUM_PATH . '/include/api/user.php'; require_once PHORUM_PATH . '/include/api/sign.php'; if (isset($_POST["username"]) && isset($_POST["password"])) { $user_id = phorum_api_user_authenticate(PHORUM_ADMIN_SESSION, trim($_POST["username"]), trim($_POST["password"])); if ($user_id && phorum_api_user_set_active_user(PHORUM_ADMIN_SESSION, $user_id) && phorum_api_user_session_create(PHORUM_ADMIN_SESSION)) { // update the token and time $GLOBALS["PHORUM"]["user"]['settings_data']['admin_token_time'] = time(); $sig_data = $GLOBALS["PHORUM"]["user"]['user_id'] . time() . $GLOBALS["PHORUM"]["user"]['username']; $GLOBALS["PHORUM"]["user"]['settings_data']['admin_token'] = phorum_api_sign($sig_data); $GLOBALS["PHORUM"]['admin_token'] = $GLOBALS["PHORUM"]["user"]['settings_data']['admin_token']; $tmp_user = array('user_id' => $GLOBALS["PHORUM"]["user"]['user_id'], 'settings_data' => $GLOBALS["PHORUM"]["user"]['settings_data']); phorum_api_user_save($tmp_user); if (!empty($_POST["target"])) { $target_url = phorum_admin_build_url($_POST['target'], TRUE); phorum_api_redirect($target_url); } else { $redir_url = phorum_admin_build_url(NULL, TRUE); phorum_api_redirect($redir_url); } exit;
/** * A common function which is used to save the userdata from the post-data. * @param panel - The panel for which to save data. * @return array - An array containing $error and $okmsg. */ function phorum_controlcenter_user_save($panel) { global $PHORUM; $error = ""; $okmsg = ""; // Setup the default userdata fields that can be changed // from the control panel interface. $userdata = array('signature' => NULL, 'hide_email' => NULL, 'hide_activity' => NULL, 'tz_offset' => NULL, 'is_dst' => NULL, 'user_language' => NULL, 'threaded_list' => NULL, 'threaded_read' => NULL, 'email_notify' => NULL, 'show_signature' => NULL, 'pm_email_notify' => NULL, 'user_template' => NULL, 'moderation_email' => NULL, 'real_name' => NULL); // Password related fields can only be updated from the password panel. if ($panel == 'password') { $userdata['password'] = NULL; $userdata['password_temp'] = NULL; } // E-mail address related fields can only be updated from the email panel. if ($panel == 'email') { $userdata['email'] = NULL; $userdata['email_temp'] = NULL; } // E-mail address related fields can only be updated from the email panel. if ($panel == 'email') { $userdata['email'] = NULL; $userdata['email_temp'] = NULL; } // Add custom profile fields as acceptable fields. foreach ($PHORUM["CUSTOM_FIELDS"][PHORUM_CUSTOM_FIELD_USER] as $id => $field) { if ($id === "num_fields" || !empty($field['deleted'])) { continue; } $userdata[$field["name"]] = NULL; } // Update userdata with $_POST information. foreach ($_POST as $key => $val) { if (array_key_exists($key, $userdata)) { $userdata[$key] = $val; } } // Remove unused profile fields. foreach ($userdata as $key => $val) { if (is_null($val)) { unset($userdata[$key]); } } // Set static userdata. $userdata["user_id"] = $PHORUM["user"]["user_id"]; // Run a hook, so module writers can update and check the userdata. if (isset($PHORUM["hooks"]["cc_save_user"])) { $userdata = phorum_api_hook("cc_save_user", $userdata); } // Set $error, in case the cc_save_user hook did set an error. if (isset($userdata['error'])) { $error = $userdata['error']; unset($userdata['error']); // Try to update the userdata in the database. } elseif (!phorum_api_user_save($userdata)) { // Updating the user failed. $error = $PHORUM["DATA"]["LANG"]["ErrUserAddUpdate"]; } else { // Updating the user was successful. $okmsg = $PHORUM["DATA"]["LANG"]["ProfileUpdatedOk"]; // Let the userdata be reloaded. phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, $userdata["user_id"]); // If a new password was set, then reset all session id(s), so // other computers or browser will lose any active session that // they are running. if (isset($userdata["password"]) && $userdata["password"] != '') { phorum_api_user_session_create(PHORUM_FORUM_SESSION, PHORUM_SESSID_RESET_ALL); } // Copy data from the updated user back into the user template data. $formatted = phorum_api_format_users(array($PHORUM['user'])); foreach ($formatted[0] as $key => $val) { $PHORUM['DATA']['USER'][$key] = $val; } // Copy data from the updated user back into the template data. // Leave PANEL and forum_id alone (these are injected into the // userdata in the template from this script). foreach ($PHORUM["DATA"]["PROFILE"] as $key => $val) { if ($key == "PANEL" || $key == "forum_id") { continue; } if (isset($PHORUM["user"][$key])) { if (is_array($val)) { // array-data would be (most often) broken when html encoded $PHORUM["DATA"]["PROFILE"][$key] = $PHORUM["user"][$key]; } elseif (substr($key, 0, 9) == 'signature') { // the signature needs special care - e.g. for the formatted sig // Fake a message here so we can run the sig through format_message. $fake_messages = array(array("author" => "", "email" => "", "subject" => "", "body" => $PHORUM["user"]["signature"])); $fake_messages = phorum_format_messages($fake_messages); $PHORUM["DATA"]["PROFILE"]["signature_formatted"] = $fake_messages[0]["body"]; // Format the user signature using standard message body formatting // or HTML escape it $PHORUM["DATA"]["PROFILE"]["signature"] = htmlspecialchars($PHORUM["user"]["signature"], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); } else { // same handling as when loading the page for the first time $PHORUM["DATA"]["PROFILE"][$key] = htmlspecialchars($PHORUM["user"][$key], ENT_COMPAT, $PHORUM['DATA']['HCHARSET']); } } else { $PHORUM["DATA"]["PROFILE"][$key] = ""; } } } return array($error, $okmsg); }
<?php # Handle a user forum login if (!defined('PHORUM')) { return; } require_once "./include/api/base.php"; require_once "./include/api/user.php"; // Check the username and password. $user_id = phorum_api_user_authenticate(PHORUM_FORUM_SESSION, "username", "password"); if (!$user_id) { die("Username or password incorrect!\n"); } // Make the authenticated user the active user for Phorum. This is all // that is needed to tell Phorum that this user is logged in. $set_active = phorum_api_user_set_active_user(PHORUM_FORUM_SESSION, $user_id, PHORUM_FLAG_SESSION_ST); if (!$set_active) { die("Setting user_id {$user_id} as the active user failed!\n"); } // Create a session for the active user, so the user will be remembered // on subsequent requests. phorum_api_user_session_create(PHORUM_FORUM_SESSION, PHORUM_SESSID_RESET_LOGIN); // appropriate at login time