/** * Returns true if this install is newly setup (i.e., there are no user * accounts yet). In this case, we enter a special mode to permit creation * of the first account form the web UI. */ protected function isFirstTimeSetup() { // If there are any auth providers, this isn't first time setup, even if // we don't have accounts. if (PhabricatorAuthProvider::getAllEnabledProviders()) { return false; } // Otherwise, check if there are any user accounts. If not, we're in first // time setup. $any_users = id(new PhabricatorPeopleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->setLimit(1)->execute(); return !$any_users; }
public function processRequest(AphrontRequest $request) { $viewer = $request->getUser(); $providers = PhabricatorAuthProvider::getAllProviders(); $accounts = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute(); $linked_head = id(new PHUIHeaderView())->setHeader(pht('Linked Accounts and Authentication')); $linked = id(new PHUIObjectItemListView())->setUser($viewer)->setFlush(true)->setNoDataString(pht('You have no linked accounts.')); $login_accounts = 0; foreach ($accounts as $account) { if ($account->isUsableForLogin()) { $login_accounts++; } } foreach ($accounts as $account) { $item = id(new PHUIObjectItemView()); $provider = idx($providers, $account->getProviderKey()); if ($provider) { $item->setHeader($provider->getProviderName()); $can_unlink = $provider->shouldAllowAccountUnlink(); if (!$can_unlink) { $item->addAttribute(pht('Permanently Linked')); } } else { $item->setHeader(pht('Unknown Account ("%s")', $account->getProviderKey())); $can_unlink = true; } $can_login = $account->isUsableForLogin(); if (!$can_login) { $item->addAttribute(pht('Disabled (an administrator has disabled login for this ' . 'account provider).')); } $can_unlink = $can_unlink && (!$can_login || $login_accounts > 1); $can_refresh = $provider && $provider->shouldAllowAccountRefresh(); if ($can_refresh) { $item->addAction(id(new PHUIListItemView())->setIcon('fa-refresh')->setHref('/auth/refresh/' . $account->getProviderKey() . '/')); } $item->addAction(id(new PHUIListItemView())->setIcon('fa-times')->setWorkflow(true)->setDisabled(!$can_unlink)->setHref('/auth/unlink/' . $account->getProviderKey() . '/')); if ($provider) { $provider->willRenderLinkedAccount($viewer, $item, $account); } $linked->addItem($item); } $linkable_head = id(new PHUIHeaderView())->setHeader(pht('Add External Account')); $linkable = id(new PHUIObjectItemListView())->setUser($viewer)->setFlush(true)->setNoDataString(pht('Your account is linked with all available providers.')); $accounts = mpull($accounts, null, 'getProviderKey'); $providers = PhabricatorAuthProvider::getAllEnabledProviders(); $providers = msort($providers, 'getProviderName'); foreach ($providers as $key => $provider) { if (isset($accounts[$key])) { continue; } if (!$provider->shouldAllowAccountLink()) { continue; } $link_uri = '/auth/link/' . $provider->getProviderKey() . '/'; $item = id(new PHUIObjectItemView()); $item->setHeader($provider->getProviderName()); $item->setHref($link_uri); $item->addAction(id(new PHUIListItemView())->setIcon('fa-link')->setHref($link_uri)); $linkable->addItem($item); } $linked_box = id(new PHUIObjectBoxView())->setHeader($linked_head)->setObjectList($linked); $linkable_box = id(new PHUIObjectBoxView())->setHeader($linkable_head)->setObjectList($linkable); return array($linked_box, $linkable_box); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); if ($viewer->isLoggedIn()) { // Kick the user home if they are already logged in. return id(new AphrontRedirectResponse())->setURI('/'); } if ($request->isAjax()) { return $this->processAjaxRequest(); } if ($request->isConduit()) { return $this->processConduitRequest(); } // If the user gets this far, they aren't logged in, so if they have a // user session token we can conclude that it's invalid: if it was valid, // they'd have been logged in above and never made it here. Try to clear // it and warn the user they may need to nuke their cookies. $session_token = $request->getCookie(PhabricatorCookies::COOKIE_SESSION); if (strlen($session_token)) { $kind = PhabricatorAuthSessionEngine::getSessionKindFromToken($session_token); switch ($kind) { case PhabricatorAuthSessionEngine::KIND_ANONYMOUS: // If this is an anonymous session. It's expected that they won't // be logged in, so we can just continue. break; default: // The session cookie is invalid, so 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.')); } } $providers = PhabricatorAuthProvider::getAllEnabledProviders(); foreach ($providers as $key => $provider) { if (!$provider->shouldAllowLogin()) { unset($providers[$key]); } } if (!$providers) { if ($this->isFirstTimeSetup()) { // If this is a fresh install, let the user register their admin // account. return id(new AphrontRedirectResponse())->setURI($this->getApplicationURI('/register/')); } return $this->renderError(pht('This Phabricator install is not configured with any enabled ' . 'authentication providers which can be used to log in. If you ' . 'have accidentally locked yourself out by disabling all providers, ' . 'you can use `%s` to recover access to an administrative account.', 'phabricator/bin/auth recover <username>')); } $next_uri = $request->getStr('next'); if (!strlen($next_uri)) { if ($this->getDelegatingController()) { // Only set a next URI from the request path if this controller was // delegated to, which happens when a user tries to view a page which // requires them to login. // If this controller handled the request directly, we're on the main // login page, and never want to redirect the user back here after they // login. $next_uri = (string) $this->getRequest()->getRequestURI(); } } if (!$request->isFormPost()) { if (strlen($next_uri)) { PhabricatorCookies::setNextURICookie($request, $next_uri); } PhabricatorCookies::setClientIDCookie($request); } if (!$request->getURIData('loggedout') && count($providers) == 1) { $auto_login_provider = head($providers); $auto_login_config = $auto_login_provider->getProviderConfig(); if ($auto_login_provider instanceof PhabricatorPhabricatorAuthProvider && $auto_login_config->getShouldAutoLogin()) { $auto_login_adapter = $provider->getAdapter(); $auto_login_adapter->setState($provider->getAuthCSRFCode($request)); return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($provider->getAdapter()->getAuthenticateURI()); } } $invite = $this->loadInvite(); $not_buttons = array(); $are_buttons = array(); $providers = msort($providers, 'getLoginOrder'); foreach ($providers as $provider) { if ($invite) { $form = $provider->buildInviteForm($this); } else { $form = $provider->buildLoginForm($this); } if ($provider->isLoginFormAButton()) { $are_buttons[] = $form; } else { $not_buttons[] = $form; } } $out = array(); $out[] = $not_buttons; if ($are_buttons) { require_celerity_resource('auth-css'); foreach ($are_buttons as $key => $button) { $are_buttons[$key] = phutil_tag('div', array('class' => 'phabricator-login-button mmb'), $button); } // If we only have one button, add a second pretend button so that we // always have two columns. This makes it easier to get the alignments // looking reasonable. if (count($are_buttons) == 1) { $are_buttons[] = null; } $button_columns = id(new AphrontMultiColumnView())->setFluidLayout(true); $are_buttons = array_chunk($are_buttons, ceil(count($are_buttons) / 2)); foreach ($are_buttons as $column) { $button_columns->addColumn($column); } $out[] = phutil_tag('div', array('class' => 'phabricator-login-buttons'), $button_columns); } $login_message = PhabricatorEnv::getEnvConfig('auth.login-message'); $login_message = phutil_safe_html($login_message); $invite_message = null; if ($invite) { $invite_message = $this->renderInviteHeader($invite); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Login')); $crumbs->setBorder(true); return $this->buildApplicationPage(array($crumbs, $login_message, $invite_message, $out), array('title' => pht('Login to Phabricator'))); }
private function loadDefaultAccount() { $providers = PhabricatorAuthProvider::getAllEnabledProviders(); $account = null; $provider = null; $response = null; foreach ($providers as $key => $candidate_provider) { if (!$candidate_provider->shouldAllowRegistration()) { unset($providers[$key]); continue; } if (!$candidate_provider->isDefaultRegistrationProvider()) { unset($providers[$key]); } } if (!$providers) { $response = $this->renderError(pht('There are no configured default registration providers.')); return array($account, $provider, $response); } else { if (count($providers) > 1) { $response = $this->renderError(pht('There are too many configured default registration providers.')); return array($account, $provider, $response); } } $provider = head($providers); $account = $provider->getDefaultExternalAccount(); return array($account, $provider, $response); }
public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $viewer = $this->getViewer(); $query = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT)); $username = $args->getArg('user'); if (strlen($username)) { $user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withUsernames(array($username))->executeOne(); if ($user) { $query->withUserPHIDs(array($user->getPHID())); } else { throw new PhutilArgumentUsageException(pht('No such user "%s"!', $username)); } } $type = $args->getArg('type'); if (strlen($type)) { $query->withAccountTypes(array($type)); } $domain = $args->getArg('domain'); if (strlen($domain)) { $query->withAccountDomains(array($domain)); } $accounts = $query->execute(); if (!$accounts) { throw new PhutilArgumentUsageException(pht('No accounts match the arguments!')); } else { $console->writeOut("%s\n", pht('Found %s account(s) to refresh.', phutil_count($accounts))); } $providers = PhabricatorAuthProvider::getAllEnabledProviders(); foreach ($accounts as $account) { $console->writeOut("%s\n", pht('Refreshing account #%d (%s/%s).', $account->getID(), $account->getAccountType(), $account->getAccountDomain())); $key = $account->getProviderKey(); if (empty($providers[$key])) { $console->writeOut("> %s\n", pht('Skipping, provider is not enabled or does not exist.')); continue; } $provider = $providers[$key]; if (!$provider instanceof PhabricatorOAuth2AuthProvider) { $console->writeOut("> %s\n", pht('Skipping, provider is not an OAuth2 provider.')); continue; } $adapter = $provider->getAdapter(); if (!$adapter->supportsTokenRefresh()) { $console->writeOut("> %s\n", pht('Skipping, provider does not support token refresh.')); continue; } $refresh_token = $account->getProperty('oauth.token.refresh'); if (!$refresh_token) { $console->writeOut("> %s\n", pht('Skipping, provider has no stored refresh token.')); continue; } $console->writeOut("+ %s\n", pht('Refreshing token, current token expires in %s seconds.', new PhutilNumber($account->getProperty('oauth.token.access.expires') - time()))); $token = $provider->getOAuthAccessToken($account, $force_refresh = true); if (!$token) { $console->writeOut("* %s\n", pht('Unable to refresh token!')); continue; } $console->writeOut("+ %s\n", pht('Refreshed token, new token expires in %s seconds.', new PhutilNumber($account->getProperty('oauth.token.access.expires') - time()))); } $console->writeOut("%s\n", pht('Done.')); return 0; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); if ($viewer->isLoggedIn()) { // Kick the user home if they are already logged in. return id(new AphrontRedirectResponse())->setURI('/'); } if ($request->isAjax()) { return $this->processAjaxRequest(); } if ($request->isConduit()) { return $this->processConduitRequest(); } // If the user gets this far, they aren't logged in, so if they have a // user session token we can conclude that it's invalid: if it was valid, // they'd have been logged in above and never made it here. Try to clear // 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($session_token); switch ($kind) { case PhabricatorAuthSessionEngine::KIND_ANONYMOUS: // If this is an anonymous session. It's expected that they won't // be logged in, so we can just continue. break; default: // The session cookie is invalid, so try to clear it. $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME); $request->clearCookie(PhabricatorCookies::COOKIE_SESSION); // 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()) { unset($providers[$key]); } } if (!$providers) { if ($this->isFirstTimeSetup()) { // If this is a fresh install, let the user register their admin // account. return id(new AphrontRedirectResponse())->setURI($this->getApplicationURI('/register/')); } return $this->renderError(pht('This Phabricator install is not configured with any enabled ' . 'authentication providers which can be used to log in. If you ' . 'have accidentally locked yourself out by disabling all providers, ' . 'you can use `%s` to recover access to an administrative account.', 'phabricator/bin/auth recover <username>')); } $next_uri = $request->getStr('next'); if (!strlen($next_uri)) { if ($this->getDelegatingController()) { // Only set a next URI from the request path if this controller was // delegated to, which happens when a user tries to view a page which // requires them to login. // If this controller handled the request directly, we're on the main // login page, and never want to redirect the user back here after they // login. $next_uri = (string) $this->getRequest()->getRequestURI(); } } if (!$request->isFormPost()) { if (strlen($next_uri)) { PhabricatorCookies::setNextURICookie($request, $next_uri); } PhabricatorCookies::setClientIDCookie($request); } $auto_response = $this->tryAutoLogin($providers); if ($auto_response) { return $auto_response; } $invite = $this->loadInvite(); $not_buttons = array(); $are_buttons = array(); $providers = msort($providers, 'getLoginOrder'); foreach ($providers as $provider) { if ($invite) { $form = $provider->buildInviteForm($this); } else { $form = $provider->buildLoginForm($this); } if ($provider->isLoginFormAButton()) { $are_buttons[] = $form; } else { $not_buttons[] = $form; } } $out = array(); $out[] = $not_buttons; if ($are_buttons) { require_celerity_resource('auth-css'); foreach ($are_buttons as $key => $button) { $are_buttons[$key] = phutil_tag('div', array('class' => 'phabricator-login-button mmb'), $button); } // If we only have one button, add a second pretend button so that we // always have two columns. This makes it easier to get the alignments // looking reasonable. if (count($are_buttons) == 1) { $are_buttons[] = null; } $button_columns = id(new AphrontMultiColumnView())->setFluidLayout(true); $are_buttons = array_chunk($are_buttons, ceil(count($are_buttons) / 2)); foreach ($are_buttons as $column) { $button_columns->addColumn($column); } $out[] = phutil_tag('div', array('class' => 'phabricator-login-buttons'), $button_columns); } $handlers = PhabricatorAuthLoginHandler::getAllHandlers(); $delegating_controller = $this->getDelegatingController(); $header = array(); foreach ($handlers as $handler) { $handler = clone $handler; $handler->setRequest($request); if ($delegating_controller) { $handler->setDelegatingController($delegating_controller); } $header[] = $handler->getAuthLoginHeaderContent(); } $invite_message = null; if ($invite) { $invite_message = $this->renderInviteHeader($invite); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Login')); $crumbs->setBorder(true); $title = pht('Login to Phabricator'); $view = array($header, $invite_message, $out); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }