public function recoverPassword($email, $user) { $fullName = $user['User']['name'] . ' ' . $user['User']['lastname']; $password = trim((string) User::randomPassword()); $Email = new CakeEmail(); $Email->config('smtp'); $Email->from(array('*****@*****.**' => 'bvmjm'))->template('forgot', 'default')->viewVars(array('name' => $fullName, 'password' => $password))->emailFormat('html')->to($email)->subject('bvmjm, Recuperación de Contraseña de Administrador')->send(); $this->data['User']['password'] = $password; $this->save(); }
/** * Given a user object, this method will create a temporary password and save it to the * user's account. Every time this is called, the reset password throttle is reset, which * means the method User::isPasswordReminderThrottled will return true for the next * $wgPasswordReminderResendTime hours * * @param User $targetUser * * @return String * * @throws MWException */ public function resetPassword(User $targetUser) { $context = RequestContext::getMain(); $currentUser = $context->getUser(); $currentIp = $context->getRequest()->getIP(); wfRunHooks('User::mailPasswordInternal', [$currentUser, $currentIp, $targetUser]); $tempPass = $targetUser->randomPassword(); $targetUser->setNewpassword($tempPass, $resetThrottle = true); $targetUser->saveSettings(); return $tempPass; }
static function setupUser() { if (self::$user == NULL) { self::$userName = "******"; self::$passWord = User::randomPassword(); self::$user = User::newFromName(self::$userName); if (!self::$user->getID()) { self::$user = User::createNew(self::$userName, array("password" => self::$passWord, "email" => "*****@*****.**", "real_name" => "Test User")); } else { self::$user->setPassword(self::$passWord); } self::$user->saveSettings(); } }
function __construct($username, $realname = 'Real Name', $email = '*****@*****.**', $groups = array()) { $this->username = $username; $this->realname = $realname; $this->email = $email; $this->groups = $groups; // don't allow user to hardcode or select passwords -- people sometimes run tests // on live wikis. Sometimes we create sysop users in these tests. A sysop user with // a known password would be a Bad Thing. $this->password = User::randomPassword(); $this->user = User::newFromName($this->username); $this->user->load(); // In an ideal world we'd have a new wiki (or mock data store) for every single test. // But for now, we just need to create or update the user with the desired properties. // we particularly need the new password, since we just generated it randomly. // In core MediaWiki, there is no functionality to delete users, so this is the best we can do. if (!$this->user->getID()) { // create the user $this->user = User::createNew($this->username, array("email" => $this->email, "real_name" => $this->realname)); if (!$this->user) { throw new Exception("error creating user"); } } // update the user to use the new random password and other details $this->user->setPassword($this->password); $this->user->setEmail($this->email); $this->user->setRealName($this->realname); // remove all groups, replace with any groups specified foreach ($this->user->getGroups() as $group) { $this->user->removeGroup($group); } if (count($this->groups)) { foreach ($this->groups as $group) { $this->user->addGroup($group); } } $this->user->saveSettings(); }
/** * Test the account creation API with a valid request. Also * make sure the new account can log in and is valid. * * This test does multiple API requests so it might end up being * a bit slow. Raise the default timeout. * @group medium */ public function testValid() { global $wgServer; if (!isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServer to be set in LocalSettings.php'); } $password = User::randomPassword(); $ret = $this->doApiRequest(array('action' => 'createaccount', 'name' => 'Apitestnew', 'password' => $password, 'email' => '*****@*****.**', 'realname' => 'Test Name')); $result = $ret[0]; $this->assertNotInternalType('bool', $result); $this->assertNotInternalType('null', $result['createaccount']); // Should first ask for token. $a = $result['createaccount']; $this->assertEquals('NeedToken', $a['result']); $token = $a['token']; // Finally create the account $ret = $this->doApiRequest(array('action' => 'createaccount', 'name' => 'Apitestnew', 'password' => $password, 'token' => $token, 'email' => '*****@*****.**', 'realname' => 'Test Name'), $ret[2]); $result = $ret[0]; $this->assertNotInternalType('bool', $result); $this->assertEquals('Success', $result['createaccount']['result']); // Try logging in with the new user. $ret = $this->doApiRequest(array('action' => 'login', 'lgname' => 'Apitestnew', 'lgpassword' => $password)); $result = $ret[0]; $this->assertNotInternalType('bool', $result); $this->assertNotInternalType('null', $result['login']); $a = $result['login']['result']; $this->assertEquals('NeedToken', $a); $token = $result['login']['token']; $ret = $this->doApiRequest(array('action' => 'login', 'lgtoken' => $token, 'lgname' => 'Apitestnew', 'lgpassword' => $password), $ret[2]); $result = $ret[0]; $this->assertNotInternalType('bool', $result); $a = $result['login']['result']; $this->assertEquals('Success', $a); // log out to destroy the session $ret = $this->doApiRequest(array('action' => 'logout'), $ret[2]); $this->assertEquals(array(), $ret[0]); }
protected function acceptRequest(IContextSource $context) { global $wgAuth, $wgAccountRequestTypes, $wgConfirmAccountSaveInfo; global $wgAllowAccountRequestFiles, $wgConfirmAccountFSRepos; $accReq = $this->accountReq; // convenience # Now create user and check if the name is valid $user = User::newFromName($this->userName, 'creatable'); if (!$user) { return array('accountconf_invalid_name', wfMsgHtml('noname')); } # Check if account name is already in use if (0 != $user->idForName() || $wgAuth->userExists($user->getName())) { return array('accountconf_user_exists', wfMsgHtml('userexists')); } $dbw = wfGetDB(DB_MASTER); $dbw->begin(); # Make a random password $p = User::randomPassword(); # Insert the new user into the DB... $tokenExpires = $accReq->getEmailTokenExpires(); $authenticated = $accReq->getEmailAuthTimestamp(); $params = array('real_name' => $accReq->getRealName(), 'newpassword' => User::crypt($p), 'email' => $accReq->getEmail(), 'email_authenticated' => $dbw->timestampOrNull($authenticated), 'email_token_expires' => $dbw->timestamp($tokenExpires), 'email_token' => $accReq->getEmailToken()); $user = User::createNew($user->getName(), $params); # Grant any necessary rights (exclude blank or dummy groups) $group = self::getGroupFromType($this->type); if ($group != '' && $group != 'user' && $group != '*') { $user->addGroup($group); } $acd_id = null; // used for rollback cleanup # Save account request data to credentials system if ($wgConfirmAccountSaveInfo) { $key = $accReq->getFileStorageKey(); # Copy any attached files to new storage group if ($wgAllowAccountRequestFiles && $key) { $repoOld = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $repoNew = new FSRepo($wgConfirmAccountFSRepos['accountcreds']); $pathRel = UserAccountRequest::relPathFromKey($key); $oldPath = $repoOld->getZonePath('public') . '/' . $pathRel; $triplet = array($oldPath, 'public', $pathRel); $status = $repoNew->storeBatch(array($triplet)); // copy! if (!$status->isOK()) { $dbw->rollback(); # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback($dbw, $user->getId(), $acd_id); return array('accountconf_copyfailed', $context->getOutput()->parse($status->getWikiText())); } } $acd_id = $dbw->nextSequenceValue('account_credentials_acd_id_seq'); # Move request data into a separate table $dbw->insert('account_credentials', array('acd_user_id' => $user->getID(), 'acd_real_name' => $accReq->getRealName(), 'acd_email' => $accReq->getEmail(), 'acd_email_authenticated' => $dbw->timestampOrNull($authenticated), 'acd_bio' => $accReq->getBio(), 'acd_notes' => $accReq->getNotes(), 'acd_urls' => $accReq->getUrls(), 'acd_ip' => $accReq->getIP(), 'acd_filename' => $accReq->getFileName(), 'acd_storage_key' => $accReq->getFileStorageKey(), 'acd_areas' => $accReq->getAreas('flat'), 'acd_registration' => $dbw->timestamp($accReq->getRegistration()), 'acd_accepted' => $dbw->timestamp(), 'acd_user' => $this->admin->getID(), 'acd_comment' => $this->reason, 'acd_id' => $acd_id), __METHOD__); if (is_null($acd_id)) { $acd_id = $dbw->insertId(); // set $acd_id to ID inserted } } # Add to global user login system (if there is one) if (!$wgAuth->addUser($user, $p, $accReq->getEmail(), $accReq->getRealName())) { $dbw->rollback(); # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback($dbw, $user->getId(), $acd_id); return array('accountconf_externaldberror', wfMsgHtml('externaldberror')); } # OK, now remove the request from the queue $accReq->remove(); # Commit this if we make past the CentralAuth system # and the groups are added. Next step is sending out an # email, which we cannot take back... $dbw->commit(); # Prepare a temporary password email... if ($this->reason != '') { $msg = "confirmaccount-email-body2-pos{$this->type}"; # If the user is in a group and there is a welcome for that group, use it if ($group && !wfEmptyMsg($msg)) { $ebody = wfMsgExt($msg, array('parsemag', 'content'), $user->getName(), $p, $this->reason); # Use standard if none found... } else { $ebody = wfMsgExt('confirmaccount-email-body2', array('parsemag', 'content'), $user->getName(), $p, $this->reason); } } else { $msg = "confirmaccount-email-body-pos{$this->type}"; # If the user is in a group and there is a welcome for that group, use it if ($group && !wfEmptyMsg($msg)) { $ebody = wfMsgExt($msg, array('parsemag', 'content'), $user->getName(), $p, $this->reason); # Use standard if none found... } else { $ebody = wfMsgExt('confirmaccount-email-body', array('parsemag', 'content'), $user->getName(), $p, $this->reason); } } # Actually send out the email (@TODO: rollback on failure including $wgAuth) $result = $user->sendMail(wfMsgForContent('confirmaccount-email-subj'), $ebody); /* if ( !$result->isOk() ) { # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback( $dbw, $user->getId(), $acd_id ); return array( 'accountconf_mailerror', wfMsg( 'mailerror', $context->getOutput()->parse( $result->getWikiText() ) ) ); } */ # Update user count $ssUpdate = new SiteStatsUpdate(0, 0, 0, 0, 1); $ssUpdate->doUpdate(); # Safe to hook/log now... wfRunHooks('AddNewAccount', array($user, false)); $user->addNewUserLogEntry(); # Clear cache for notice of how many account requests there are ConfirmAccount::clearAccountRequestCountCache(); # Delete any attached file and don't stop the whole process if this fails if ($wgAllowAccountRequestFiles) { $key = $accReq->getFileStorageKey(); if ($key) { $repoOld = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $pathRel = UserAccountRequest::relPathFromKey($key); $oldPath = $repoOld->getZonePath('public') . '/' . $pathRel; if (file_exists($oldPath)) { unlink($oldPath); // delete! } } } # Start up the user's userpages if set to do so. # Will not append, so previous content will be blanked. $this->createUserPage($user); # Greet the new user if set to do so. $this->createUserTalkPage($user); return array(true, null); }
/** * @param User $u * @param bool $throttle * @param string $emailTitle Message name of email title * @param string $emailText Message name of email text * @return Status */ function mailPasswordInternal($u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext') { global $wgNewPasswordExpiry; if ($u->getEmail() == '') { return Status::newFatal('noemail', $u->getName()); } $ip = $this->getRequest()->getIP(); if (!$ip) { return Status::newFatal('badipaddress'); } $currentUser = $this->getUser(); Hooks::run('User::mailPasswordInternal', array(&$currentUser, &$ip, &$u)); $np = $u->randomPassword(); $u->setNewpassword($np, $throttle); $u->saveSettings(); $userLanguage = $u->getOption('language'); $mainPage = Title::newMainPage(); $mainPageUrl = $mainPage->getCanonicalURL(); $m = $this->msg($emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>', round($wgNewPasswordExpiry / 86400))->inLanguage($userLanguage)->text(); $result = $u->sendMail($this->msg($emailTitle)->inLanguage($userLanguage)->text(), $m); return $result; }
/** * Create an account, returning a random password */ function createAccount($username, $options) { global $wgDefaultGid, $wgHomeDirectory; $password = User::randomPassword(); $insert = array('pwd_name' => strtolower($username), 'pwd_password' => Md5crypt::encryptPassword($password), 'pwd_password_lastchange' => wfTimestamp(TS_UNIX), 'pwd_gid' => $wgDefaultGid, 'pwd_home' => str_replace('$1', strtolower($username), $wgHomeDirectory)); // $options is something that is passed to user_props $insert['pwd_email'] = $options['email']; $insert['pwd_active'] = $options['active']; // Guess a nice uid. We actually need a lock here $dbw = $this->getDB(DB_MASTER); $row = $dbw->selectRow('passwd', 'MAX(pwd_uid) + 1 AS uid', array(), __METHOD__); $uid = $row->uid; if (function_exists('posix_getpwuid')) { while (posix_getpwuid($uid)) { $uid++; } } $insert['pwd_uid'] = $uid; $dbw->insert('passwd', $insert, __METHOD__); return $password; }
public static function insert($is_btc = false, $bank_account_currency = false, $amount = false, $btc_address = false, $account_number = false) { global $CFG; $bank_account_currency = preg_replace("/[^0-9]/", "", $bank_account_currency); $amount = preg_replace("/[^0-9\\.]/", "", $amount); $account_number = preg_replace("/[^0-9]/", "", $account_number); $btc_address = preg_replace("/[^0-9a-zA-Z]/", '', $btc_address); if (!$CFG->session_active) { return false; } if ($CFG->withdrawals_status == 'suspended') { return false; } $available = User::getAvailable(); if ($is_btc) { if (round($amount, 8) > round($available['BTC'], 8)) { return false; } } else { $currency_info = $CFG->currencies[$bank_account_currency]; if ($amount > $available[$currency_info['currency']]) { return false; } } if ($is_btc) { if ((User::$info['verified_authy'] == 'Y' || User::$info['verified_google'] == 'Y') && User::$info['confirm_withdrawal_2fa_btc'] == 'Y' && !($CFG->token_verified || $CFG->session_api)) { return false; } if ((User::$info['verified_authy'] == 'Y' || User::$info['verified_google'] == 'Y') && User::$info['confirm_withdrawal_2fa_bank'] == 'Y' && !($CFG->token_verified || $CFG->session_api)) { return false; } $status = User::$info['confirm_withdrawal_email_btc'] == 'Y' && !($CFG->token_verified || $CFG->session_api) ? $CFG->request_awaiting_id : $CFG->request_pending_id; $request_id = db_insert('requests', array('date' => date('Y-m-d H:i:s'), 'site_user' => User::$info['id'], 'currency' => $CFG->btc_currency_id, 'amount' => $amount, 'description' => $CFG->withdraw_btc_desc, 'request_status' => $status, 'request_type' => $CFG->request_withdrawal_id, 'send_address' => $btc_address, 'fee' => $CFG->bitcoin_sending_fee, 'net_amount' => $amount - $CFG->bitcoin_sending_fee)); db_insert('history', array('date' => date('Y-m-d H:i:s'), 'ip' => $CFG->client_ip, 'history_action' => $CFG->history_withdraw_id, 'site_user' => User::$info['id'], 'request_id' => $request_id, 'bitcoin_address' => $btc_address, 'balance_before' => User::$info['btc'], 'balance_after' => User::$info['btc'] - $amount)); if (User::$info['confirm_withdrawal_email_btc'] == 'Y' && !($CFG->token_verified || $CFG->session_api) && $request_id > 0) { Status::sumFields(array('pending_withdrawals' => $amount)); $email_token = User::randomPassword(12); $vars = User::$info; $vars['authcode'] = urlencode(Encryption::encrypt($email_token)); $vars['baseurl'] = $CFG->frontend_baseurl; db_update('requests', $request_id, array('email_token' => $email_token)); $email = SiteEmail::getRecord('request-auth'); Email::send($CFG->form_email, User::$info['email'], $email['title'], $CFG->form_email_from, false, $email['content'], $vars); } elseif (User::$info['notify_withdraw_btc'] == 'Y') { $info['amount'] = $amount; $info['currency'] = 'BTC'; $info['first_name'] = User::$info['first_name']; $info['last_name'] = User::$info['last_name']; $info['id'] = $request_id; $email = SiteEmail::getRecord('new-withdrawal'); Email::send($CFG->form_email, User::$info['email'], str_replace('[amount]', $amount, str_replace('[currency]', 'BTC', $email['title'])), $CFG->form_email_from, false, $email['content'], $info); } } else { if ((User::$info['verified_authy'] == 'Y' || User::$info['verified_google'] == 'Y') && User::$info['confirm_withdrawal_2fa_bank'] == 'Y' && !($CFG->token_verified || $CFG->session_api)) { return false; } $amount = round($amount, 2, PHP_ROUND_HALF_UP); $status = User::$info['confirm_withdrawal_email_bank'] == 'Y' && !($CFG->token_verified || $CFG->session_api) ? $CFG->request_awaiting_id : $CFG->request_pending_id; $request_id = db_insert('requests', array('date' => date('Y-m-d H:i:s'), 'site_user' => User::$info['id'], 'currency' => $bank_account_currency, 'amount' => $amount, 'description' => $CFG->withdraw_fiat_desc, 'request_status' => $status, 'request_type' => $CFG->request_withdrawal_id, 'account' => $account_number, 'fee' => $CFG->fiat_withdraw_fee, 'net_amount' => $amount - $CFG->fiat_withdraw_fee)); db_insert('history', array('date' => date('Y-m-d H:i:s'), 'ip' => $CFG->client_ip, 'history_action' => $CFG->history_withdraw_id, 'site_user' => User::$info['id'], 'request_id' => $request_id, 'balance_before' => User::$info[strtolower($currency_info['currency'])], 'balance_after' => User::$info[strtolower($currency_info['currency'])] - $amount)); if (User::$info['confirm_withdrawal_email_bank'] == 'Y' && !($CFG->token_verified || $CFG->session_api) && $request_id > 0) { $vars = User::$info; $email_token = User::randomPassword(12); $vars['authcode'] = urlencode(Encryption::encrypt($email_token)); $vars['baseurl'] = $CFG->frontend_baseurl; db_update('requests', $request_id, array('email_token' => $email_token)); $email = SiteEmail::getRecord('request-auth'); Email::send($CFG->form_email, User::$info['email'], $email['title'], $CFG->form_email_from, false, $email['content'], $vars); } elseif (User::$info['notify_withdraw_bank'] == 'Y') { $info['amount'] = number_format($amount, 2); $info['currency'] = $currency_info['currency']; $info['first_name'] = User::$info['first_name']; $info['last_name'] = User::$info['last_name']; $info['id'] = $request_id; $email = SiteEmail::getRecord('new-withdrawal'); Email::send($CFG->form_email, User::$info['email'], str_replace('[amount]', number_format($amount, 2), str_replace('[currency]', $currency_info['currency'], $email['title'])), $CFG->form_email_from, false, $email['content'], $info); } } if ($request_id && $CFG->memcached) { $CFG->unset_cache['balances'][User::$info['id']] = 2; self::unsetCache(User::$info['id']); } if ($CFG->session_api && $request_id > 0) { $result = self::get(false, false, false, false, false, false, 1, $request_id); return $result[0]; } else { return $request_id; } }
function TuleapMediawikiAuthentication($user, &$result) { global $fusionforgeproject, $wgGroupPermissions; session_set(); if (session_loggedin()) { $tuleap_user = session_get_user(); $group = group_get_object_by_name($fusionforgeproject); $madiawiki_name = ucfirst($tuleap_user->getUnixName()); $mediawiki_user = User::newFromName($madiawiki_name); if ($mediawiki_user->getID() == 0) { $mediawiki_user->addToDatabase(); $mediawiki_user->setPassword(User::randomPassword()); $mediawiki_user->setRealName($tuleap_user->getRealName()); $mediawiki_user->setToken(); $mediawiki_user->loadFromDatabase(); } $user->mId = $mediawiki_user->getID(); $user->loadFromId(); $user = manageMediawikiGroupsForUser($user, $tuleap_user, $group); $user->setCookies(); $user->saveSettings(); wfSetupSession(); } else { $user->logout(); } $result = true; return true; }
/** * Todo: if we are supposed to tie this account to an existing one, create it but don't use it * --> cf _isCreatedFromTwitter --> relation * Unfortunately there doesn't seem to be a way to disable or hide an account programmatically */ private function _createUser( $user, $name, $screen_name ){ global $wgAuth; try { wfDebug( __METHOD__ . ':: created user ' . $screen_name . ' from Twitter' ); $user->addToDatabase(); $user->setRealName($name); if ( $wgAuth->allowPasswordChange() ) $user->setPassword(User::randomPassword()); $user->addGroup('twitter'); //$user->confirmEmail(); $user->setToken(); // store the twitter id in our own table $this->_storeInTable( $user, $screen_name ); // $relation return true; } catch( Exception $e ) { print( $e->getTraceAsString() ); return false; } }
public function actionActive() { $usermodel = new User(); $name = 'message'; $data = $_GET['data']; $data = base64_decode($data); $data = json_decode($data, true); $message = $data['data']; $received_signature = $data['sig']; $private_key = $usermodel->get_private_key_for_public_key($data['pubKey']); $computed_signature = base64_encode(hash_hmac('sha1', $message, $private_key, true)); if ($computed_signature == $received_signature) { $user = User::model()->find("activationkey = ?", array($message)); if (!$user) { Yii::app()->user->setFlash('title', Yii::t('account', 'Invalid path')); } else { if ($user->level == UserPolicy::Guest) { $command = Yii::app()->db->createCommand()->select('capacity_secure,capacity_unsecure')->from('user_levels')->where('id=2')->queryRow(); $user->webspace = $command["capacity_unsecure"]; $user->webspace_secure = $command["capacity_secure"]; $activeKey = $usermodel->randomPassword(32); $user->level = UserPolicy::Member; $user->activationkey = $activeKey; $user->update(array("level", "activationkey", "webspace", "webspace_secure")); $user->refresh(); } CommonHelper::reloadUser(Yii::app()->user->id); Yii::app()->user->setFlash('title', Yii::t('account', 'Member active')); //Yii::app()->user->setFlash('msg', "<strong>".Yii::t("fshare", "Successful active")."</strong>".Yii::t("fshare","<p> Thank you for using our services <br /> <small> Fshare.vn </ small><br /> <small> Return home 10 seconds</ small>")); //$this->redirect(array('site/message')); } } else { Yii::app()->user->setFlash('title', Yii::t('account', 'Invalid path')); } $this->render('message'); }
/** * Load session from user * * At this time here, we can be in two situations. Either we are an * anonymous user (user object here has most likely no name set we assume) * but we also might happen to just be back from our trip to the OAuth * Resource server. * * Documentation says we should read cookies and just pop in that user object * the name coming from the cookies. I expect that just breaks any security * steps we’ve taken so far. * * Since we came from the OAuth Resource server and the user had a successful * authentication exchange, the Request URI should have TWO properties * * - code * - state * * The Code will be used right after to get a bearer token, so, its safe * to assume that we can start that validation here instead than later in the * execution flow. * * If that step was successful, we trust that we already saved * a state object in the Memcache server. Lets use that as a way to check * **before any html has been given to the browser** to validate that user. * * We already might got cookies: * * - (.*)Token, * - (.*)UserID * - (.*)UserName * * Since we already can know expectable data from the resource server, * use this hook as an event handler to actually do the validation. * from our OAuth Resource server, and nothing else should be done * * @param [type] $user [description] * @param [type] $result [description] * @return [type] [description] */ public static function onUserLoadFromSession($user, &$result) { $GLOBALS['poorman_logging'] = array(); $diagnosis['session'] = RequestContext::getMain()->getRequest()->getCookie('_session'); $diagnosis['username'] = RequestContext::getMain()->getRequest()->getCookie('UserName'); $diagnosis['user_id'] = RequestContext::getMain()->getRequest()->getCookie('UserID'); if (isset($_COOKIE['wpdSsoUsername'])) { $diagnosis['wpdSsoUsername'] = $_COOKIE['wpdSsoUsername']; } if (isset($_POST['recoveryPayload'])) { $diagnosis['recoveryPayload'] = $_POST['recoveryPayload']; } //header("X-WebPlatform-Debug: ".substr(str_replace('"','', json_encode($diagnosis,true)),1,-1)); //header("X-WebPlatform-Debug-Cookie: ".substr(str_replace('"','', json_encode($_COOKIE,true)),1,-1)); //if(isset($_POST['recoveryPayload'])){ // header("X-WebPlatform-Debug-Edgecase2: recoveryPayload is present"); //} // Use Native PHP way to check REQUEST params $state_key = isset($_GET['state']) ? $_GET['state'] : null; $code = isset($_GET['code']) ? $_GET['code'] : null; $bearer_token = null; $profile = null; $site_root = str_replace('$1', '', $GLOBALS['wgArticlePath']); //$registeredCookieWithUsername = RequestContext::getMain()->getRequest()->getCookie( 'UserName' ); //$GLOBALS['poorman_logging'][] = 'Registered cookie username: '******'recoveryPayload']) ? $_POST['recoveryPayload'] : null; if (is_string($sessionToken)) { header('Cache-Control: no-store, no-cache, must-revalidate'); // TODO: Do some more validation with this, see // notes at http://docs.webplatform.org/wiki/WPD:Projects/SSO/Improvements_roadmap#Recovering_session_data try { $uri = 'https://profile.accounts.webplatform.org/v1/session/recover'; $client = new Guzzle\Http\Client(); $client->setDefaultOption('timeout', 22); $subreq = $client->get($uri); $subreq->setHeader('Content-type', 'application/json'); $subreq->setHeader('Authorization', 'Session ' . $sessionToken); $r = $client->send($subreq); } catch (Guzzle\Http\Exception\ClientErrorResponseException $e) { $clientErrorStatusCode = $e->getResponse()->getStatusCode(); $clientErrorReason = $e->getResponse()->getReasonPhrase(); // We are considering that wgUser id 0 means anonymous if ($clientErrorStatusCode === 401 && $GLOBALS['wgUser']->getId() !== 0) { $GLOBALS['wgUser']->logout(); header("HTTP/1.1 401 Unauthorized"); header("X-WebPlatform-Outcome-1: Session closed, closing local too"); // 401 AND uid 0 means we have nothing to do } elseif ($clientErrorStatusCode === 401 && $GLOBALS['wgUser']->getId() === 0) { header("HTTP/1.1 204 No Content"); header("X-WebPlatform-Outcome-2: Session closed both local and accounts"); } return true; } catch (Guzzle\Http\Exception\CurlException $e) { header("X-WebPlatform-Outcome-3: CurlException"); header("HTTP/1.1 400 Bad Request"); echo $e->getMessage(); return true; } try { $data = $r->json(); } catch (Exception $e) { header("HTTP/1.1 400 Bad Request"); header("X-WebPlatform-Outcome-4: Profile refused communication"); echo "Profile server refused communication"; return true; } # 20140807 $wgUserName = is_object($GLOBALS['wgUser']) ? $GLOBALS['wgUser']->getName() : null; if (isset($data['username']) && strtolower($wgUserName) === strtolower($data['username'])) { header("X-WebPlatform-Outcome-5: " . strtolower($wgUserName) . " is " . strtolower($data['username'])); header("HTTP/1.1 204 No Content"); return true; // All is good } $tempUser = WebPlatformAuthUserFactory::prepareUser($data); wfSetupSession(); if ($tempUser->getId() === 0) { // No user exists whatsoever, create and make current user $tempUser->ConfirmEmail(); $tempUser->setEmailAuthenticationTimestamp(time()); $tempUser->setPassword(User::randomPassword()); $tempUser->setToken(); $tempUser->setOption("rememberpassword", 0); $tempUser->addToDatabase(); $GLOBALS['poorman_logging'][] = sprintf('User %s created', $tempUser->getName()); } else { // User exist in database, load it $tempUser->loadFromDatabase(); $GLOBALS['poorman_logging'][] = sprintf('Session for %s started', $tempUser->getName()); } $GLOBALS['poorman_logging'][] = $tempUser->getId(); $GLOBALS['wgUser'] = $tempUser; $tempUser->saveSettings(); $tempUser->setCookies(); // Ideally, the first false below should be true! But we need SSL at the top level domain setcookie('wpdSsoUsername', $data['username'], time() + 60 * 60 * 7, '/', '.webplatform.org', false, true); if (isset($_GET['username'])) { header("X-WebPlatform-Username: "******"X-WebPlatform-Recovery: " . urlencode(json_encode($data)) ); header("HTTP/1.0 201 Created"); return true; } if (is_string($state_key) && is_string($code)) { // START IF HAS STATE AND CODE // WE HAVE STATE AND CODE, NOW ARE THEY JUNK? //$GLOBALS['poorman_logging'][] = 'About to retrieve data: '.(($user->isLoggedIn())?'logged in':'not logged in'); // DEBUG // Since we DO have what we need to get // to our validation server, please do not cache. // ... and since WE DIDN’t send any HTML, yet (good boy) // we can actually do that. header('Cache-Control: no-store, no-cache, must-revalidate'); try { $apiHandler = new FirefoxAccountsManager($GLOBALS['wgWebPlatformAuth']); // $code can be used ONLY ONCE! //$GLOBALS['poorman_logging'][] = 'Code: '.print_r($code,1); // DEBUG $bearer_token = $apiHandler->getBearerToken($code); } catch (ClientErrorResponseException $e) { $msg = 'Could not get authorization token'; $GLOBALS['poorman_logging'][] = $msg; $msg .= ', returned after FirefoxAccountsManager::getBearerToken(), it said:' . $e->getMessage(); $obj = json_decode($e->getResponse()->getBody(true), true); $msg .= isset($obj['reason']) ? ', reason: ' . $obj['reason'] : null; $msg .= isset($obj['message']) ? ', message: ' . $obj['message'] : null; error_log($msg); //header('Location: '.$site_root); return true; } catch (Exception $e) { // Other error: e.g. config, or other Guzzle call not expected. $msg = 'Unknown error, Could not get authorization token'; $GLOBALS['poorman_logging'][] = $msg; $msg .= ', returned a "' . get_class($e); $msg .= '" after FirefoxAccountsManager::getBearerToken(), it said: ' . $e->getMessage(); error_log($msg); //header('Location: '.$site_root); return true; } //$GLOBALS['poorman_logging'][] = 'Bearer token: '.print_r($bearer_token,1); // DEBUG // FirefoxAccountsManager::getBearerToken() // returns an array. if (is_array($bearer_token)) { try { $profile = $apiHandler->getProfile($bearer_token); //$GLOBALS['poorman_logging'][] = 'Profile: '.print_r($profile,1); // DEBUG $tempUser = WebPlatformAuthUserFactory::prepareUser($profile); } catch (ClientErrorResponseException $e) { $msg = 'Could not retrieve profile data'; $GLOBALS['poorman_logging'][] = $msg; $msg .= ', returned a "' . get_class($e); $msg .= '" after calling getProfile(), it said: ' . $e->getMessage(); $obj = json_decode($e->getResponse()->getBody(true), true); $msg .= isset($obj['reason']) ? ', with reason: ' . $obj['reason'] : null; $msg .= isset($obj['message']) ? ', message: ' . $obj['message'] : null; error_log($msg); return true; } catch (Exception $e) { $msg = 'Unknown error, Could not get profile data or create new user'; $GLOBALS['poorman_logging'][] = $msg; $msg .= ', returned a "' . get_class($e); $msg .= '" after FirefoxAccountsManager::getProfile(), it said: ' . $e->getMessage(); error_log($msg); return true; } // Note that, HERE, whether we use $GLOBALS['wgUser'] // or $user (passed in this function call from the hook) // or EVEN the one passed to WebPlatformAuthUserFactory::prepareUser() // it should be the same. It is assumed that in prepareUser() it the call // to MW User::loadDefaults($username) makes that binding. // #DOUBLECHECKLATER // Let’s be EXPLICIT // // Note that MW User::isLoggedIn() is not **only** checking // whether the user is logged in per se. But rather do both; // checking if the user exists in the database. Doesn’t mean // the session is bound, yet. wfSetupSession(); if ($tempUser->getId() === 0) { // No user exists whatsoever, create and make current user $tempUser->ConfirmEmail(); $tempUser->setEmailAuthenticationTimestamp(time()); $tempUser->setPassword(User::randomPassword()); $tempUser->setToken(); $tempUser->setOption("rememberpassword", 0); $tempUser->addToDatabase(); $GLOBALS['poorman_logging'][] = sprintf('User %s created', $tempUser->getName()); } else { // User exist in database, load it $tempUser->loadFromDatabase(); $GLOBALS['poorman_logging'][] = sprintf('Session for %s started', $tempUser->getName()); } $GLOBALS['poorman_logging'][] = $tempUser->getId(); $GLOBALS['wgUser'] = $tempUser; $tempUser->saveSettings(); $tempUser->setCookies(); //$GLOBALS['poorman_logging'][] = ($GLOBALS['wgUser']->isLoggedIn())?'logged in':'not logged in'; // DEBUG //$GLOBALS['poorman_logging'][] = $tempUser->getId(); // DEBUG $state_data = $apiHandler->stateRetrieve($state_key); if (is_array($state_data) && isset($state_data['return_to'])) { $apiHandler->stateDeleteKey($state_key); $GLOBALS['poorman_logging'][] = 'State data: ' . print_r($state_data, 1); header('Location: ' . $state_data['return_to']); return true; // Even though it might just be sent elsewhere, making sure. } } else { $GLOBALS['poorman_logging'][] = 'No bearer tokens'; header('Location: ' . $site_root); } } //$GLOBALS['poorman_logging'][] = ($GLOBALS['wgUser']->isLoggedIn())?'logged in':'not logged in'; /** * I can put true or false because we wont be using local authentication * whatsoever. Hopefully that’s the way to do. * * Quoting the doc * * "When the authentication should continue undisturbed * after the hook was executed, do not touch $result. When * the normal authentication should not happen * (e.g., because $user is completely initialized), * set $result to any boolean value." * * -- 2014-05-22 http://www.mediawiki.org/wiki/Manual:Hooks/UserLoadFromSession * * But, if I set $result to either true or false, it doesn’t make the UI to * act as if you are logged in, AT ALL. Even though I created * the user and set it to the global object. I’d like to investigate on why we cannot * set either true or false here because it is unclear what it means undisturbed... we are * creating local users, based on remote data, but authentication implies password, we arent using * local ones, what gives? #DOUBLECHECKLATER */ //$result = false; // Doesn’t matter true or false, and its passed here by-reference. return true; // Hook MUST return true if it was as intended, was it? (hopefully so far) }