public function ProcessFrontend() { global $sso_rng, $sso_provider, $sso_settings, $sso_session_info; $redirect_uri = BB_GetRequestHost() . SSO_ROOT_URL . "/index.php?sso_provider=" . urlencode($sso_provider) . "&sso_google_action=signin"; if (isset($_REQUEST["sso_google_action"]) && $_REQUEST["sso_google_action"] == "signin") { // Recover the language settings. if (!isset($sso_session_info["sso_google_info"])) { $this->DisplayError(BB_Translate("Unable to authenticate the request.")); return; } $url = BB_GetRequestHost() . SSO_ROOT_URL . "/index.php?sso_provider=" . urlencode($sso_provider) . "&sso_google_action=signin2"; if (isset($_REQUEST["state"])) { $url .= "&state=" . urlencode($_REQUEST["state"]); } if (isset($_REQUEST["code"])) { $url .= "&code=" . urlencode($_REQUEST["code"]); } if (isset($_REQUEST["error"])) { $url .= "&error=" . urlencode($_REQUEST["error"]); } $url .= "&lang=" . urlencode($sso_session_info["sso_google_info"]["lang"]); header("Location: " . $url); } else { if (isset($_REQUEST["sso_google_action"]) && $_REQUEST["sso_google_action"] == "signin2") { // Validate the token. if (!isset($_REQUEST["state"]) || !isset($sso_session_info["sso_google_info"]) || $_REQUEST["state"] !== $sso_session_info["sso_google_info"]["token"]) { $this->DisplayError(BB_Translate("Unable to authenticate the request.")); return; } // Check for token expiration. if (CSDB::ConvertFromDBTime($sso_session_info["sso_google_info"]["expires"]) < time()) { $this->DisplayError(BB_Translate("Verification token has expired.")); return; } if (isset($_REQUEST["error"])) { if ($_REQUEST["error"] == "access_denied") { $message = BB_Translate("The request to sign in with Google was denied."); } else { $message = BB_Translate("The error message returned was '%s'.", $_REQUEST["error"]); } $this->DisplayError(BB_Translate("Sign in failed. %s", $message)); return; } if (!isset($_REQUEST["code"])) { $this->DisplayError(BB_Translate("Sign in failed. Authorization code missing.")); return; } // Get an access token from the authorization code. require_once SSO_ROOT_PATH . "/" . SSO_SUPPORT_PATH . "/http.php"; require_once SSO_ROOT_PATH . "/" . SSO_SUPPORT_PATH . "/web_browser.php"; $url = "https://accounts.google.com/o/oauth2/token"; $options = array("postvars" => array("code" => $_REQUEST["code"], "client_id" => $sso_settings["sso_google"]["client_id"], "client_secret" => $sso_settings["sso_google"]["client_secret"], "redirect_uri" => $redirect_uri, "grant_type" => "authorization_code")); $web = new WebBrowser(); $result = $web->Process($url, "auto", $options); if (!$result["success"]) { $this->DisplayError(BB_Translate("Sign in failed. Error retrieving URL for Google access token. %s", $result["error"])); } else { if ($result["response"]["code"] != 200) { $this->DisplayError(BB_Translate("Sign in failed. The Google access token server returned: %s", $result["response"]["code"] . " " . $result["response"]["meaning"])); } else { // Get the access token. $data = @json_decode($result["body"], true); if ($data === false || !isset($data["access_token"])) { $this->DisplayError(BB_Translate("Sign in failed. Error retrieving access token from Google.")); } else { // Get the user's profile information. $url = "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" . urlencode($data["access_token"]); $result = $web->Process($url); if (!$result["success"]) { $this->DisplayError(BB_Translate("Sign in failed. Error retrieving URL for Google profile information. %s", $result["error"])); } else { if ($result["response"]["code"] != 200) { $this->DisplayError(BB_Translate("Sign in failed. The Google profile information server returned: %s", $result["response"]["code"] . " " . $result["response"]["meaning"])); } else { $profile = @json_decode($result["body"], true); if ($profile === false) { $this->DisplayError(BB_Translate("Sign in failed. Error retrieving profile information from Google.")); } $origprofile = $profile; // Remove unverified e-mail addresses. if (!isset($profile["verified_email"]) || !$profile["verified_email"]) { unset($profile["verified_email"]); unset($profile["email"]); } // Convert most profile fields into strings. foreach ($profile as $key => $val) { if (is_string($val)) { continue; } if (is_bool($val)) { $val = (string) (int) $val; } else { if (is_numeric($val)) { $val = (string) $val; } else { if (is_object($val) && isset($val->id) && isset($val->name)) { $val = $val->name; } } } $profile[$key] = $val; } $mapinfo = array(); foreach (self::$fieldmap as $key => $info) { $key2 = $sso_settings["sso_google"]["map_" . $key]; if ($key2 != "" && isset($profile[$key])) { $mapinfo[$key2] = $profile[$key]; } } SSO_ActivateUser($profile["id"], serialize($origprofile), $mapinfo); // Only falls through on account lockout or a fatal error. $this->DisplayError(BB_Translate("User activation failed.")); } } } } } } else { // Create internal data packet. $token = $sso_rng->GenerateString(); $sso_session_info["sso_google_info"] = array("lang" => isset($_REQUEST["lang"]) ? $_REQUEST["lang"] : "", "token" => $token, "expires" => CSDB::ConvertToDBTime(time() + 30 * 60)); if (!SSO_SaveSessionInfo()) { $this->DisplayError(BB_Translate("Unable to save session information.")); return; } // Calculate the required scope. $scope = array("https://www.googleapis.com/auth/userinfo.profile" => true); foreach (self::$fieldmap as $key => $info) { if ($info["extra"] != "" && $sso_settings["sso_google"]["map_" . $key] != "") { $scope[$info["extra"]] = true; } } // Get the login redirection URL. $options = array("response_type" => "code", "client_id" => $sso_settings["sso_google"]["client_id"], "redirect_uri" => $redirect_uri, "scope" => implode(" ", array_keys($scope)), "state" => $token); $options2 = array(); foreach ($options as $key => $val) { $options2[] = urlencode($key) . "=" . urlencode($val); } $url = "https://accounts.google.com/o/oauth2/auth?" . implode("&", $options2); SSO_ExternalRedirect($url); } } }
public function ProcessFrontend() { global $sso_settings, $sso_rng, $sso_provider, $sso_target_url, $sso_session_info, $sso_session_id, $sso_db; if (isset($sso_session_info["setlogin_result"]) && !isset($_REQUEST["tryagain"])) { // Check the secret. if (!isset($_REQUEST["sso_setlogin_secret"]) || !isset($sso_session_info["setlogin_info"]) || $_REQUEST["sso_setlogin_secret"] !== $sso_session_info["setlogin_info"]["secret"]) { $this->DisplayError(BB_Translate("Unable to authenticate the request.")); return; } // Should be nearly impossible to get here since browser redirects are executed almost immediately. if (CSDB::ConvertFromDBTime($sso_session_info["setlogin_info"]["expires"]) < time()) { $this->DisplayError(BB_Translate("Verification token has expired.")); return; } // The user is signed in. Activate the account. $sso_db_sso_remote_users = SSO_DB_PREFIX . "p_sso_remote_users"; try { $id = $sso_db->GetOne("SELECT", array("id", "FROM" => "?", "WHERE" => "remote_id = ? AND user_id = ?"), $sso_db_sso_remote_users, $this->info["row"]->id, $sso_session_info["setlogin_result"]["user_id"]); if ($id === false) { $sso_db->Query("INSERT", array($sso_db_sso_remote_users, array("remote_id" => $this->info["row"]->id, "user_id" => $sso_session_info["setlogin_result"]["user_id"], "created" => CSDB::ConvertToDBTime(time())), "AUTO INCREMENT" => "id")); $id = $sso_db->GetInsertID(); } $mapinfo = $sso_session_info["setlogin_result"]["protected_fields"]; $mapinfo[$sso_settings["sso_remote"]["map_remote_id"]] = $this->info["row"]->id; SSO_ActivateUser($id, serialize($sso_session_info["setlogin_info"]), $mapinfo, false, $this->info["row_info"]["automate"]); // Only falls through on account lockout or a fatal error. $this->DisplayError(BB_Translate("User activation failed.")); } catch (Exception $e) { $this->DisplayError("A database error has occurred. Most likely cause: Bad SQL query."); } } else { // Check the API key information. $info = unserialize($this->info["apirow"]->info); if ($info["type"] != "remote") { $this->DisplayError(BB_Translate("The target client API key is not a remote API key.")); return; } if ($info["url"] == "") { $this->DisplayError(BB_Translate("The target client API key URL is missing.")); return; } // Set up the session so that the endpoint works. unset($sso_session_info["setlogin_result"]); $token = $sso_rng->GenerateString(); $sso_session_info["setlogin_info"] = array("provider" => $sso_provider, "apikey_id" => $this->info["apirow"]->id, "redirect_url" => BB_GetRequestHost() . $sso_target_url, "token" => $token, "secret" => $sso_rng->GenerateString(), "expires" => CSDB::ConvertToDBTime(time() + 30 * 60)); if (!SSO_SaveSessionInfo()) { $this->DisplayError(BB_Translate("Unable to save session information.")); return; } // Redirect to the remote host. $url = $info["url"] . (strpos($info["url"], "?") === false ? "?" : "&") . "from_sso_server=1&sso_setlogin_id=" . urlencode($sso_session_id[1]) . "&sso_setlogin_token=" . urlencode($token) . (isset($_REQUEST["lang"]) ? "&sso_lang=" . urlencode($_REQUEST["lang"]) : ""); SSO_ExternalRedirect($url); } }
public function ProcessFrontend() { global $sso_provider, $sso_settings, $sso_target_url, $sso_header, $sso_footer, $sso_providers, $sso_selectors_url; require_once SSO_ROOT_PATH . "/" . SSO_PROVIDER_PATH . "/" . $sso_provider . "/facebook.php"; $facebook = new SSO_FacebookSDK(array("appId" => $sso_settings["sso_facebook"]["app_id"], "secret" => $sso_settings["sso_facebook"]["app_secret"])); $id = $facebook->getUser(); if ($id) { try { // Calculate the required fields. $fields = array("id" => true, "first_name" => true, "last_name" => true); foreach (self::$fieldmap as $key => $info) { if ($sso_settings["sso_facebook"]["map_" . $key] != "" && !isset($info["pseudo"])) { $fields[isset($info["parent"]) ? $info["parent"] : $key] = true; } } $profile = $facebook->api("/me", "GET", array("fields" => implode(",", array_keys($fields)))); } catch (FacebookApiException $e) { // Fall through here to go to the next step. $id = 0; $exceptionmessage = $e->getMessage(); } } if (isset($_REQUEST["sso_facebook_action"]) && $_REQUEST["sso_facebook_action"] == "signin") { if ($id) { // Create a fake username based on available information. if ($sso_settings["sso_facebook"]["map_username"] != "") { if (isset($profile["email"])) { $profile["username"] = (string) @substr($profile["email"], 0, strpos($profile["email"], "@")); } else { if (isset($profile["first_name"]) && isset($profile["last_name"])) { $profile["username"] = $profile["first_name"] . @substr($profile["last_name"], 0, 1); } else { if (isset($profile["name"])) { $name = explode(" ", $name); $profile["username"] = $name[0] . @substr($name[count($name) - 1], 0, 1); } else { $profile["username"] = (string) $id; } } } $profile["username"] = preg_replace('/\\s+/', "_", trim(preg_replace('/[^a-z0-9]/', " ", strtolower((string) $profile["username"])))); } // Check username blacklist. $message = ""; if (isset($profile["username"])) { $blacklist = explode("\n", str_replace("\r", "\n", $sso_settings["sso_facebook"]["username_blacklist"])); foreach ($blacklist as $word) { $word = trim($word); if ($word != "" && stripos($profile["username"], $word) !== false) { $message = BB_Translate("Username contains a blocked word."); break; } } } // Check e-mail domain blacklist. if (isset($profile["email"])) { define("CS_TRANSLATE_FUNC", "BB_Translate"); require_once SSO_ROOT_PATH . "/" . SSO_SUPPORT_PATH . "/smtp.php"; $email = SMTP::MakeValidEmailAddress($profile["email"]); if (!$email["success"]) { $message = BB_Translate("Invalid e-mail address. %s", $email["error"]); } else { $domain = strtolower(substr($email["email"], strrpos($email["email"], "@") + 1)); $y = strlen($domain); $baddomains = explode("\n", strtolower($sso_settings["sso_facebook"]["email_bad_domains"])); foreach ($baddomains as $baddomain) { $baddomain = trim($baddomain); if ($baddomain != "") { $y2 = strlen($baddomain); if ($domain == $baddomain || $y < $y2 && substr($domain, $y - $y2 - 1, 1) == "." && substr($domain, $y - $y2) == $baddomain) { $message = BB_Translate("E-mail address is in a blacklisted domain."); break; } } } } } if ($message == "") { // Fix birthday to be in international format YYYY-MM-DD. if (isset($profile["birthday"])) { $birthday = explode("/", $profile["birthday"]); $year = array_pop($birthday); array_unshift($birthday, $year); $profile["birthday"] = implode("-", $birthday); } // Convert most profile fields into strings. foreach ($profile as $key => $val) { if (is_string($val)) { continue; } if (is_bool($val)) { $val = (string) (int) $val; } else { if (is_numeric($val)) { $val = (string) $val; } else { if (is_object($val) && isset($val->id) && isset($val->name)) { $val = $val->name; } } } $profile[$key] = $val; } // Convert specialized fields into strings. if (isset($profile["age_range"])) { $profile["age_range"] = trim($item->min . "-" . $item->max); } if (isset($profile["education"])) { $items = array(); foreach ($profile["education"] as $item) { $items[] = trim($item->year . " " . $item->type . " " . $item->school->name); } $profile["education"] = implode("\n", $items); } if (isset($profile["work"])) { $items = array(); foreach ($profile["work"] as $item) { $items[] = trim($item->employer . ", " . $item->location . ", " . $item->position); } $profile["work"] = implode("\n", $items); } $mapinfo = array(); foreach (self::$fieldmap as $key => $info) { $key2 = $sso_settings["sso_facebook"]["map_" . $key]; if ($key2 != "" && isset($profile[$key])) { $mapinfo[$key2] = $profile[$key]; } } // Process specialized fields. if (isset($profile["birthday"])) { $birthday = explode("-", $profile["birthday"]); $key = "birthday_year"; $key2 = $sso_settings["sso_facebook"]["map_" . $key]; if ($key2 != "") { $mapinfo[$key2] = $birthday[0]; } $key = "birthday_month"; $key2 = $sso_settings["sso_facebook"]["map_" . $key]; if ($key2 != "") { $mapinfo[$key2] = $birthday[1]; } $key = "birthday_day"; $key2 = $sso_settings["sso_facebook"]["map_" . $key]; if ($key2 != "") { $mapinfo[$key2] = $birthday[2]; } } SSO_ActivateUser($profile["id"], serialize($profile), $mapinfo); // Only falls through on account lockout or a fatal error. $message = BB_Translate("User activation failed."); } } else { if (isset($_REQUEST["error"]) && $_REQUEST["error"] == "access_denied") { $message = BB_Translate("The request to sign in with Facebook was denied."); } else { if (isset($_REQUEST["error_description"])) { $message = BB_Translate($_REQUEST["error_description"]); } else { $message = BB_Translate("An unknown error occurred. %s", $exceptionmessage); } } } $message = BB_Translate("Sign in failed. %s", $message); echo $sso_header; SSO_OutputHeartbeat(); ?> <div class="sso_main_wrap"> <div class="sso_main_wrap_inner"> <div class="sso_main_messages_wrap"> <div class="sso_main_messages"> <div class="sso_main_messageerror"><?php echo htmlspecialchars($message); ?> </div> </div> </div> <div class="sso_main_info"><a href="<?php echo htmlspecialchars($sso_target_url); ?> "><?php echo htmlspecialchars(BB_Translate("Try again")); ?> </a><?php if (count($sso_providers) > 1) { ?> | <a href="<?php echo htmlspecialchars($sso_selectors_url); ?> "><?php echo htmlspecialchars(BB_Translate("Select another sign in method")); ?> </a><?php } ?> </div> </div> </div> <?php echo $sso_footer; } else { // Calculate the required scope. $scope = array(); foreach (self::$fieldmap as $key => $info) { if ($info["extra"] != "" && $sso_settings["sso_facebook"]["map_" . $key] != "") { $scope[$info["extra"]] = true; } } // Get the login redirection URL. $options = array("scope" => implode(",", array_keys($scope)), "redirect_uri" => BB_GetRequestHost() . $sso_target_url . "&sso_facebook_action=signin"); $url = $facebook->getLoginUrl($options); SSO_ExternalRedirect($url); } }
function SSO_ValidateUser() { global $sso_rng, $sso_db, $sso_db_user_sessions, $sso_db_temp_sessions, $sso_session_info, $sso_apirow, $sso_sessionrow, $sso_sessionrow2, $sso_ipaddr, $sso_settings; try { // Browser gets a token representing the new session in the temporary session. $sso_session_info["new_id2"] = $sso_rng->GenerateString(); $sso_db->Query("UPDATE", array($sso_db_temp_sessions, array("info" => serialize($sso_session_info)), "WHERE" => "id = ?"), $sso_sessionrow->id); // Validate the session. $sso_db->Query("UPDATE", array($sso_db_user_sessions, array("updated" => CSDB::ConvertToDBTime(time()), "info" => serialize(array("validated" => true, "ipaddr" => $sso_ipaddr["ipv6"]))), "WHERE" => "id = ?"), $sso_sessionrow2->id); // Build the redirect. $redirect = str_replace(array("\r", "\n"), "", base64_decode($sso_session_info["url"])); $redirect .= (strpos($redirect, "?") === false ? "?" : "&") . "from_sso_server=1&sso_id=" . urlencode($sso_session_info["new_id2"]) . "&sso_id2=" . urlencode($_REQUEST["sso_id"]); // Set the namespace cookie. if (isset($sso_settings[""]["namespacekey2"])) { $namespaces = SSO_LoadNamespaces(true); $namespaces[$sso_apirow->namespace] = $_COOKIE["sso_server_id2"]; $data = serialize($namespaces); $data = base64_encode(Blowfish::CreateDataPacket($data, pack("H*", $sso_settings[""]["namespacekey"]), array("prefix" => $sso_rng->GenerateString(), "mode" => "CBC", "iv" => pack("H*", $sso_settings[""]["namespaceiv"]), "key2" => pack("H*", $sso_settings[""]["namespacekey2"]), "iv2" => pack("H*", $sso_settings[""]["namespaceiv2"]), "lightweight" => true))); SetCookieFixDomain("sso_server_ns", $data, 0, "", "", SSO_IsSSLRequest(), true); } // Set the exposed namespace cookie if the option is enabled. if (isset($sso_settings[""]["expose_namespaces"]) && $sso_settings[""]["expose_namespaces"] && isset($sso_settings[""]["namespacekey4"])) { $namespaces = SSO_LoadNamespaces(false); $namespaces[$sso_apirow->namespace] = $sso_sessionrow2->id; $data = serialize($namespaces); $data = base64_encode(Blowfish::CreateDataPacket($data, pack("H*", $sso_settings[""]["namespacekey3"]), array("prefix" => $sso_rng->GenerateString(), "mode" => "CBC", "iv" => pack("H*", $sso_settings[""]["namespaceiv3"]), "key2" => pack("H*", $sso_settings[""]["namespacekey4"]), "iv2" => pack("H*", $sso_settings[""]["namespaceiv4"]), "lightweight" => true))); $host = str_replace(array("http://", "https://"), "", BB_GetRequestHost()); SetCookieFixDomain("sso_server_ns2", $data, 0, "/", $host, false, true); } // Redirect back to the client. SSO_ExternalRedirect($redirect, true); } catch (Exception $e) { // Don't do anything here. Just catch the database exception and let the code fall through. // It should be nearly impossible to get here in the first place. } return false; }