function SSO_LoadDecryptedUserInfo($row) { $result = @unserialize($row->info); $info = SSO_DecryptDBData($row->info2); if ($info !== false) { $result = array_merge($result, $info); } return $result; }
public function ProcessFrontend() { global $g_sso_login_modules, $sso_settings, $sso_rng, $sso_header, $sso_footer, $sso_target_url, $sso_db, $sso_ipaddr_info, $sso_session_info, $sso_providers; if (!isset($sso_ipaddr_info["sso_login_modules"])) { $sso_ipaddr_info["sso_login_modules"] = array(); } // Initialize active modules. $this->activemodules = array(); foreach ($g_sso_login_modules as $key => $info) { if ($sso_settings["sso_login"]["modules"][$key]["_a"]) { $module = "sso_login_module_" . $key; $this->activemodules[$key] = new $module(); } } $sso_db_sso_login_users = SSO_DB_PREFIX . "p_sso_login_users"; if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "module" && isset($_REQUEST["sso_login_module"]) && isset($this->activemodules[$_REQUEST["sso_login_module"]])) { $this->activemodules[$_REQUEST["sso_login_module"]]->CustomFrontend(); } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "verify" && $sso_settings["sso_login"]["open_reg"]) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->VerifyCheck($messages); } if (!count($messages["errors"])) { if (!isset($_REQUEST["sso_v"]) || !isset($sso_session_info["sso_login_verify"])) { $messages["errors"][] = BB_Translate("Invalid URL. Verification missing."); } else { if (trim($_REQUEST["sso_v"]) !== $sso_session_info["sso_login_verify"]["v"]) { $messages["errors"][] = BB_Translate("Invalid verification string specified."); } else { try { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("verified" => 1), "WHERE" => "id = ?"), $sso_session_info["sso_login_verify"]["id"]); } catch (Exception $e) { $messages["errors"][] = BB_Translate("Verification failed. Database query error."); } if (!count($messages["errors"])) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_msg=verified"); exit; } } } } echo $sso_header; SSO_OutputHeartbeat(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, false); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> </div> </div> <?php echo $sso_footer; } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "signup_check" && $sso_settings["sso_login"]["open_reg"]) { $result = $this->SignupUpdateCheck(true, false, false, false); foreach ($result["errors"] as $error) { echo "<div class=\"sso_main_formerror\">" . htmlspecialchars($error) . "</div>"; } foreach ($result["warnings"] as $warning) { echo "<div class=\"sso_main_formwarning\">" . htmlspecialchars($warning) . "</div>"; } if (!count($result["errors"]) && !count($result["warnings"])) { if ($result["success"] != "") { echo "<div class=\"sso_main_formokay\">" . htmlspecialchars($result["success"]) . "</div>"; } else { if (isset($result["htmlsuccess"]) && $result["htmlsuccess"] != "") { echo "<div class=\"sso_main_formokay\">" . $result["htmlsuccess"] . "</div>"; } } } } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "signup" && $sso_settings["sso_login"]["open_reg"]) { if (SSO_FrontendFieldValue("submit") === false) { $messages = false; } else { $messages = $this->SignupUpdateCheck(false, false, false, false); if (!count($messages["errors"])) { // Create the account. $username = SSO_FrontendFieldValue("username", ""); $email = SSO_FrontendFieldValue("email", ""); $verified = true; if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { $result = SMTP::MakeValidEmailAddress($email); $email = $result["email"]; $verified = $sso_settings["sso_login"]["email_verify_subject"] == "" || $sso_settings["sso_login"]["email_verify_msg"] == ""; } $salt = $sso_rng->GenerateString(); $data = $username . ":" . $email . ":" . $salt . ":" . SSO_FrontendFieldValue("createpass"); $passwordinfo = self::HashPasswordInfo($data, $sso_settings["sso_login"]["password_mode"], $sso_settings["sso_login"]["password_minrounds"]); if (!$passwordinfo["success"]) { $messages["errors"][] = BB_Translate("Unexpected cryptography error."); } else { $userinfo = array(); $userinfo["extra"] = $sso_rng->GenerateString(); $userinfo["two_factor_key"] = $sso_session_info["sso_login_two_factor_key"]; $userinfo["two_factor_method"] = SSO_FrontendFieldValue("two_factor_method", ""); foreach ($this->activemodules as &$instance) { $instance->SignupAddInfo($userinfo, false); } $userinfo["salt"] = $salt; $userinfo["rounds"] = (int) $passwordinfo["rounds"]; $userinfo["password"] = bin2hex($passwordinfo["hash"]); $userinfo2 = SSO_EncryptDBData($userinfo); try { if ($sso_settings["sso_login"]["install_type"] == "email_username") { $sso_db->Query("INSERT", array($sso_db_sso_login_users, array("username" => $username, "email" => $email, "verified" => (int) $verified, "created" => CSDB::ConvertToDBTime(time()), "info" => $userinfo2), "AUTO INCREMENT" => "id")); } else { if ($sso_settings["sso_login"]["install_type"] == "email") { $sso_db->Query("INSERT", array($sso_db_sso_login_users, array("email" => $email, "verified" => (int) $verified, "created" => CSDB::ConvertToDBTime(time()), "info" => $userinfo2), "AUTO INCREMENT" => "id")); } else { if ($sso_settings["sso_login"]["install_type"] == "username") { $sso_db->Query("INSERT", array($sso_db_sso_login_users, array("username" => $username, "created" => CSDB::ConvertToDBTime(time()), "info" => $userinfo2), "AUTO INCREMENT" => "id")); } else { $messages["errors"][] = BB_Translate("Fatal error: Login system is broken."); } } } // Send verification e-mail. if (!count($messages["errors"])) { $userid = $sso_db->GetInsertID(); } if (!count($messages["errors"]) && !$verified) { $this->SendVerificationEmail($userid, $userinfo, $messages, $username, $email); } } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } if (!count($messages["errors"])) { foreach ($this->activemodules as &$instance) { $instance->SignupDone($userid, false); } header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_msg=" . ($verified ? "verified" : "verify")); exit; } } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS($sso_target_url . "&sso_login_action=signup_check&sso_ajax=1"); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> <div class="sso_main_form_wrap sso_login_signup_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Sign up")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=signup"); ?> " autocomplete="off"> <?php if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Your E-mail Address")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text sso_login_changehook" type="text" name="<?php echo SSO_FrontendField("email"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("email", "")); ?> " /></div> </div> <?php } if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username") { ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Choose Username")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text sso_login_changehook" type="text" name="<?php echo SSO_FrontendField("username"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("username", "")); ?> " /></div> </div> <?php } ?> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Choose Password")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text sso_login_changehook" type="password" name="<?php echo SSO_FrontendField("createpass"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("createpass", "")); ?> " /></div> </div> <?php $outputmap = array(); // Two-factor authentication dropdown. $outputmap2 = array(); $method = SSO_FrontendFieldValue("two_factor_method", ""); foreach ($this->activemodules as $key => &$instance) { $name = $instance->GetTwoFactorName(); if ($name !== false) { $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap2, $order, $key, "<option value=\"" . htmlspecialchars($key) . "\"" . ($method == $key ? " selected" : "") . ">" . htmlspecialchars($name) . "</option>"); } } if (!$sso_settings["sso_login"]["require_two_factor"] && count($outputmap2)) { SSO_AddSortedOutput($outputmap2, 0, "", "<option value=\"\"" . ($method == "" ? " selected" : "") . ">" . htmlspecialchars(BB_Translate("None")) . "</option>"); } if (count($outputmap2)) { if (!isset($sso_session_info["sso_login_two_factor_key"])) { $sso_session_info["sso_login_two_factor_key"] = self::GenerateOTPKey(10); SSO_SaveSessionInfo(); } ob_start(); ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Choose Two-Factor Authentication Method")); ?> </div> <div class="sso_main_formdata"><select class="sso_main_dropdown sso_login_changehook_two_factor" name="<?php echo SSO_FrontendField("two_factor_method"); ?> "> <?php SSO_DisplaySortedOutput($outputmap2); ?> </select></div> <div class="sso_main_formdesc"><?php echo htmlspecialchars(BB_Translate($sso_settings["sso_login"]["require_two_factor"] ? "Required. Two-factor authentication vastly improves the security of your account." : "Optional. Two-factor authentication vastly improves the security of your account.")); ?> </div> </div> <?php $order = $sso_settings["sso_login"]["two_factor_order"]; SSO_AddSortedOutput($outputmap, $order, "two_factor", ob_get_contents()); ob_end_clean(); } // Add active module output. foreach ($this->activemodules as $key => &$instance) { ob_start(); $instance->GenerateSignup(false); $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap, $order, $key, ob_get_contents()); ob_end_clean(); } SSO_DisplaySortedOutput($outputmap); ?> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Sign up")); ?> " /> </div> </form> </div> </div> </div> <?php echo $sso_footer; } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "update_info") { // Check the session and load the user account. $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->UpdateInfoCheck($messages, false, false); } $userrow = false; if (!count($messages["errors"])) { if (!isset($_REQUEST["sso_v"]) || !isset($sso_session_info["sso_login_update"])) { $messages["errors"][] = BB_Translate("Invalid URL. Verification missing."); } else { if (trim($_REQUEST["sso_v"]) !== $sso_session_info["sso_login_update"]["v"]) { $messages["errors"][] = BB_Translate("Invalid verification string specified."); } else { if (!isset($sso_session_info["sso_login_update"]["expires"]) || CSDB::ConvertFromDBTime($sso_session_info["sso_login_update"]["expires"]) < time()) { $messages["errors"][] = BB_Translate("Update information is expired or invalid."); } else { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "id = ?"), $sso_db_sso_login_users, $sso_session_info["sso_login_update"]["id"]); if ($userrow === false) { $messages["errors"][] = BB_Translate("Update information is expired or invalid."); } else { if (!isset($userrow->username)) { $userrow->username = ""; } if (!isset($userrow->email)) { $userrow->email = ""; } if (!isset($userrow->verified)) { $userrow->verified = 1; } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("User check failed. Database query error."); } } } } } if (!count($messages["errors"])) { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { $messages["errors"][] = BB_Translate("Error loading user information."); } } if (isset($_REQUEST["sso_ajax"])) { if (!count($messages["errors"])) { $messages = $this->SignupUpdateCheck(true, $userrow, $userinfo, false); } foreach ($messages["errors"] as $error) { echo "<div class=\"sso_main_formerror\">" . htmlspecialchars($error) . "</div>"; } foreach ($messages["warnings"] as $warning) { echo "<div class=\"sso_main_formwarning\">" . htmlspecialchars($warning) . "</div>"; } if (!count($messages["errors"]) && !count($messages["warnings"])) { if ($messages["success"] != "") { echo "<div class=\"sso_main_formokay\">" . htmlspecialchars($messages["success"]) . "</div>"; } else { if ($messages["htmlsuccess"] != "") { echo "<div class=\"sso_main_formokay\">" . $messages["htmlsuccess"] . "</div>"; } } } } else { if (count($messages["errors"])) { echo $sso_header; SSO_OutputHeartbeat(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, false); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> </div> </div> <?php echo $sso_footer; } else { $messagesheader = false; $messages = false; if (SSO_FrontendFieldValue("submit") === false) { if (isset($_REQUEST["sso_msg"])) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->InitMessages($messages); } } } else { $messages = $this->SignupUpdateCheck(false, $userrow, $userinfo, false); if (!count($messages["errors"])) { // Update the account. if ($sso_settings["sso_login"]["change_username"] && ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username")) { $username = SSO_FrontendFieldValue("update_username", ""); } else { $username = $userrow->username; } if ($sso_settings["sso_login"]["change_email"] && ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email")) { $email = SSO_FrontendFieldValue("update_email", ""); $result = SMTP::MakeValidEmailAddress($email); $email = $result["email"]; $verified = $sso_settings["sso_login"]["email_verify_subject"] == "" || $sso_settings["sso_login"]["email_verify_msg"] == "" || $userrow->email == $email; } else { $email = $userrow->email; $verified = $userrow->verified; } if (SSO_FrontendFieldValue("update_pass", "") != "") { $salt = $sso_rng->GenerateString(); $data = $username . ":" . $email . ":" . $salt . ":" . SSO_FrontendFieldValue("update_pass"); $passwordinfo = self::HashPasswordInfo($data, $sso_settings["sso_login"]["password_mode"], $sso_settings["sso_login"]["password_minrounds"]); if (!$passwordinfo["success"]) { $messages["errors"][] = BB_Translate("Unexpected cryptography error."); } else { $numrounds = (int) $passwordinfo["rounds"]; $password = bin2hex($passwordinfo["hash"]); } } else { if ($username != $userrow->username || $email != $userrow->email) { $messages["errors"][] = BB_Translate("Please enter a new password."); } else { $salt = $userinfo["salt"]; $numrounds = $userinfo["rounds"]; $password = $userinfo["password"]; } } if (SSO_FrontendFieldValue("reset_two_factor_key", "") == "yes") { $sso_session_info["sso_login_two_factor_key"] = self::GenerateOTPKey(10); SSO_SaveSessionInfo(); $messages["errors"][] = BB_Translate("Two-factor authentication security key has been reset."); } if (!count($messages["errors"])) { $userinfo["two_factor_key"] = $sso_session_info["sso_login_two_factor_key"]; $userinfo["two_factor_method"] = SSO_FrontendFieldValue("update_two_factor_method", ""); foreach ($this->activemodules as &$instance) { $instance->UpdateAddInfo($userinfo); } $userinfo["salt"] = $salt; $userinfo["rounds"] = $numrounds; $userinfo["password"] = $password; $userinfo2 = SSO_EncryptDBData($userinfo); try { if ($sso_settings["sso_login"]["install_type"] == "email_username") { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("username" => $username, "email" => $email, "verified" => (int) $verified, "info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } else { if ($sso_settings["sso_login"]["install_type"] == "email") { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("email" => $email, "verified" => (int) $verified, "info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } else { if ($sso_settings["sso_login"]["install_type"] == "username") { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("username" => $username, "info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } else { $messages["errors"][] = BB_Translate("Fatal error: Login system is broken."); } } } // Send verification e-mail. $userid = $userrow->id; if (!count($messages["errors"]) && !$verified) { $this->SendVerificationEmail($userid, $userinfo, $messages, $username, $email); } } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } if (!count($messages["errors"])) { foreach ($this->activemodules as &$instance) { $instance->UpdateInfoDone($userid); } header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_msg=" . ($verified ? "updated" : "verify")); exit; } } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS($sso_target_url . "&sso_login_action=update_info&sso_v=" . urlencode($_REQUEST["sso_v"]) . "&sso_ajax=1"); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> <div class="sso_main_form_wrap sso_login_updateinfo_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Update Information")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=update_info&sso_v=" . urlencode($_REQUEST["sso_v"])); ?> " autocomplete="off"> <?php if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Your E-mail Address")); ?> </div> <div class="sso_main_formdata"><?php if ($sso_settings["sso_login"]["change_email"]) { ?> <input class="sso_main_text sso_login_changehook" type="text" name="<?php echo SSO_FrontendField("update_email"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("update_email", $userrow->email)); ?> " /><?php } else { ?> <input type="hidden" name="<?php echo SSO_FrontendField("update_email"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("update_email", $userrow->email)); ?> " /><div class="sso_main_static"><?php echo htmlspecialchars($userrow->email); ?> </div><?php } ?> </div> </div> <?php } if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username") { ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Your Username")); ?> </div> <div class="sso_main_formdata"><?php if ($sso_settings["sso_login"]["change_username"]) { ?> <input class="sso_main_text sso_login_changehook" type="text" name="<?php echo SSO_FrontendField("update_username"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("update_username", $userrow->username)); ?> " /><?php } else { ?> <input type="hidden" name="<?php echo SSO_FrontendField("update_username"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("update_username", $userrow->username)); ?> " /><div class="sso_main_static"><?php echo htmlspecialchars($userrow->username); ?> </div><?php } ?> </div> </div> <?php } ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("New Password")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text sso_login_changehook" type="password" name="<?php echo SSO_FrontendField("update_pass"); ?> " value="<?php echo htmlspecialchars(SSO_FrontendFieldValue("update_pass", "")); ?> " /></div> <div class="sso_main_formdesc"><?php echo htmlspecialchars(BB_Translate("Optional. Will change the password for the account.")); ?> </div> </div> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <?php $outputmap = array(); // Two-factor authentication dropdown. $outputmap2 = array(); $method = SSO_FrontendFieldValue("update_two_factor_method", isset($updateinfo["two_factor_method"]) ? $updateinfo["two_factor_method"] : ""); foreach ($this->activemodules as $key => &$instance) { $name = $instance->GetTwoFactorName(); if ($name !== false) { $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap2, $order, $key, "<option value=\"" . htmlspecialchars($key) . "\"" . ($method == $key ? " selected" : "") . ">" . htmlspecialchars($name) . "</option>"); } } if (!$sso_settings["sso_login"]["require_two_factor"] && count($outputmap2)) { SSO_AddSortedOutput($outputmap2, 0, "", "<option value=\"\"" . ($method == "" ? " selected" : "") . ">" . htmlspecialchars(BB_Translate("None")) . "</option>"); } if (count($outputmap2)) { if (!isset($sso_session_info["sso_login_two_factor_key"])) { $sso_session_info["sso_login_two_factor_key"] = self::GenerateOTPKey(10); SSO_SaveSessionInfo(); } ob_start(); ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Choose Two-Factor Authentication Method")); ?> </div> <div class="sso_main_formdata"><select class="sso_main_dropdown sso_login_changehook_two_factor" name="<?php echo SSO_FrontendField("update_two_factor_method"); ?> "> <?php SSO_DisplaySortedOutput($outputmap2); ?> </select></div> <div class="sso_main_formdesc"><?php echo htmlspecialchars(BB_Translate($sso_settings["sso_login"]["require_two_factor"] ? "Required. Two-factor authentication vastly improves the security of your account." : "Optional. Two-factor authentication vastly improves the security of your account.")); ?> </div> <div class="sso_main_formtwofactorreset"><input id="sso_two_factor_reset" type="checkbox" name="<?php echo SSO_FrontendField("reset_two_factor_key"); ?> " value="yes"> <label for="sso_two_factor_reset"><?php echo htmlspecialchars(BB_Translate("Reset two-factor authentication security key")); ?> </label></div> </div> <?php $order = $sso_settings["sso_login"]["two_factor_order"]; SSO_AddSortedOutput($outputmap, $order, "two_factor", ob_get_contents()); ob_end_clean(); } // Add active module output. foreach ($this->activemodules as $key => &$instance) { ob_start(); $instance->GenerateUpdateInfo($userrow, $userinfo); $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap, $order, $key, ob_get_contents()); ob_end_clean(); } SSO_DisplaySortedOutput($outputmap); ?> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Update")); ?> " /> </div> </form> </div> </div> </div> <?php } } } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "recover2" && isset($_REQUEST["sso_method"]) && $this->IsRecoveryAllowed()) { // Load and validate the recovery options. $userrow = false; if (isset($sso_session_info["sso_login_recover"]) && isset($sso_session_info["sso_login_recover"]["id"]) && isset($sso_session_info["sso_login_recover"]["method"]) && $sso_session_info["sso_login_recover"]["method"] == $_REQUEST["sso_method"]) { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "id = ?"), $sso_db_sso_login_users, $sso_session_info["sso_login_recover"]["id"]); if ($userrow) { if (!isset($userrow->username)) { $userrow->username = ""; } if (!isset($userrow->email)) { $userrow->email = ""; } if (!isset($userrow->verified)) { $userrow->verified = 1; } } } catch (Exception $e) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=recover&sso_msg=recovery_db_error"); exit; } } if ($userrow === false) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=recover&sso_msg=recovery_expired_invalid"); exit; } $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=recover&sso_msg=recovery_db_user_error"); exit; } $messagesheader = false; $messages = false; if (SSO_FrontendFieldValue("submit") === false) { if (isset($_REQUEST["sso_msg"])) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->InitMessages($messages); } } } else { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->RecoveryCheck2($messages, false); } if (!count($messages["errors"])) { foreach ($this->activemodules as &$instance) { $instance->RecoveryCheck2($messages, $userinfo); } if (!count($messages["errors"])) { $sso_session_info["sso_login_update"] = array("id" => $userrow->id, "v" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 30 * 60)); $sso_session_info["sso_login_two_factor_key"] = isset($userinfo["two_factor_key"]) && $userinfo["two_factor_key"] != "" ? $userinfo["two_factor_key"] : self::GenerateOTPKey(10); if (!SSO_SaveSessionInfo()) { $result["errors"][] = BB_Translate("Recovery was successful but a fatal error occurred. Fatal error: Unable to save session information."); } else { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=update_info&sso_v=" . urlencode($sso_session_info["sso_login_update"]["v"])); exit; } } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, $messagesheader); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> <div class="sso_main_form_wrap sso_login_recover_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Restore Access")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=recover2&sso_method=" . urlencode($_REQUEST["sso_method"])); ?> " autocomplete="off"> <?php $outputmap = array(); foreach ($this->activemodules as $key => &$instance) { ob_start(); $instance->GenerateRecovery2($messages); $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap, $order, $key, ob_get_contents()); ob_end_clean(); } SSO_DisplaySortedOutput($outputmap); ?> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Next")); ?> " /> </div> </form> </div> </div> </div> <?php echo $sso_footer; } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "recover" && $this->IsRecoveryAllowed()) { $messagesheader = false; $messages = false; if (SSO_FrontendFieldValue("submit") === false) { if (isset($_REQUEST["sso_msg"])) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); if ($_REQUEST["sso_msg"] == "recovery_db_error") { $messages["warnings"][] = BB_Translate("A database error occurred while attempting to load recovery information."); } else { if ($_REQUEST["sso_msg"] == "recovery_expired_invalid") { $messages["errors"][] = BB_Translate("Recovery information is expired or invalid."); } else { if ($_REQUEST["sso_msg"] == "recovery_db_user_error") { $messages["errors"][] = BB_Translate("User information in the database is corrupted."); } else { foreach ($this->activemodules as &$instance) { $instance->InitMessages($messages); } } } } } } else { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); $user = SSO_FrontendFieldValue("user_recover"); $method = SSO_FrontendFieldValue("recover_method"); if ($user === false || $user == "" || $method === false || $method == "") { $messages["errors"][] = BB_Translate("Please fill in the fields."); } else { foreach ($this->activemodules as &$instance) { $instance->RecoveryCheck($messages, false); } if (!count($messages["errors"])) { $userrow = false; if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "email = ?"), $sso_db_sso_login_users, $user); if ($userrow) { if (!isset($userrow->username)) { $userrow->username = ""; } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("User check failed. Database query error."); } } else { if ($sso_settings["sso_login"]["install_type"] == "username") { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "username = ?"), $sso_db_sso_login_users, $user); if ($userrow) { if (!isset($userrow->email)) { $userrow->email = ""; } if (!isset($userrow->verified)) { $userrow->verified = 1; } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("User check failed. Database query error."); } } else { $messages["errors"][] = BB_Translate("Login system is broken."); } } if ($userrow === false) { $messages["errors"][] = BB_Translate("Invalid login."); } else { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { $messages["errors"][] = BB_Translate("Error loading user information."); } else { foreach ($this->activemodules as &$instance) { $instance->RecoveryCheck($messages, $userinfo); } } } if (!count($messages["errors"])) { if ($method == "email" && $userrow->email != "") { $sso_session_info["sso_login_update"] = array("id" => $userrow->id, "v" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 30 * 60)); $sso_session_info["sso_login_two_factor_key"] = isset($userinfo["two_factor_key"]) && $userinfo["two_factor_key"] != "" ? $userinfo["two_factor_key"] : self::GenerateOTPKey(10); if (!SSO_SaveSessionInfo()) { $messages["errors"][] = BB_Translate("Login exists but a fatal error occurred. Fatal error: Unable to save session information."); } else { $fromaddr = BB_PostTranslate($sso_settings["sso_login"]["email_recover_from"] != "" ? $sso_settings["sso_login"]["email_recover_from"] : SSO_SMTP_FROM); $subject = BB_Translate($sso_settings["sso_login"]["email_recover_subject"]); $verifyurl = BB_GetRequestHost() . $sso_target_url . ($sso_settings["sso_login"]["email_session"] == "all" ? "&sso_id=" . urlencode($_REQUEST["sso_id"]) : "") . "&sso_login_action=update_info&sso_v=" . urlencode($sso_session_info["sso_login_update"]["v"]); $htmlmsg = str_ireplace(array("@USERNAME@", "@EMAIL@", "@VERIFY@"), array(htmlspecialchars($userrow->username), htmlspecialchars($userrow->email), htmlspecialchars($verifyurl)), BB_PostTranslate($sso_settings["sso_login"]["email_recover_msg"])); $textmsg = str_ireplace(array("@USERNAME@", "@EMAIL@", "@VERIFY@"), array($userrow->username, $userrow->email, $verifyurl), BB_PostTranslate($sso_settings["sso_login"]["email_recover_msg_text"])); foreach ($this->activemodules as &$instance) { $instance->ModifyEmail($userinfo, $htmlmsg, $textmsg); } $result = SSO_SendEmail($fromaddr, $userrow->email, $subject, $htmlmsg, $textmsg); if (!$result["success"]) { $messages["errors"][] = BB_Translate("Login exists but a fatal error occurred. Fatal error: Unable to send verification e-mail. %s", $result["error"]); } else { foreach ($this->activemodules as &$instance) { $instance->RecoveryDone($messages, $method, $userrow, $userinfo); } if (!count($messages["errors"])) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_msg=recovery_email_sent"); exit; } } } } else { foreach ($this->activemodules as &$instance) { $instance->RecoveryDone($messages, $method, $userrow, $userinfo); } } } } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, $messagesheader); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> <div class="sso_main_form_wrap sso_login_recover_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Restore Access")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=recover"); ?> " autocomplete="off"> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { echo htmlspecialchars(BB_Translate("E-mail Address")); } else { if ($sso_settings["sso_login"]["install_type"] == "username") { echo htmlspecialchars(BB_Translate("Username")); } else { echo htmlspecialchars(BB_Translate("Login system is broken.")); } } ?> </div> <div class="sso_main_formdata"><input class="sso_main_text" type="text" name="<?php echo SSO_FrontendField("user_recover"); ?> " /></div> </div> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Recovery Method")); ?> </div> <div class="sso_main_formdata"><select class="sso_main_dropdown" name="<?php echo SSO_FrontendField("recover_method"); ?> "> <?php $method = SSO_FrontendFieldValue("recover_method", ""); if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { echo "<option value=\"email\"" . ($method == "email" ? " selected" : "") . ">" . htmlspecialchars(BB_Translate("E-mail")) . "</option>"; } foreach ($this->activemodules as &$instance) { $instance->AddRecoveryMethod($method); } ?> </select></div> </div> <?php $outputmap = array(); foreach ($this->activemodules as $key => &$instance) { ob_start(); $instance->GenerateRecovery($messages); $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap, $order, $key, ob_get_contents()); ob_end_clean(); } SSO_DisplaySortedOutput($outputmap); ?> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Next")); ?> " /> </div> </form> </div> </div> </div> <?php echo $sso_footer; } else { if (isset($_REQUEST["sso_login_action"]) && $_REQUEST["sso_login_action"] == "two_factor") { // Check the session and load the user account. $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->TwoFactorCheck($messages, false); } $userrow = false; if (!count($messages["errors"])) { if (!isset($_REQUEST["sso_v"]) || !isset($sso_session_info["sso_login_two_factor"])) { $messages["errors"][] = BB_Translate("Invalid URL. Verification missing."); } else { if (trim($_REQUEST["sso_v"]) !== $sso_session_info["sso_login_two_factor"]["v"]) { $messages["errors"][] = BB_Translate("Invalid verification string specified."); } else { if (!isset($sso_session_info["sso_login_two_factor"]["expires"]) || CSDB::ConvertFromDBTime($sso_session_info["sso_login_two_factor"]["expires"]) < time()) { $messages["errors"][] = BB_Translate("Two-factor information is expired or invalid."); } else { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "id = ?"), $sso_db_sso_login_users, $sso_session_info["sso_login_two_factor"]["id"]); if ($userrow === false) { $messages["errors"][] = BB_Translate("Two-factor information is expired or invalid."); } else { if (!isset($userrow->username)) { $userrow->username = ""; } if (!isset($userrow->email)) { $userrow->email = ""; } if (!isset($userrow->verified)) { $userrow->verified = 1; } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("User check failed. Database query error."); } } } } } $method = BB_Translate("Unknown/Invalid."); if (!count($messages["errors"])) { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { $messages["errors"][] = BB_Translate("Error loading user information."); } else { // Check the two-factor authentication method. $methods = array(); foreach ($this->activemodules as $key => &$instance) { $name = $instance->GetTwoFactorName(false); if ($name !== false) { $methods[$key] = $name; } } if (isset($userinfo["two_factor_method"]) && isset($methods[$userinfo["two_factor_method"]])) { $method = $methods[$userinfo["two_factor_method"]]; } else { $messages["errors"][] = BB_Translate("A valid two-factor authentication method for this account is not available. Use account recovery to restore access to the account."); } } } if (count($messages["errors"])) { echo $sso_header; SSO_OutputHeartbeat(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, false); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> </div> </div> <?php echo $sso_footer; } else { $messagesheader = false; $messages = false; if (SSO_FrontendFieldValue("submit") === false) { if (isset($_REQUEST["sso_msg"])) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->InitMessages($messages); } } } else { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); foreach ($this->activemodules as &$instance) { $instance->TwoFactorCheck($messages, $userinfo); } if (count($messages["errors"])) { foreach ($this->activemodules as &$instance) { $instance->TwoFactorFailed($messages, $userinfo); } } else { // Login with two-factor authentication succeeded. Activate the user. $mapinfo = array(); if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { $mapinfo[$sso_settings["sso_login"]["map_email"]] = $userrow->email; } if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username") { $mapinfo[$sso_settings["sso_login"]["map_username"]] = $userrow->username; } $origuserinfo = $userinfo; foreach ($this->activemodules as &$instance) { $instance->LoginAddMap($mapinfo, $userrow, $userinfo, false); } // If a module updated $userinfo, then update the database. if (serialize($userinfo) !== serialize($origuserinfo)) { $userinfo2 = SSO_EncryptDBData($userinfo); try { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } } if (!count($messages["errors"])) { SSO_ActivateUser($userrow->id, $userinfo["extra"], $mapinfo, CSDB::ConvertFromDBTime($userrow->created)); // Only falls through on account lockout or a fatal error. $messages["errors"][] = BB_Translate("User activation failed."); } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, $messagesheader); ?> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> <div class="sso_main_form_wrap sso_login_recover_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Two-Factor Authentication")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=two_factor&sso_v=" . urlencode($_REQUEST["sso_v"])); ?> " autocomplete="off"> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Enter Two-Factor Authentication Code")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text" type="text" name="<?php echo SSO_FrontendField("two_factor_code"); ?> " /></div> <div class="sso_main_formdesc"><?php echo htmlspecialchars(BB_Translate("From %s.", $method)); ?> </div> </div> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Sign in")); ?> " /> </div> </form> </div> </div> </div> <?php echo $sso_footer; } } else { $messagesheader = false; $messages = false; if (SSO_FrontendFieldValue("submit") === false) { if (isset($_REQUEST["sso_msg"])) { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); if ($_REQUEST["sso_msg"] == "verified") { $messages["success"] = BB_Translate("Your account is ready to use."); } else { if ($_REQUEST["sso_msg"] == "verify") { $messages["warnings"][] = BB_Translate("Account must be verified before it can be used. Check your e-mail."); } else { if ($_REQUEST["sso_msg"] == "recovery_email_sent") { $messages["warnings"][] = BB_Translate("Account recovery URL sent. Check your e-mail."); } else { if ($_REQUEST["sso_msg"] == "updated") { $messages["success"] = BB_Translate("Your account information has been updated and is ready to use."); } else { if ($_REQUEST["sso_msg"] == "two_factor_auth_expired") { $messages["errors"][] = BB_Translate("Two-factor authentication expired. Sign in again."); } else { foreach ($this->activemodules as &$instance) { $instance->InitMessages($messages); } } } } } } } } else { $messages = array("errors" => array(), "warnings" => array(), "success" => ""); $user = SSO_FrontendFieldValue("user"); $password = SSO_FrontendFieldValue("password"); if ($user === false || $user == "" || $password === false || $password == "") { $messages["errors"][] = BB_Translate("Please fill in the fields."); } else { $recoveryallowed = $this->IsRecoveryAllowed(false); foreach ($this->activemodules as &$instance) { $instance->LoginCheck($messages, false, $recoveryallowed); } if (!count($messages["errors"])) { $userrow = false; if (strpos($user, "@") !== false && ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email")) { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "email = ?"), $sso_db_sso_login_users, $user); if ($userrow) { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { $userrow = false; } else { if (!isset($userrow->username)) { $userrow->username = ""; } $data = $userrow->username . ":" . $userrow->email . ":" . $userinfo["salt"] . ":" . $password; if (!self::VerifyPasswordInfo($data, $userinfo["password"], $userinfo["rounds"])) { $userrow = false; } } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("Login failed. Database query error."); } } if ($userrow === false && ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username")) { try { $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "username = ?"), $sso_db_sso_login_users, $user); if ($userrow) { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo === false) { $userrow = false; } else { if (!isset($userrow->email)) { $userrow->email = ""; } if (!isset($userrow->verified)) { $userrow->verified = 1; } $data = $userrow->username . ":" . $userrow->email . ":" . $userinfo["salt"] . ":" . $password; if (!self::VerifyPasswordInfo($data, $userinfo["password"], $userinfo["rounds"])) { $userrow = false; } } } } catch (Exception $e) { $messages["errors"][] = BB_Translate("Login failed. Database query error."); } } if ($userrow === false) { $messages["errors"][] = BB_Translate("Invalid login."); } else { // Make sure the password is stored securely. If not, transparently update the hash information in the database. if ($userinfo["rounds"] < $sso_settings["sso_login"]["password_minrounds"]) { $userinfo["salt"] = $sso_rng->GenerateString(); $data = $userrow->username . ":" . $userrow->email . ":" . $userinfo["salt"] . ":" . $password; $passwordinfo = self::HashPasswordInfo($data, $sso_settings["sso_login"]["password_mode"], $sso_settings["sso_login"]["password_minrounds"]); if ($passwordinfo["success"]) { $userinfo["rounds"] = (int) $passwordinfo["rounds"]; $userinfo["password"] = bin2hex($passwordinfo["hash"]); $userinfo2 = SSO_EncryptDBData($userinfo); try { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } } } foreach ($this->activemodules as &$instance) { $instance->LoginCheck($messages, $userinfo, $recoveryallowed); } } if (!count($messages["errors"])) { // Go to two-factor authentication page. $methods = array(); foreach ($this->activemodules as $key => &$instance) { $name = $instance->GetTwoFactorName(false); if ($name !== false) { $methods[$key] = true; } } // Resend the verification e-mail. if (!$userrow->verified) { $this->SendVerificationEmail($userrow->id, $userinfo, $messages, $userrow->username, $userrow->email); } else { if (!$recoveryallowed && SSO_FrontendFieldValue("update_info", "") == "yes") { $sso_session_info["sso_login_update"] = array("id" => $userrow->id, "v" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 30 * 60)); $sso_session_info["sso_login_two_factor_key"] = isset($userinfo["two_factor_key"]) && $userinfo["two_factor_key"] != "" ? $userinfo["two_factor_key"] : self::GenerateOTPKey(10); if (!SSO_SaveSessionInfo()) { $messages["errors"][] = BB_Translate("Login exists but a fatal error occurred. Fatal error: Unable to save session information."); } else { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=update_info&sso_v=" . urlencode($sso_session_info["sso_login_update"]["v"])); exit; } } else { if ($sso_settings["sso_login"]["require_two_factor"] || isset($userinfo["two_factor_method"]) && $userinfo["two_factor_method"] != "" && (count($methods) || ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email"))) { if ($sso_settings["sso_login"]["require_two_factor"] && (!isset($userinfo["two_factor_method"]) || !isset($methods[$userinfo["two_factor_method"]]))) { $messages["errors"][] = BB_Translate("A valid two-factor authentication method for this account is not available. Use account recovery to restore access to the account."); } else { $sso_session_info["sso_login_two_factor"] = array("id" => $userrow->id, "v" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 5 * 60)); if (!SSO_SaveSessionInfo()) { $messages["errors"][] = BB_Translate("Login exists but a fatal error occurred. Fatal error: Unable to save session information."); } else { $this->activemodules[$userinfo["two_factor_method"]]->SendTwoFactorCode($messages, $userrow, $userinfo); if (!count($messages["errors"])) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=two_factor&sso_v=" . urlencode($sso_session_info["sso_login_two_factor"]["v"])); exit; } } } } else { // Login succeeded. Activate the user. $mapinfo = array(); if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { $mapinfo[$sso_settings["sso_login"]["map_email"]] = $userrow->email; } if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username") { $mapinfo[$sso_settings["sso_login"]["map_username"]] = $userrow->username; } $origuserinfo = $userinfo; foreach ($this->activemodules as &$instance) { $instance->LoginAddMap($mapinfo, $userrow, $userinfo, false); } // If a module updated $userinfo, then update the database. if (serialize($userinfo) !== serialize($origuserinfo)) { $userinfo2 = SSO_EncryptDBData($userinfo); try { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } } if (!count($messages["errors"])) { SSO_ActivateUser($userrow->id, $userinfo["extra"], $mapinfo, CSDB::ConvertFromDBTime($userrow->created)); // Only falls through on account lockout or a fatal error. $messages["errors"][] = BB_Translate("User activation failed."); } } } } } } } } echo $sso_header; SSO_OutputHeartbeat(); $this->OutputJS(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <?php $this->DisplayMessages($messages, $messagesheader); if ($sso_settings["sso_login"]["open_reg"]) { ?> <div class="sso_login_signup"><a href="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=signup"); ?> "><?php echo htmlspecialchars(BB_Translate("Sign up")); ?> </a></div> <?php } ?> <div class="sso_main_form_wrap sso_login_signin_form"> <div class="sso_main_form_header"><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </div> <form class="sso_main_form" name="sso_login_form" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="<?php echo htmlspecialchars($sso_target_url); ?> " autocomplete="off"> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php if ($sso_settings["sso_login"]["install_type"] == "email_username") { echo htmlspecialchars(BB_Translate("Username or E-mail Address")); } else { if ($sso_settings["sso_login"]["install_type"] == "username") { echo htmlspecialchars(BB_Translate("Username")); } else { if ($sso_settings["sso_login"]["install_type"] == "email") { echo htmlspecialchars(BB_Translate("E-mail Address")); } else { echo htmlspecialchars(BB_Translate("Login system is broken.")); } } } ?> </div> <div class="sso_main_formdata"><input class="sso_main_text" type="text" name="<?php echo SSO_FrontendField("user"); ?> " /></div> </div> <script type="text/javascript"> jQuery('input.sso_main_text:first').focus(); </script> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Password")); ?> </div> <div class="sso_main_formdata"><input class="sso_main_text" type="password" name="<?php echo SSO_FrontendField("password"); ?> " /></div> </div> <?php $outputmap = array(); foreach ($this->activemodules as $key => &$instance) { ob_start(); $instance->GenerateLogin($messages); $order = isset($sso_settings["sso_login"]["modules"][$key]["_s"]) ? $sso_settings["sso_login"]["modules"][$key]["_s"] : $instance->DefaultOrder(); SSO_AddSortedOutput($outputmap, $order, $key, ob_get_contents()); ob_end_clean(); } SSO_DisplaySortedOutput($outputmap); if (!$this->IsRecoveryAllowed(false)) { ?> <div class="sso_main_formitem"> <div class="sso_main_formtitle"><?php echo htmlspecialchars(BB_Translate("Update Information")); ?> </div> <div class="sso_main_formdata"><input id="sso_norecovery_updateinfo" type="checkbox" name="<?php echo SSO_FrontendField("update_info"); ?> " value="yes"<?php if (SSO_FrontendFieldValue("update_info", "") == "yes") { echo " checked"; } ?> /> <label for="sso_norecovery_updateinfo">Change account information upon successful sign in</label></div> </div> <?php } ?> <div class="sso_main_formsubmit"> <input type="submit" name="<?php echo SSO_FrontendField("submit"); ?> " value="<?php echo htmlspecialchars(BB_Translate("Sign in")); ?> " /> </div> </form> </div> <?php if ($this->IsRecoveryAllowed()) { ?> <div class="sso_login_recover_changeinfo"><a href="<?php echo htmlspecialchars($sso_target_url . "&sso_login_action=recover"); ?> "><?php echo htmlspecialchars(BB_Translate("Can't access your account?")); ?> </a></div> <?php } ?> </div> </div> <?php echo $sso_footer; } } } } } } } } }
public function CustomFrontend() { global $g_sso_login_modules, $sso_settings, $sso_header, $sso_footer, $sso_target_url, $sso_db, $sso_session_info, $sso_rng; $messages = array("errors" => array(), "warnings" => array(), "success" => ""); $info = $this->GetInfo(); if ($info["cookiekey"] != "" && $info["cookieiv"] != "" && $info["cookiekey2"] != "" && $info["cookieiv2"] != "") { // Initialize active modules. $this->activemodules = array(); foreach ($g_sso_login_modules as $key => $info2) { if ($sso_settings["sso_login"]["modules"][$key]["_a"]) { $module = "sso_login_module_" . $key; $this->activemodules[$key] = new $module(); } } $sso_db_sso_login_users = SSO_DB_PREFIX . "p_sso_login_users"; if (isset($_REQUEST["id"]) && isset($_COOKIE["sso_l_rme"])) { // Decrypt data. $info2 = @base64_decode($_COOKIE["sso_l_rme"]); if ($info2 !== false) { $info2 = Blowfish::ExtractDataPacket($info2, pack("H*", $info["cookiekey"]), array("mode" => "CBC", "iv" => pack("H*", $info["cookieiv"]), "key2" => pack("H*", $info["cookiekey2"]), "iv2" => pack("H*", $info["cookieiv2"]), "lightweight" => true)); } if ($info2 !== false) { $info2 = @unserialize($info2); } if ($info2 !== false) { $id = (int) $_REQUEST["id"]; if (isset($info2[$id]) && is_array($info2[$id]) && count($info2[$id]) == 2) { // Load database information and verify the sign in. $userrow = $sso_db->GetRow("SELECT", array("*", "FROM" => "?", "WHERE" => "id = ?"), $sso_db_sso_login_users, $id); if ($userrow && (!isset($userrow->verified) || $userrow->verified)) { $userinfo = SSO_DecryptDBData($userrow->info); if ($userinfo !== false && isset($userinfo["sso_remember_me"]) && isset($userinfo["sso_remember_me"][$info2[$userrow->id][0]])) { $info3 = $userinfo["sso_remember_me"][$info2[$userrow->id][0]]; $ts = CSDB::ConvertFromDBTime($info3["expires"]); if ($ts > time()) { $data = $info3["salt"] . ":" . $info2[$userrow->id][1]; if (sso_login::VerifyPasswordInfo($data, $info3["hash"], $info3["rounds"])) { // Sign in is now verified to be valid. if (!$info3["bypass"] && ($sso_settings["sso_login"]["require_two_factor"] || isset($userinfo["two_factor_method"]) && $userinfo["two_factor_method"] != "")) { // Go to two-factor authentication page. $methods = array(); foreach ($this->activemodules as $key => &$instance) { $name = $instance->GetTwoFactorName(false); if ($name !== false) { $methods[$key] = true; } } if ($sso_settings["sso_login"]["require_two_factor"] && (!isset($userinfo["two_factor_method"]) || !isset($methods[$userinfo["two_factor_method"]]))) { $messages["errors"][] = BB_Translate("A valid two-factor authentication method for this account is not available. Use account recovery to restore access to the account."); } else { $sso_session_info["sso_login_two_factor"] = array("id" => $userrow->id, "v" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 5 * 60)); if (!SSO_SaveSessionInfo()) { $messages["errors"][] = BB_Translate("Login exists but a fatal error occurred. Fatal error: Unable to save session information."); } else { $this->activemodules[$userinfo["two_factor_method"]]->SendTwoFactorCode($messages, $userrow, $userinfo); if (!count($messages["errors"])) { header("Location: " . BB_GetRequestHost() . $sso_target_url . "&sso_login_action=two_factor&sso_v=" . urlencode($sso_session_info["sso_login_two_factor"]["v"])); exit; } } } } else { // Login succeeded. Activate the user. $mapinfo = array(); if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "email") { $mapinfo[$sso_settings["sso_login"]["map_email"]] = $userrow->email; } if ($sso_settings["sso_login"]["install_type"] == "email_username" || $sso_settings["sso_login"]["install_type"] == "username") { $mapinfo[$sso_settings["sso_login"]["map_username"]] = $userrow->username; } $origuserinfo = $userinfo; foreach ($this->activemodules as &$instance) { $instance->LoginAddMap($mapinfo, $userrow, $userinfo, false); } // If a module updated $userinfo, then update the database. if (serialize($userinfo) !== serialize($origuserinfo)) { $userinfo2 = SSO_EncryptDBData($userinfo); try { $sso_db->Query("UPDATE", array($sso_db_sso_login_users, array("info" => $userinfo2), "WHERE" => "id = ?"), $userrow->id); } catch (Exception $e) { $messages["errors"][] = BB_Translate("Database query error."); } } if (!count($messages["errors"])) { SSO_ActivateUser($userrow->id, $userinfo["extra"], $mapinfo, CSDB::ConvertFromDBTime($userrow->created)); // Only falls through on account lockout or a fatal error. $messages["errors"][] = BB_Translate("User activation failed."); } } } } } } } } } echo $sso_header; SSO_OutputHeartbeat(); ?> <div class="sso_main_wrap sso_login"> <div class="sso_main_wrap_inner"> <div class="sso_main_messages_wrap"> <div class="sso_main_messages"> <?php if (count($messages["errors"])) { ?> <div class="sso_main_messageerror"><?php echo htmlspecialchars($messages["errors"][0]); ?> </div> <?php } ?> <div class="sso_main_messageerror"><?php echo htmlspecialchars(BB_Translate("An error occurred while processing the remembered sign in. You will have to sign in normally.")); ?> </div> </div> </div> <div class="sso_login_signin"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Sign in")); ?> </a></div> </div> </div> <?php echo $sso_footer; } }