@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement "auth.logout" Conduit API method

Summary:
Ref T7303. Ref T7673. This implements an "auth.logout" which:

- terminates all web sessions;
- terminates the current OAuth token if called via OAuth; and
- may always be called via OAuth.

(Since it consumes an OAuth token, even a "malicious" OAuth application can't really be that much of a jerk with this: it can't continuously log you out, since calling the method once kills the token. The application would need to ask your permission again to get a fresh token.)

The primary goal here is to let Phacility instances call this against the Phacility upstream, so that when you log out of an instance it also logs you out of your Phacility account (possibly with a checkbox or something).

This also smooths over the session token code. Before this change, your sessions would get logged out but when you reloaded we'd tell you your session was invalid.

Instead, try to clear the invalid session before telling the user there's an issue. I think that ssentially 100% of invalid sessions are a result of something in this vein (e.g., forced logout via Settings) nowadays, since the session code is generally stable and sane and has been for a long time.

Test Plan:
- Called `auth.logout` via console, got a reasonable logout experience.
- Called `auth.logout` via OAuth.
- Tried to make another call, verified OAuth token had been invalidated.
- Verified web session had been invalidated.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T7303, T7673

Differential Revision: https://secure.phabricator.com/D15594

+89 -6
+2
src/__phutil_library_map__.php
··· 1807 1807 'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php', 1808 1808 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 1809 1809 'PhabricatorAuthLoginHandler' => 'applications/auth/handler/PhabricatorAuthLoginHandler.php', 1810 + 'PhabricatorAuthLogoutConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php', 1810 1811 'PhabricatorAuthMainMenuBarExtension' => 'applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php', 1811 1812 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php', 1812 1813 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', ··· 6149 6150 'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController', 6150 6151 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', 6151 6152 'PhabricatorAuthLoginHandler' => 'Phobject', 6153 + 'PhabricatorAuthLogoutConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod', 6152 6154 'PhabricatorAuthMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 6153 6155 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow', 6154 6156 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
+51
src/applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthLogoutConduitAPIMethod 4 + extends PhabricatorAuthConduitAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'auth.logout'; 8 + } 9 + 10 + public function getMethodSummary() { 11 + return pht('Terminate all login sessions.'); 12 + } 13 + 14 + public function getMethodDescription() { 15 + return pht( 16 + 'Terminate all web login sessions. If called via OAuth, also terminate '. 17 + 'the current OAuth token.'. 18 + "\n\n". 19 + 'WARNING: This method does what it claims on the label. If you call '. 20 + 'this method via the test console in the web UI, it will log you out!'); 21 + } 22 + 23 + protected function defineParamTypes() { 24 + return array(); 25 + } 26 + 27 + protected function defineReturnType() { 28 + return 'void'; 29 + } 30 + 31 + public function getRequiredScope() { 32 + return self::SCOPE_ALWAYS; 33 + } 34 + 35 + protected function execute(ConduitAPIRequest $request) { 36 + $viewer = $request->getUser(); 37 + 38 + // Destroy all web sessions. 39 + $engine = id(new PhabricatorAuthSessionEngine()); 40 + $engine->terminateLoginSessions($viewer); 41 + 42 + // If we were called via OAuth, destroy the OAuth token. 43 + $oauth_token = $request->getOAuthToken(); 44 + if ($oauth_token) { 45 + $oauth_token->delete(); 46 + } 47 + 48 + return null; 49 + } 50 + 51 + }
+23 -6
src/applications/auth/controller/PhabricatorAuthStartController.php
··· 29 29 // it and warn the user they may need to nuke their cookies. 30 30 31 31 $session_token = $request->getCookie(PhabricatorCookies::COOKIE_SESSION); 32 + $did_clear = $request->getStr('cleared'); 32 33 33 34 if (strlen($session_token)) { 34 35 $kind = PhabricatorAuthSessionEngine::getSessionKindFromToken( ··· 39 40 // be logged in, so we can just continue. 40 41 break; 41 42 default: 42 - // The session cookie is invalid, so clear it. 43 + // The session cookie is invalid, so try to clear it. 43 44 $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME); 44 45 $request->clearCookie(PhabricatorCookies::COOKIE_SESSION); 45 46 46 - return $this->renderError( 47 - pht( 48 - 'Your login session is invalid. Try reloading the page and '. 49 - 'logging in again. If that does not work, clear your browser '. 50 - 'cookies.')); 47 + // We've previously tried to clear the cookie but we ended up back 48 + // here, so it didn't work. Hard fatal instead of trying again. 49 + if ($did_clear) { 50 + return $this->renderError( 51 + pht( 52 + 'Your login session is invalid, and clearing the session '. 53 + 'cookie was unsuccessful. Try clearing your browser cookies.')); 54 + } 55 + 56 + $redirect_uri = $request->getRequestURI(); 57 + $redirect_uri->setQueryParam('cleared', 1); 58 + return id(new AphrontRedirectResponse())->setURI($redirect_uri); 51 59 } 60 + } 61 + 62 + // If we just cleared the session cookie and it worked, clean up after 63 + // ourselves by redirecting to get rid of the "cleared" parameter. The 64 + // the workflow will continue normally. 65 + if ($did_clear) { 66 + $redirect_uri = $request->getRequestURI(); 67 + $redirect_uri->setQueryParam('cleared', null); 68 + return id(new AphrontRedirectResponse())->setURI($redirect_uri); 52 69 } 53 70 54 71 $providers = PhabricatorAuthProvider::getAllEnabledProviders();
+2
src/applications/conduit/controller/PhabricatorConduitAPIController.php
··· 395 395 ); 396 396 } 397 397 398 + $api_request->setOAuthToken($token); 399 + 398 400 return $this->validateAuthenticatedUser( 399 401 $api_request, 400 402 $user);
+11
src/applications/conduit/protocol/ConduitAPIRequest.php
··· 5 5 protected $params; 6 6 private $user; 7 7 private $isClusterRequest = false; 8 + private $oauthToken; 8 9 9 10 public function __construct(array $params) { 10 11 $this->params = $params; ··· 46 47 'shouldRequireAuthentication()')); 47 48 } 48 49 return $this->user; 50 + } 51 + 52 + public function setOAuthToken( 53 + PhabricatorOAuthServerAccessToken $oauth_token) { 54 + $this->oauthToken = $oauth_token; 55 + return $this; 56 + } 57 + 58 + public function getOAuthToken() { 59 + return $this->oauthToken; 49 60 } 50 61 51 62 public function setIsClusterRequest($is_cluster_request) {