diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1807,6 +1807,7 @@ 'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php', 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 'PhabricatorAuthLoginHandler' => 'applications/auth/handler/PhabricatorAuthLoginHandler.php', + 'PhabricatorAuthLogoutConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php', 'PhabricatorAuthMainMenuBarExtension' => 'applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php', 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php', 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', @@ -6149,6 +6150,7 @@ 'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorAuthLoginHandler' => 'Phobject', + 'PhabricatorAuthLogoutConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod', 'PhabricatorAuthMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', diff --git a/src/applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php b/src/applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php @@ -0,0 +1,51 @@ +getUser(); + + // Destroy all web sessions. + $engine = id(new PhabricatorAuthSessionEngine()); + $engine->terminateLoginSessions($viewer); + + // If we were called via OAuth, destroy the OAuth token. + $oauth_token = $request->getOAuthToken(); + if ($oauth_token) { + $oauth_token->delete(); + } + + return null; + } + +} diff --git a/src/applications/auth/controller/PhabricatorAuthStartController.php b/src/applications/auth/controller/PhabricatorAuthStartController.php --- a/src/applications/auth/controller/PhabricatorAuthStartController.php +++ b/src/applications/auth/controller/PhabricatorAuthStartController.php @@ -29,6 +29,7 @@ // it and warn the user they may need to nuke their cookies. $session_token = $request->getCookie(PhabricatorCookies::COOKIE_SESSION); + $did_clear = $request->getStr('cleared'); if (strlen($session_token)) { $kind = PhabricatorAuthSessionEngine::getSessionKindFromToken( @@ -39,18 +40,34 @@ // be logged in, so we can just continue. break; default: - // The session cookie is invalid, so clear it. + // The session cookie is invalid, so try to clear it. $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME); $request->clearCookie(PhabricatorCookies::COOKIE_SESSION); - return $this->renderError( - pht( - 'Your login session is invalid. Try reloading the page and '. - 'logging in again. If that does not work, clear your browser '. - 'cookies.')); + // We've previously tried to clear the cookie but we ended up back + // here, so it didn't work. Hard fatal instead of trying again. + if ($did_clear) { + return $this->renderError( + pht( + 'Your login session is invalid, and clearing the session '. + 'cookie was unsuccessful. Try clearing your browser cookies.')); + } + + $redirect_uri = $request->getRequestURI(); + $redirect_uri->setQueryParam('cleared', 1); + return id(new AphrontRedirectResponse())->setURI($redirect_uri); } } + // If we just cleared the session cookie and it worked, clean up after + // ourselves by redirecting to get rid of the "cleared" parameter. The + // the workflow will continue normally. + if ($did_clear) { + $redirect_uri = $request->getRequestURI(); + $redirect_uri->setQueryParam('cleared', null); + return id(new AphrontRedirectResponse())->setURI($redirect_uri); + } + $providers = PhabricatorAuthProvider::getAllEnabledProviders(); foreach ($providers as $key => $provider) { if (!$provider->shouldAllowLogin()) { diff --git a/src/applications/conduit/controller/PhabricatorConduitAPIController.php b/src/applications/conduit/controller/PhabricatorConduitAPIController.php --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -395,6 +395,8 @@ ); } + $api_request->setOAuthToken($token); + return $this->validateAuthenticatedUser( $api_request, $user); diff --git a/src/applications/conduit/protocol/ConduitAPIRequest.php b/src/applications/conduit/protocol/ConduitAPIRequest.php --- a/src/applications/conduit/protocol/ConduitAPIRequest.php +++ b/src/applications/conduit/protocol/ConduitAPIRequest.php @@ -5,6 +5,7 @@ protected $params; private $user; private $isClusterRequest = false; + private $oauthToken; public function __construct(array $params) { $this->params = $params; @@ -48,6 +49,16 @@ return $this->user; } + public function setOAuthToken( + PhabricatorOAuthServerAccessToken $oauth_token) { + $this->oauthToken = $oauth_token; + return $this; + } + + public function getOAuthToken() { + return $this->oauthToken; + } + public function setIsClusterRequest($is_cluster_request) { $this->isClusterRequest = $is_cluster_request; return $this;