Store OAuth tokens and more OAuth account info.

Summary:

Test Plan:

Reviewers:

CC:
This commit is contained in:
epriestley
2011-02-22 10:24:49 -08:00
parent 21286a723e
commit 063269a00a
7 changed files with 164 additions and 32 deletions

View File

@@ -0,0 +1,6 @@
alter table phabricator_user.user_oauthinfo add accountURI varchar(255);
alter table phabricator_user.user_oauthinfo add accountName varchar(255);
alter table phabricator_user.user_oauthinfo add token varchar(255);
alter table phabricator_user.user_oauthinfo add tokenExpires int unsigned;
alter table phabricator_user.user_oauthinfo add tokenScope varchar(255);
alter table phabricator_user.user_oauthinfo add tokenStatus varchar(255);

View File

@@ -21,6 +21,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
private $provider; private $provider;
private $userID; private $userID;
private $accessToken; private $accessToken;
private $tokenExpires;
public function shouldRequireLogin() { public function shouldRequireLogin() {
return false; return false;
@@ -91,6 +92,13 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
if (!$token) { if (!$token) {
return $this->buildErrorResponse(new PhabricatorOAuthFailureView()); return $this->buildErrorResponse(new PhabricatorOAuthFailureView());
} }
if (idx($data, 'expires')) {
$this->tokenExpires = time() + $data['expires'];
}
} else {
$this->tokenExpires = $request->getInt('expires');
} }
$userinfo_uri = new PhutilURI($provider->getUserInfoURI()); $userinfo_uri = new PhutilURI($provider->getUserInfoURI());
@@ -148,6 +156,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
'<p>Link your '.$provider_name.' account to your Phabricator '. '<p>Link your '.$provider_name.' account to your Phabricator '.
'account?</p>'); 'account?</p>');
$dialog->addHiddenInput('token', $token); $dialog->addHiddenInput('token', $token);
$dialog->addHiddenInput('expires', $this->tokenExpires);
$dialog->addSubmitButton('Link Accounts'); $dialog->addSubmitButton('Link Accounts');
$dialog->addCancelButton('/settings/page/'.$provider_key.'/'); $dialog->addCancelButton('/settings/page/'.$provider_key.'/');
@@ -156,8 +165,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
$oauth_info = new PhabricatorUserOAuthInfo(); $oauth_info = new PhabricatorUserOAuthInfo();
$oauth_info->setUserID($current_user->getID()); $oauth_info->setUserID($current_user->getID());
$oauth_info->setOAuthProvider($provider_key); $this->configureOAuthInfo($oauth_info);
$oauth_info->setOAuthUID($user_id);
$oauth_info->save(); $oauth_info->save();
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
@@ -170,6 +178,10 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
if ($known_oauth) { if ($known_oauth) {
$known_user = id(new PhabricatorUser())->load($known_oauth->getUserID()); $known_user = id(new PhabricatorUser())->load($known_oauth->getUserID());
$session_key = $known_user->establishSession('web'); $session_key = $known_user->establishSession('web');
$this->configureOAuthInfo($known_oauth);
$known_oauth->save();
$request->setCookie('phusr', $known_user->getUsername()); $request->setCookie('phusr', $known_user->getUsername());
$request->setCookie('phsid', $session_key); $request->setCookie('phsid', $session_key);
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
@@ -184,31 +196,17 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
$known_email = id(new PhabricatorUser()) $known_email = id(new PhabricatorUser())
->loadOneWhere('email = %s', $oauth_email); ->loadOneWhere('email = %s', $oauth_email);
if ($known_email) { if ($known_email) {
$known_oauth = id(new PhabricatorUserOAuthInfo())->loadOneWhere( $dialog = new AphrontDialogView();
'userID = %d AND oauthProvider = %s', $dialog->setUser($current_user);
$known_email->getID(), $dialog->setTitle('Already Linked to Another Account');
$provider->getProviderKey()); $dialog->appendChild(
if ($known_oauth) { '<p>The '.$provider_name.' account you just authorized has an '.
$provider_name = $provider->getName(); 'email address which is already in use by another Phabricator '.
throw new Exception( 'account. To link the accounts, log in to your Phabricator '.
"The email associated with the ".$provider_name." account you ". 'account and then go to Settings.</p>');
"just logged in with is already associated with another ". $dialog->addCancelButton('/login/');
"Phabricator account which is, in turn, associated with a ".
$provider_name." account different from the one you just logged ".
"in with.");
}
$oauth_info = new PhabricatorUserOAuthInfo(); return id(new AphrontDialogResponse())->setDialog($dialog);
$oauth_info->setUserID($known_email->getID());
$oauth_info->setOAuthProvider($provider->getProviderKey());
$oauth_info->setOAuthUID($user_id);
$oauth_info->save();
$session_key = $known_email->establishSession('web');
$request->setCookie('phusr', $known_email->getUsername());
$request->setCookie('phsid', $session_key);
return id(new AphrontRedirectResponse())
->setURI('/');
} }
} }
@@ -279,8 +277,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
$oauth_info = new PhabricatorUserOAuthInfo(); $oauth_info = new PhabricatorUserOAuthInfo();
$oauth_info->setUserID($user->getID()); $oauth_info->setUserID($user->getID());
$oauth_info->setOAuthProvider($provider->getProviderKey()); $this->configureOAuthInfo($oauth_info);
$oauth_info->setOAuthUID($user_id);
$oauth_info->save(); $oauth_info->save();
$session_key = $user->establishSession('web'); $session_key = $user->establishSession('web');
@@ -312,6 +309,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
$form = new AphrontFormView(); $form = new AphrontFormView();
$form $form
->addHiddenInput('token', $token) ->addHiddenInput('token', $token)
->addHiddenInput('expires', $this->tokenExpires)
->setUser($request->getUser()) ->setUser($request->getUser())
->setAction($provider->getRedirectURI()) ->setAction($provider->getRedirectURI())
->appendChild( ->appendChild(
@@ -410,8 +408,45 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
return null; return null;
} }
private function retrieveAccountURI() {
switch ($this->provider->getProviderKey()) {
case PhabricatorOAuthProvider::PROVIDER_FACEBOOK:
return $this->userData['link'];
case PhabricatorOAuthProvider::PROVIDER_GITHUB:
$username = $this->retrieveUsernameSuggestion();
if ($username) {
return 'https://github.com/'.$username;
}
return null;
}
return null;
}
private function retreiveRealNameSuggestion() { private function retreiveRealNameSuggestion() {
return $this->userData['name']; return $this->userData['name'];
} }
private function configureOAuthInfo(PhabricatorUserOAuthInfo $oauth_info) {
$provider = $this->provider;
$oauth_info->setOAuthProvider($provider->getProviderKey());
$oauth_info->setOAuthUID($this->retrieveUserID());
$oauth_info->setAccountURI($this->retrieveAccountURI());
$oauth_info->setAccountName($this->retrieveUserNameSuggestion());
$oauth_info->setToken($this->accessToken);
$oauth_info->setTokenStatus(PhabricatorUserOAuthInfo::TOKEN_STATUS_GOOD);
// If we have out-of-date expiration info, just clear it out. Then replace
// it with good info if the provider gave it to us.
$expires = $oauth_info->getTokenExpires();
if ($expires <= time()) {
$expires = null;
}
if ($this->tokenExpires) {
$expires = $this->tokenExpires;
}
$oauth_info->setTokenExpires($expires);
}
} }

View File

@@ -348,8 +348,15 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
->appendChild( ->appendChild(
id(new AphrontFormStaticControl()) id(new AphrontFormStaticControl())
->setLabel($provider_name.' ID') ->setLabel($provider_name.' ID')
->setValue($oauth_info->getOAuthUID())); ->setValue($oauth_info->getOAuthUID()))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel($provider_name.' Name')
->setValue($oauth_info->getAccountName()))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel($provider_name.' URI')
->setValue($oauth_info->getAccountURI()));
$unlink = 'Unlink '.$provider_name.' Account'; $unlink = 'Unlink '.$provider_name.' Account';
$unlink_form = new AphrontFormView(); $unlink_form = new AphrontFormView();
@@ -363,6 +370,45 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink)); ->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink));
$forms['Unlink Account'] = $unlink_form; $forms['Unlink Account'] = $unlink_form;
$expires = $oauth_info->getTokenExpires();
if ($expires) {
if ($expires <= time()) {
$expires = "Expired";
} else {
$expires = phabricator_format_timestamp($expires);
}
} else {
$expires = 'No Information Available';
}
$scope = $oauth_info->getTokenScope();
if (!$scope) {
$scope = 'No Information Available';
}
$status = $oauth_info->getTokenStatus();
$status = PhabricatorUserOAuthInfo::getReadableTokenStatus($status);
$token_form = new AphrontFormView();
$token_form
->setUser($user)
->appendChild(
'<p class="aphront-from-instructions">insert rap about tokens</p>')
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Token Status')
->setValue($status))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Expires')
->setValue($expires))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Scope')
->setValue($scope));
$forms['Account Token Information'] = $token_form;
} }
$panel = new AphrontPanelView(); $panel = new AphrontPanelView();

View File

@@ -25,6 +25,7 @@ phutil_require_module('phabricator', 'view/form/control/textarea');
phutil_require_module('phabricator', 'view/form/error'); phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel'); phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/layout/sidenav'); phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils'); phutil_require_module('phutil', 'utils');

View File

@@ -18,8 +18,43 @@
class PhabricatorUserOAuthInfo extends PhabricatorUserDAO { class PhabricatorUserOAuthInfo extends PhabricatorUserDAO {
const TOKEN_STATUS_NONE = 'none';
const TOKEN_STATUS_GOOD = 'good';
const TOKEN_STATUS_FAIL = 'fail';
const TOKEN_STATUS_EXPIRED = 'xpyr';
protected $userID; protected $userID;
protected $oauthProvider; protected $oauthProvider;
protected $oauthUID; protected $oauthUID;
protected $accountURI;
protected $accountName;
protected $token;
protected $tokenExpires;
protected $tokenScope;
protected $tokenStatus;
public function getTokenStatus() {
if (!$this->token) {
return self::TOKEN_STATUS_NONE;
}
if ($this->tokenExpires && $this->tokenExpires <= time()) {
return self::TOKEN_STATUS_EXPIRED;
}
return $this->tokenStatus;
}
public static function getReadableTokenStatus($status) {
static $map = array(
self::TOKEN_STATUS_NONE => 'No Token',
self::TOKEN_STATUS_GOOD => 'Token Good',
self::TOKEN_STATUS_FAIL => 'Token Failed',
self::TOKEN_STATUS_EXPIRED => 'Token Expired',
);
return idx($map, $status, 'Unknown');
}
} }

View File

@@ -8,5 +8,7 @@
phutil_require_module('phabricator', 'applications/people/storage/base'); phutil_require_module('phabricator', 'applications/people/storage/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorUserOAuthInfo.php'); phutil_require_source('PhabricatorUserOAuthInfo.php');

View File

@@ -27,8 +27,15 @@ function phabricator_format_relative_time($duration) {
function phabricator_format_timestamp($epoch) { function phabricator_format_timestamp($epoch) {
$difference = (time() - $epoch); $difference = (time() - $epoch);
if ($difference < 0) {
$difference = -$difference;
$relative = 'from now';
} else {
$relative = 'ago';
}
if ($difference < 60 * 60 * 24) { if ($difference < 60 * 60 * 24) {
return phabricator_format_relative_time($difference).' ago'; return phabricator_format_relative_time($difference).' '.$relative;
} else if (date('Y') == date('Y', $epoch)) { } else if (date('Y') == date('Y', $epoch)) {
return date('M j, g:i A', $epoch); return date('M j, g:i A', $epoch);
} else { } else {