/** * Logs a user in via a vb login and connects them to a facebook account * * Expects post fields for login (only one of the three password fields is strictly required -- * Typically either the password (plain text) or the md5 pair are passed but not both): * * password * * vb_login_md5password * * vb_login_md5password_utf * * username * * auth -- Facebook auth token for FB user to connect to (provide by FB JS SDK) * * If the connection fails then login tokens will not be set and the user will not be logged in even * if the login portion succeeds. * * Will output a JSON object with either a standard error message or {'redirect' : $homepageurl} * @return boolean */ public function actionLoginAndAssociate() { $result = array(); $api = Api_InterfaceAbstract::instance(); //we might not get all of these $password = isset($_POST['password']) ? $_POST['password'] : ''; $vb_login_md5password = isset($_POST['vb_login_md5password']) ? $_POST['vb_login_md5password'] : ''; $vb_login_md5password_utf = isset($_POST['vb_login_md5password_utf']) ? $_POST['vb_login_md5password_utf'] : ''; //login $loginInfo = $api->callApi('user', 'login', array($_POST['username'], $password, $vb_login_md5password, $vb_login_md5password_utf, '')); if ($this->handleErrorsForAjax($result, $response)) { $this->sendAsJson($result); return false; } $api = Api_InterfaceAbstract::instance(); $response = $api->callApi('facebook', 'connectCurrentUser', array('token' => $_POST['auth'])); if ($this->handleErrorsForAjax($result, $response)) { $this->sendAsJson($result); return false; } //don't set the auth cookies until after we have connected the user vB5_Auth::setLoginCookies($loginInfo, '', !empty($_POST['rememberme'])); $homeurl = $api->callApi('route', 'getUrl', array('home', array(), array())); $this->sendAsJson(array('redirect' => $homeurl)); return true; }
public function init() { if ($this->initialized) { return true; } //initialize core $core_path = vB5_Config::instance()->core_path; require_once $core_path . '/vb/vb.php'; vB::init(); $request = new vB_Request_WebApi(); vB::setRequest($request); // When we reach here, there's no user information loaded. What we can do is trying to load language from cookies. // Shouldn't use vB5_User::getLanguageId() as it will try to load userinfo from session $languageid = vB5_Cookie::get('languageid', vB5_Cookie::TYPE_UINT); if ($languageid) { $request->setLanguageid($languageid); } $sessionhash = vB5_Cookie::get('sessionhash', vB5_Cookie::TYPE_STRING); $restoreSessionInfo['userid'] = vB5_Cookie::get('userid', vB5_Cookie::TYPE_STRING); $restoreSessionInfo['remembermetoken'] = vB5_Cookie::get('password', vB5_Cookie::TYPE_STRING); $remembermetokenOrig = $restoreSessionInfo['remembermetoken']; $retry = false; if ($restoreSessionInfo['remembermetoken'] == 'facebook-retry') { $restoreSessionInfo['remembermetoken'] = 'facebook'; $retry = true; } //We normally don't allow the use of the backend classes in the front end, but the //rules are relaxed inside the api class and especially in the bootstrap dance of getting //things set up. Right now getting at the options in the front end is nasty, but I don't //want the backend dealing with cookies if I can help it (among other things it makes //it nasty to handle callers of the backend that don't have cookies). But we need //so information to determine what the cookie name is. This is the least bad way //of handling things. $options = vB::getDatastore()->getValue('options'); if ($options['facebookactive'] and $options['facebookappid']) { //this is not a vB cookie so it doesn't use our prefix -- which the cookie class adds automatically $cookie_name = 'fbsr_' . $options['facebookappid']; $restoreSessionInfo['fb_signed_request'] = isset($_COOKIE[$cookie_name]) ? strval($_COOKIE[$cookie_name]) : ''; } $session = $request->createSessionNew($sessionhash, $restoreSessionInfo); if ($session['sessionhash'] !== $sessionhash) { vB5_Cookie::set('sessionhash', $session['sessionhash'], 0, true); } //redirect to handle a stale FB cookie when doing a FB "remember me". //only do it once to prevent redirect loops -- don't try this with //posts since we'd lose the post data in that case // //Some notes on the JS code (don't want them in the JS inself to avoid //increasing what gets sent to the browser). //1) This code is deliberately designed to avoid using subsystems that // would increase the processing time for something that doesn't need it // (we even avoid initializing JQUERY here). This is the reason it is // inline and not in a template. //2) The code inits the FB system which will create update the cookie // if it is able to validate the user. The cookie is what we are after. // We use getLoginStatus instead of setting status to true because // the latter introduces a race condition were we can do the redirect // before the we've fully initialized and updated the cookie. The // explicit call to getLoginStatus allows us to redirect when the // status is obtained. //3) If we fail to update the cookie we catch that when we try to // create the vb session (which is why we only allow one retry) //4) The JS here should *never* prompt the user, assuming the FB // docs are correct. //5) If the FB version is changed it needs to changed in the // FB library class and the facebook.js file if (strtolower($_SERVER['REQUEST_METHOD']) == 'get' and vB::getCurrentSession()->get('userid') == 0 and $options['facebookactive'] and $options['facebookappid'] and $restoreSessionInfo['remembermetoken'] == 'facebook') { if (!$retry) { //if this isn't a retry, then do a redirect vB5_Auth::setRememberMeCookies('facebook-retry', $restoreSessionInfo['userid']); $fbredirect = "\n\t\t\t\t\t<!DOCTYPE html>\n\t\t\t\t\t<html>\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type='text/javascript' src='//connect.facebook.net/en_US/sdk.js'></script>\n\t\t\t\t\t\t<script type='text/javascript'>\n\t\t\t\t\t\t\tFB.init({\n\t\t\t\t\t\t\t\tappId : '{$options['facebookappid']}',\n\t\t\t\t\t\t\t\tversion : 'v2.2',\n\t\t\t\t\t\t\t\tstatus : false,\n\t\t\t\t\t\t\t\tcookie : true,\n\t\t\t\t\t\t\t\txfbml : false\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tFB.getLoginStatus(function(response)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twindow.top.location.reload(true);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t</script>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body></body>\n\t\t\t\t\t</html>\n\t\t\t\t"; echo $fbredirect; exit; } else { //we tried and failed to log in via FB. That probably means that the user //is logged out of facebook. Let's kill the autolog in so that we stop //trying to connect via FB vB5_Auth::setRememberMeCookies('', ''); } } //if we have an existing token and if we got a token back from the session that is different then we //need to update the token in the browser. We shouldn't get a token back if we didn't pass one in but //we shouldn't depend on that behavior. if ($session['remembermetoken'] and $session['remembermetoken'] != $remembermetokenOrig) { vB5_Auth::setRememberMeCookies($session['remembermetoken'], $restoreSessionInfo['userid']); } // Try to set cpsession hash to session object if exists vB::getCurrentSession()->setCpsessionHash(vB5_Cookie::get('cpsession', vB5_Cookie::TYPE_STRING)); // Update lastvisit/lastactivity $info = vB::getCurrentSession()->doLastVisitUpdate(vB5_Cookie::get('lastvisit', vB5_Cookie::TYPE_UINT), vB5_Cookie::get('lastactivity', vB5_Cookie::TYPE_UINT)); if (!empty($info)) { // for guests we need to set some cookies if (isset($info['lastvisit'])) { vB5_Cookie::set('lastvisit', $info['lastvisit']); } if (isset($info['lastactivity'])) { vB5_Cookie::set('lastactivity', $info['lastactivity']); } } $this->initialized = true; }