Skip to content

Commit c94ef13

Browse files
author
epriestley
committed
Add bin/auth refresh for debugging OAuth token refresh issues
Summary: Ref T2852. Provide a script for inspecting/debugging OAuth token refresh. Test Plan: Ran `bin/auth refresh` with various arguments, saw token refreshes. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2852 Differential Revision: https://secure.phabricator.com/D6276
1 parent b22e52e commit c94ef13

File tree

5 files changed

+161
-3
lines changed

5 files changed

+161
-3
lines changed

scripts/setup/manage_auth.php

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
$workflows = array(
1818
new PhabricatorAuthManagementRecoverWorkflow(),
19+
new PhabricatorAuthManagementRefreshWorkflow(),
1920
new PhabricatorAuthManagementLDAPWorkflow(),
2021
new PhutilHelpArgumentWorkflow(),
2122
);

src/__phutil_library_map__.php

+2
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@
836836
'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php',
837837
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
838838
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
839+
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
839840
'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php',
840841
'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php',
841842
'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php',
@@ -2712,6 +2713,7 @@
27122713
'PhabricatorAuthLoginController' => 'PhabricatorAuthController',
27132714
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
27142715
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
2716+
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
27152717
'PhabricatorAuthManagementWorkflow' => 'PhutilArgumentWorkflow',
27162718
'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController',
27172719
'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
final class PhabricatorAuthManagementRefreshWorkflow
4+
extends PhabricatorAuthManagementWorkflow {
5+
6+
protected function didConstruct() {
7+
$this
8+
->setName('refresh')
9+
->setExamples('**refresh**')
10+
->setSynopsis(
11+
pht(
12+
'Refresh OAuth access tokens. This is primarily useful for '.
13+
'development and debugging.'))
14+
->setArguments(
15+
array(
16+
array(
17+
'name' => 'user',
18+
'param' => 'user',
19+
'help' => 'Refresh tokens for a given user.',
20+
),
21+
array(
22+
'name' => 'type',
23+
'param' => 'provider',
24+
'help' => 'Refresh tokens for a given provider type.',
25+
),
26+
array(
27+
'name' => 'domain',
28+
'param' => 'domain',
29+
'help' => 'Refresh tokens for a given domain.',
30+
),
31+
));
32+
}
33+
34+
public function execute(PhutilArgumentParser $args) {
35+
$console = PhutilConsole::getConsole();
36+
$viewer = PhabricatorUser::getOmnipotentUser();
37+
38+
$query = id(new PhabricatorExternalAccountQuery())
39+
->setViewer($viewer);
40+
41+
$username = $args->getArg('user');
42+
if (strlen($username)) {
43+
$user = id(new PhabricatorPeopleQuery())
44+
->setViewer($viewer)
45+
->withUsernames(array($username))
46+
->executeOne();
47+
if ($user) {
48+
$query->withUserPHIDs(array($user->getPHID()));
49+
} else {
50+
throw new PhutilArgumentUsageException(
51+
pht('No such user "%s"!', $username));
52+
}
53+
}
54+
55+
56+
$type = $args->getArg('type');
57+
if (strlen($type)) {
58+
$query->withAccountTypes(array($type));
59+
}
60+
61+
$domain = $args->getArg('domain');
62+
if (strlen($domain)) {
63+
$query->withAccountDomains(array($domain));
64+
}
65+
66+
$accounts = $query->execute();
67+
68+
if (!$accounts) {
69+
throw new PhutilArgumentUsageException(
70+
pht("No accounts match the arguments!"));
71+
} else {
72+
$console->writeOut(
73+
"%s\n",
74+
pht(
75+
"Found %s accounts to refresh.",
76+
new PhutilNumber(count($accounts))));
77+
}
78+
79+
$providers = PhabricatorAuthProvider::getAllEnabledProviders();
80+
81+
foreach ($accounts as $account) {
82+
$console->writeOut(
83+
"%s\n",
84+
pht(
85+
"Refreshing account #%d (%s/%s).",
86+
$account->getID(),
87+
$account->getAccountType(),
88+
$account->getAccountDomain()));
89+
90+
$key = $account->getProviderKey();
91+
if (empty($providers[$key])) {
92+
$console->writeOut(
93+
"> %s\n",
94+
pht("Skipping, provider is not enabled or does not exist."));
95+
continue;
96+
}
97+
98+
$provider = $providers[$key];
99+
if (!($provider instanceof PhabricatorAuthProviderOAuth)) {
100+
$console->writeOut(
101+
"> %s\n",
102+
pht("Skipping, provider is not an OAuth provider."));
103+
continue;
104+
}
105+
106+
$adapter = $provider->getAdapter();
107+
if (!$adapter->supportsTokenRefresh()) {
108+
$console->writeOut(
109+
"> %s\n",
110+
pht("Skipping, provider does not support token refresh."));
111+
continue;
112+
}
113+
114+
$refresh_token = $account->getProperty('oauth.token.refresh');
115+
if (!$refresh_token) {
116+
$console->writeOut(
117+
"> %s\n",
118+
pht("Skipping, provider has no stored refresh token."));
119+
continue;
120+
}
121+
122+
$console->writeOut(
123+
"+ %s\n",
124+
pht(
125+
"Refreshing token, current token expires in %s seconds.",
126+
new PhutilNumber(
127+
$account->getProperty('oauth.token.access.expires') - time())));
128+
129+
$adapter->refreshAccessToken($refresh_token);
130+
131+
$console->writeOut(
132+
"+ %s\n",
133+
pht(
134+
"Refreshed token, new token expires in %s seconds.",
135+
new PhutilNumber($adapter->getAccessTokenExpires() - time())));
136+
137+
}
138+
139+
$console->writeOut("%s\n", pht("Done."));
140+
141+
return 0;
142+
}
143+
144+
}

src/applications/auth/provider/PhabricatorAuthProviderOAuth.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,20 @@ public function renderConfigPropertyTransactionTitle(
284284
protected function willSaveAccount(PhabricatorExternalAccount $account) {
285285
parent::willSaveAccount($account);
286286

287-
$oauth_token = $this->getAdapter()->getAccessToken();
288-
$account->setProperty('oauth.token', $oauth_token);
287+
$adapter = $this->getAdapter();
288+
289+
$oauth_token = $adapter->getAccessToken();
290+
$account->setProperty('oauth.token.access', $oauth_token);
291+
292+
if ($adapter->supportsTokenRefresh()) {
293+
$refresh_token = $adapter->getRefreshToken();
294+
$account->setProperty('oauth.token.refresh', $refresh_token);
295+
} else {
296+
$account->setProperty('oauth.token.refresh', null);
297+
}
289298

299+
$expires = $adapter->getAccessTokenExpires();
300+
$account->setProperty('oauth.token.access.expires', $expires);
290301
}
291302

292303
}

src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function pullRefs(array $refs) {
3535
// right now so this is currently moot.
3636
$account = head($accounts);
3737

38-
$token = $account->getProperty('oauth.token');
38+
$token = $account->getProperty('oauth.token.access');
3939
if (!$token) {
4040
return;
4141
}

0 commit comments

Comments
 (0)