public function login($loginoremail, $password) { if (isset($_COOKIE[$this->cookie_name])) { $this->logout(); } $user = new User($this->db); $user->loadByLoginOrEmail($loginoremail); if (isset($user) && $user->is_loaded) { if ($user->val('user_failed_attempts') > $this::$max_attempts) { $messages[] = t('Max. number of login attempts exceeded. Please ask for new password.'); } if (Authentication::verifyPassword($password, $user->val('user_password_hash'))) { // success - create new session $this->user = $user; $this->updateLastAccess(); $token = $this->generateToken(); $token_hash = Authentication::hashPassword($token); $expires = time() + Authentication::$session_expire; $session = new UserSession($this->db); $session->data['user_session_token_hash'] = $token_hash; $session->data['user_session_user_id'] = $this->user->val('user_id'); $session->data['user_session_expires'] = SqlQuery::mysqlTimestamp($expires); $session->save(); setcookie($this->cookie_name, $session->val('user_session_id') . "-" . $token, $expires, '/', false, false); $this->session = $session; } else { $user->data['user_failed_attempts'] += 1; $user->save(); } } }
public static function install($data, &$fail, &$errno, &$error) { if (!$fail) { $auth = new Authentication(); $salt = $auth->generateSalt(); $passwordHash = $auth->hashPassword($data['DB']['db_passwd_insert'], $salt); $sql = "INSERT INTO `User` (`U_id`, `U_username`, `U_email`, `U_lastName`, `U_firstName`, `U_title`, `U_password`, `U_flag`, `U_salt`, `U_failed_logins`, `U_externalId`, `U_studentNumber`, `U_isSuperAdmin`, `U_comment`) VALUES (NULL, '{$data['DB']['db_user_insert']}', '{$data['DB']['db_email_insert']}', '{$data['DB']['db_last_name_insert']}', '{$data['DB']['db_first_name_insert']}', NULL, '{$passwordHash}', 1, '{$salt}', 0, NULL, NULL, 1, NULL);"; $result = DBRequest::request($sql, false, $data); if ($result["errno"] !== 0) { $fail = true; $errno = $result["errno"]; $error = isset($result["error"]) ? $result["error"] : ''; } } return null; }
/** * Processes a request to update a user's account information. * * Processes the request from the user account settings form, checking that: * 1. The user correctly input their current password; * 2. They have the necessary permissions to update the posted field(s); * 3. The submitted data is valid. * This route requires authentication. * Request type: POST */ public function accountSettings() { // Load the request schema $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/account-settings.json"); // Get the alert message stream $ms = $this->_app->alerts; // Access control for entire page if (!$this->_app->user->checkAccess('uri_account_settings')) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } $data = $this->_app->request->post(); // Remove csrf_token unset($data['csrf_token']); // Check current password if (!isset($data['passwordcheck']) || !$this->_app->user->verifyPassword($data['passwordcheck'])) { $ms->addMessageTranslated("danger", "ACCOUNT_PASSWORD_INVALID"); $this->_app->halt(403); } // Validate new email, if specified if (isset($data['email']) && $data['email'] != $this->_app->user->email) { // Check authorization if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $this->_app->user, 'property' => 'email'])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } // Check if address is in use if (User::where('email', $data['email'])->first()) { $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $data); $this->_app->halt(400); } } else { $data['email'] = $this->_app->user->email; } // Validate locale, if specified if (isset($data['locale']) && $data['locale'] != $this->_app->user->locale) { // Check authorization if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $this->_app->user, 'property' => 'locale'])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } // Validate locale if (!in_array($data['locale'], $this->_app->site->getLocales())) { $ms->addMessageTranslated("danger", "ACCOUNT_SPECIFY_LOCALE"); $this->_app->halt(400); } } else { $data['locale'] = $this->_app->user->locale; } // Validate display_name, if specified if (isset($data['display_name']) && $data['display_name'] != $this->_app->user->display_name) { // Check authorization if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $this->_app->user, 'property' => 'display_name'])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } } else { $data['display_name'] = $this->_app->user->display_name; } // Validate password, if specified and not empty if (isset($data['password']) && !empty($data['password'])) { // Check authorization if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $this->_app->user, 'property' => 'password'])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } } else { // Do not pass to model if no password is specified unset($data['password']); unset($data['passwordc']); } // Set up Fortress to validate the request $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $data); // Validate if (!$rf->validate()) { $this->_app->halt(400); } // If a new password was specified, hash it. if (isset($data['password'])) { $data['password'] = Authentication::hashPassword($data['password']); } // Remove passwordc, passwordcheck unset($data['passwordc']); unset($data['passwordcheck']); // Looks good, let's update with new values! foreach ($data as $name => $value) { $this->_app->user->{$name} = $value; } $this->_app->user->store(); $ms->addMessageTranslated("success", "ACCOUNT_SETTINGS_UPDATED"); }
/** * Processes the request to update an existing user's details, including enabled/disabled status and activation status. * * Processes the request from the user update form, checking that: * 1. The target user's new email address, if specified, is not already in use; * 2. The logged-in user has the necessary permissions to update the posted field(s); * 3. We're not trying to disable the master account; * 4. The submitted data is valid. * This route requires authentication. * Request type: POST * @param int $user_id the id of the user to edit. * @see formUserEdit */ public function updateUser($user_id) { $post = $this->_app->request->post(); // Load the request schema $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/user-update.json"); // Get the alert message stream $ms = $this->_app->alerts; // Get the target user $target_user = User::find($user_id); // Get the target user's groups $groups = $target_user->getGroups(); /* // Access control for entire page if (!$this->_app->user->checkAccess('uri_update_user')){ $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } */ // Only the master account can edit the master account! if ($target_user->id == $this->_app->config('user_id_master') && $this->_app->user->id != $this->_app->config('user_id_master')) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } // Remove csrf_token unset($post['csrf_token']); // Set up Fortress to process the request $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post); if (isset($post['passwordc'])) { unset($post['passwordc']); } // Check authorization for submitted fields, if the value has been changed foreach ($post as $name => $value) { if ($name == "groups" || isset($target_user->{$name}) && $post[$name] != $target_user->{$name}) { // Check authorization if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $target_user, 'property' => $name])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } } else { if (!isset($target_user->{$name})) { $ms->addMessageTranslated("danger", "NO_DATA"); $this->_app->halt(400); } } } // Check that we are not disabling the master account if ($target_user->id == $this->_app->config('user_id_master') && isset($post['flag_enabled']) && $post['flag_enabled'] == "0") { $ms->addMessageTranslated("danger", "ACCOUNT_DISABLE_MASTER"); $this->_app->halt(403); } // Check that the email address is not in use if (isset($post['email']) && $post['email'] != $target_user->email && UserLoader::exists($post['email'], 'email')) { $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $post); $this->_app->halt(400); } // Sanitize $rf->sanitize(); // Validate, and halt on validation errors. if (!$rf->validate()) { $this->_app->halt(400); } // Remove passwordc $rf->removeFields(['passwordc']); // Get the filtered data $data = $rf->data(); // Update user groups if (isset($data['groups'])) { foreach ($data['groups'] as $group_id => $is_member) { if ($is_member == "1" && !isset($groups[$group_id])) { $target_user->addGroup($group_id); } else { if ($is_member == "0" && isset($groups[$group_id])) { $target_user->removeGroup($group_id); } } } unset($data['groups']); } // Hash password if (isset($data['password'])) { $data['password'] = Authentication::hashPassword($data['password']); } // Update the user and generate success messages foreach ($data as $name => $value) { if ($value != $target_user->{$name}) { $target_user->{$name} = $value; // Custom success messages (optional) if ($name == "flag_enabled") { if ($value == "1") { $ms->addMessageTranslated("success", "ACCOUNT_ENABLE_SUCCESSFUL", ["user_name" => $target_user->user_name]); } else { $ms->addMessageTranslated("success", "ACCOUNT_DISABLE_SUCCESSFUL", ["user_name" => $target_user->user_name]); } } if ($name == "flag_verified") { $ms->addMessageTranslated("success", "ACCOUNT_MANUALLY_ACTIVATED", ["user_name" => $target_user->user_name]); } } } // If we're generating a password reset, create the corresponding event and shoot off an email if (isset($data['flag_password_reset']) && $data['flag_password_reset'] == "1") { // Recheck auth if (!$this->_app->user->checkAccess('update_account_setting', ['user' => $target_user, 'property' => 'flag_password_reset'])) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } // New password reset event - bypass any rate limiting $target_user->newEventPasswordReset(); $target_user->save(); // Email the user asking to confirm this change password request $twig = $this->_app->view()->getEnvironment(); $template = $twig->loadTemplate("mail/password-reset.twig"); $notification = new Notification($template); $notification->fromWebsite(); // Automatically sets sender and reply-to $notification->addEmailRecipient($target_user->email, $target_user->display_name, ["user" => $target_user, "request_date" => date("Y-m-d H:i:s")]); try { $notification->send(); } catch (\Exception\phpmailerException $e) { $ms->addMessageTranslated("danger", "MAIL_ERROR"); error_log('Mailer Error: ' . $e->errorMessage()); $this->_app->halt(500); } $ms->addMessageTranslated("success", "FORGOTPASS_REQUEST_SENT", ["user_name" => $target_user->user_name]); } $ms->addMessageTranslated("success", "ACCOUNT_DETAILS_UPDATED", ["user_name" => $target_user->user_name]); $target_user->save(); }
<?php include_once $home_dir . 'classes/emails.php'; $page_title = t('Reset Password'); $data['show_form'] = false; if (isset($path[2]) && isset($_GET['reset_token'])) { $user_id = intval($path[2]); $reset_token = $_GET['reset_token']; $zUser = new User($db, $user_id); if ($zUser->is_loaded && $zUser->val('user_reset_password_expires') > ModelBase::mysqlTimestamp(time()) && password_verify($reset_token, $zUser->val('user_reset_password_hash'))) { if (isset($_POST['password']) && isset($_POST['password2'])) { if ($_POST['password'] == $_POST['password2']) { $zUser->data['user_password_hash'] = Authentication::hashPassword($_POST['password']); $zUser->data['user_reset_password_hash'] = null; $zUser->data['user_reset_password_expires'] = null; $zUser->save(); $messages->add(t('Your password was reset.'), 'success'); } else { $messages->error(t('Passwords don\'t match.')); } } else { $data['show_form'] = true; $data['user_id'] = $zUser->val('user_id'); $data['reset_token'] = $reset_token; $messages->add(t('Enter your new password.')); } } else { $messages->error(t('Your link seems to be invalid.')); } } else { $messages->error(t('This page should only be accessed from link sent to your e-mail.'));
/** * Processes the request to create a new user (from the admin controls). * * Processes the request from the user creation form, checking that: * 1. The username and email are not already in use; * 2. The logged-in user has the necessary permissions to update the posted field(s); * 3. The submitted data is valid. * This route requires authentication. * Request type: POST * @see formUserCreate */ public function createUser() { $post = $this->_app->request->post(); // Load the request schema $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/user-create.json"); // Get the alert message stream $ms = $this->_app->alerts; // Access-controlled resource if (!$this->_app->user->checkAccess('create_account')) { $ms->addMessageTranslated("danger", "ACCESS_DENIED"); $this->_app->halt(403); } // Set up Fortress to process the request $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post); // Sanitize data $rf->sanitize(); // Validate, and halt on validation errors. $error = !$rf->validate(true); // Get the filtered data $data = $rf->data(); // Remove csrf_token, password confirmation from object data $rf->removeFields(['csrf_token, passwordc']); // Perform desired data transformations on required fields. Is this a feature we could add to Fortress? $data['user_name'] = strtolower(trim($data['user_name'])); $data['display_name'] = trim($data['display_name']); $data['email'] = strtolower(trim($data['email'])); $data['active'] = 1; // Check if username or email already exists if (UserLoader::exists($data['user_name'], 'user_name')) { $ms->addMessageTranslated("danger", "ACCOUNT_USERNAME_IN_USE", $data); $error = true; } if (UserLoader::exists($data['email'], 'email')) { $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $data); $error = true; } // Halt on any validation errors if ($error) { $this->_app->halt(400); } // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY) $primaryGroup = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, "is_default"); // Set default values if not specified or not authorized if (!isset($data['locale']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "locale"])) { $data['locale'] = $this->_app->site->default_locale; } if (!isset($data['title']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "title"])) { // Set default title for new users $data['title'] = $primaryGroup->new_user_title; } if (!isset($data['primary_group_id']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "primary_group_id"])) { $data['primary_group_id'] = $primaryGroup->id; } // Set groups to default groups if not specified or not authorized to set groups if (!isset($data['groups']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "groups"])) { $default_groups = GroupLoader::fetchAll(GROUP_DEFAULT, "is_default"); $data['groups'] = []; foreach ($default_groups as $group_id => $group) { $data['groups'][$group_id] = "1"; } } // Hash password $data['password'] = Authentication::hashPassword($data['password']); // Create the user $user = new User($data); // Add user to groups, including selected primary group $user->addGroup($data['primary_group_id']); foreach ($data['groups'] as $group_id => $is_member) { if ($is_member == "1") { $user->addGroup($group_id); } } // Store new user to database $user->store(); // Success message $ms->addMessageTranslated("success", "ACCOUNT_CREATION_COMPLETE", $data); }
/** * Processes a request to create the master account. * * Processes the request from the master account creation form, checking that: * 1. The honeypot has not been changed; * 2. The master account does not already exist; * 3. The correct configuration token was submitted; * 3. The submitted data is valid. * This route is "public access" (until the master account has been created, that is) * Request type: POST */ public function setupMasterAccount() { $post = $this->_app->request->post(); // Get the alert message stream $ms = $this->_app->alerts; // Check the honeypot. 'spiderbro' is not a real field, it is hidden on the main page and must be submitted with its default value for this to be processed. if (!$post['spiderbro'] || $post['spiderbro'] != "http://") { error_log("Possible spam received:" . print_r($this->_app->request->post(), true)); $ms->addMessage("danger", "Aww hellllls no!"); $this->_app->halt(500); // Don't let on about why the request failed ;-) } // Do not allow registering a master account if one has already been created if (User::find($this->_app->config('user_id_master'))) { $ms->addMessageTranslated("danger", "MASTER_ACCOUNT_EXISTS"); $this->_app->halt(403); } // Check the configuration token if ($post['root_account_config_token'] != $this->_app->site->root_account_config_token) { $ms->addMessageTranslated("danger", "CONFIG_TOKEN_MISMATCH"); $this->_app->halt(403); } // Load the request schema $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/register.json"); // Set up Fortress to process the request $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post); // Sanitize data $rf->sanitize(); // Validate, and halt on validation errors. $error = !$rf->validate(true); // Get the filtered data $data = $rf->data(); // Remove configuration token, password confirmation from object data $rf->removeFields(['root_account_config_token', 'passwordc']); // Perform desired data transformations. Is this a feature we could add to Fortress? $data['display_name'] = trim($data['display_name']); $data['flag_verified'] = 1; $data['locale'] = $this->_app->site->default_locale; // Halt on any validation errors if ($error) { $this->_app->halt(400); } // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY) $primaryGroup = Group::where('is_default', GROUP_DEFAULT_PRIMARY)->first(); $data['primary_group_id'] = $primaryGroup->id; // Set default title for new users $data['title'] = $primaryGroup->new_user_title; // Hash password $data['password'] = Authentication::hashPassword($data['password']); // Create the master user $user = new User($data); $user->id = $this->_app->config('user_id_master'); // Add user to default groups, including default primary group $defaultGroups = Group::where('is_default', GROUP_DEFAULT)->get(); $user->addGroup($primaryGroup->id); foreach ($defaultGroups as $group) { $group_id = $group->id; $user->addGroup($group_id); } // Add sign-up event $user->newEventSignUp(); // Store new user to database $user->save(); // No activation required $ms->addMessageTranslated("success", "ACCOUNT_REGISTRATION_COMPLETE_TYPE1"); // Update install status $this->_app->site->install_status = "new"; $this->_app->site->root_account_config_token = ""; $this->_app->site->store(); }
if (strlen($_POST["user_search"]) <= 0 || substr($_POST["user_search"], 0, 10) == "Search for") { exit("Please specify a user name."); } elseif (strlen($_POST["new1"]) < 6) { exit("Password too short."); } elseif ($_POST["new1"] != $_POST["new2"]) { exit("Passwords did not match."); } else { // echo '<p>Form processing in progress...</p>'; $user = $_POST["user_search"]; // echo '<p>USER='******'<p>NEW1=' . $_POST["new1"] . "</p>"; // echo '<p>NEW2=' . $_POST["new2"] . "</p>"; $isTableBasedUser = Authentication::isTableUser($user); $old_salt = Authentication::getUserPasswordSalt($user); $new_salt = Authentication::generatePasswordSalt(); $new_hashed_password = Authentication::hashPassword($_POST["new1"], $new_salt); if (strlen($old_salt) < 4) { exit("Username is invalid or does not exist."); } elseif (!$isTableBasedUser) { exit("User is not table-based."); } elseif (strlen($new_hashed_password) < 8) { exit("Hmmm, could not create a new hashed password."); } else { // echo '<p>ISTU=' . $isTableBasedUser . "</p>"; // echo '<p>OSLT=' . $old_salt . "</p>"; // echo '<p>SALT=' . $new_salt . "</p>"; // echo '<p>HASH=' . $new_hashed_password . "</p>"; $setpwResult = Authentication::setUserPasswordAndSalt($user, $new_hashed_password, $new_salt); // echo '<p>RESULT=' . $setpwResult . "</p>"; if ($setpwResult > 0) { echo '<p><span style="color: green;">Successfully</span> set the password for user <tt>' . $user . '</tt>';
<?php include_once $home_dir . 'classes/emails.php'; $page_title = t('Forgotten Password'); if (isset($_POST['email'])) { $zUser = new User($db); $zUser->loadByLoginOrEmail($_POST['email']); if ($zUser->is_loaded) { $reset_token = generateToken(50); $expires = time() + 60 * 60 * 24 * User::$reset_password_expires_days; $zUser->data['user_reset_password_hash'] = Authentication::hashPassword($reset_token); $zUser->data['user_reset_password_expires'] = ModelBase::mysqlTimestamp($expires); $zUser->save(); $email_text = t('To reset your password, visit this link: %s/admin/reset-password/%d?reset_token=%s. This link is only valid for %d days.', $base_url, $zUser->val('user_id'), $reset_token, User::$reset_password_expires_days); Emails::sendPlain($globals['emails_from'], $zUser->val('user_email'), '', t('Forgotten Password'), $email_text); $messages->add(t('An e-mail was sent to your address with reset password instructions.')); } else { // increase ip address failed attempts here // * $messages->error(t('This e-mail address or login was not found in our database.')); } }