diff --git a/src/applications/auth/controller/PhabricatorAuthLoginController.php b/src/applications/auth/controller/PhabricatorAuthLoginController.php index 4f957b28a4..2a1ecf97c4 100644 --- a/src/applications/auth/controller/PhabricatorAuthLoginController.php +++ b/src/applications/auth/controller/PhabricatorAuthLoginController.php @@ -1,281 +1,286 @@ extraURIData; } public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->providerKey = $request->getURIData('pkey'); $this->extraURIData = $request->getURIData('extra'); $response = $this->loadProvider(); if ($response) { return $response; } $invite = $this->loadInvite(); $provider = $this->provider; try { list($account, $response) = $provider->processLoginRequest($this); } catch (PhutilAuthUserAbortedException $ex) { if ($viewer->isLoggedIn()) { // If a logged-in user cancels, take them back to the external accounts // panel. $next_uri = '/settings/panel/external/'; } else { // If a logged-out user cancels, take them back to the auth start page. $next_uri = '/'; } // User explicitly hit "Cancel". $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Authentication Canceled')) ->appendChild( pht('You canceled authentication.')) ->addCancelButton($next_uri, pht('Continue')); return id(new AphrontDialogResponse())->setDialog($dialog); } if ($response) { return $response; } if (!$account) { throw new Exception( pht( 'Auth provider failed to load an account from %s!', 'processLoginRequest()')); } if ($account->getUserPHID()) { // The account is already attached to a Phabricator user, so this is // either a login or a bad account link request. if (!$viewer->isLoggedIn()) { if ($provider->shouldAllowLogin()) { return $this->processLoginUser($account); } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow logins on this Phabricator install. '. - 'An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow logins on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } else if ($viewer->getPHID() == $account->getUserPHID()) { // This is either an attempt to re-link an existing and already // linked account (which is silly) or a refresh of an external account // (e.g., an OAuth account). return id(new AphrontRedirectResponse()) ->setURI('/settings/panel/external/'); } else { return $this->renderError( pht( - 'The external account ("%s") you just used to log in is already '. - 'associated with another Phabricator user account. Log in to the '. - 'other Phabricator account and unlink the external account before '. - 'linking it to a new Phabricator account.', - $provider->getProviderName())); + 'The external service ("%s") you just used to log in is already '. + 'associated with another %s user account. Log in to the '. + 'other %s account and unlink the external account before '. + 'linking it to a new %s account.', + $provider->getProviderName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName())); } } else { // The account is not yet attached to a Phabricator user, so this is // either a registration or an account link request. if (!$viewer->isLoggedIn()) { if ($provider->shouldAllowRegistration() || $invite) { return $this->processRegisterUser($account); } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow registration on this Phabricator '. - 'install. An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow registration on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } else { // If the user already has a linked account on this provider, prevent // them from linking a second account. This can happen if they swap // logins and then refresh the account link. // There's no technical reason we can't allow you to link multiple // accounts from a single provider; disallowing this is currently a // product deciison. See T2549. $existing_accounts = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->withProviderConfigPHIDs( array( $provider->getProviderConfigPHID(), )) ->execute(); if ($existing_accounts) { return $this->renderError( pht( - 'Your Phabricator account is already connected to an external '. - 'account on this provider ("%s"), but you are currently logged '. - 'in to the provider with a different account. Log out of the '. + 'Your %s account is already connected to an external '. + 'account on this service ("%s"), but you are currently logged '. + 'in to the service with a different account. Log out of the '. 'external service, then log back in with the correct account '. 'before refreshing the account link.', + PlatformSymbols::getPlatformServerName(), $provider->getProviderName())); } if ($provider->shouldAllowAccountLink()) { return $this->processLinkUser($account); } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow account linking on this Phabricator '. - 'install. An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow account linking on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } } // This should be unreachable, but fail explicitly if we get here somehow. return new Aphront400Response(); } private function processLoginUser(PhabricatorExternalAccount $account) { $user = id(new PhabricatorUser())->loadOneWhere( 'phid = %s', $account->getUserPHID()); if (!$user) { return $this->renderError( pht( 'The external account you just logged in with is not associated '. - 'with a valid Phabricator user.')); + 'with a valid %s user account.', + PlatformSymbols::getPlatformServerName())); } return $this->loginUser($user); } private function processRegisterUser(PhabricatorExternalAccount $account) { $account_secret = $account->getAccountSecret(); $register_uri = $this->getApplicationURI('register/'.$account_secret.'/'); return $this->setAccountKeyAndContinue($account, $register_uri); } private function processLinkUser(PhabricatorExternalAccount $account) { $account_secret = $account->getAccountSecret(); $confirm_uri = $this->getApplicationURI('confirmlink/'.$account_secret.'/'); return $this->setAccountKeyAndContinue($account, $confirm_uri); } private function setAccountKeyAndContinue( PhabricatorExternalAccount $account, $next_uri) { if ($account->getUserPHID()) { throw new Exception(pht('Account is already registered or linked.')); } // Regenerate the registration secret key, set it on the external account, // set a cookie on the user's machine, and redirect them to registration. // See PhabricatorAuthRegisterController for discussion of the registration // key. $registration_key = Filesystem::readRandomCharacters(32); $account->setProperty( 'registrationKey', PhabricatorHash::weakDigest($registration_key)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $account->save(); unset($unguarded); $this->getRequest()->setTemporaryCookie( PhabricatorCookies::COOKIE_REGISTRATION, $registration_key); return id(new AphrontRedirectResponse())->setURI($next_uri); } private function loadProvider() { $provider = PhabricatorAuthProvider::getEnabledProviderByKey( $this->providerKey); if (!$provider) { return $this->renderError( pht( 'The account you are attempting to log in with uses a nonexistent '. 'or disabled authentication provider (with key "%s"). An '. 'administrator may have recently disabled this provider.', $this->providerKey)); } $this->provider = $provider; return null; } protected function renderError($message) { return $this->renderErrorPage( pht('Login Failed'), array($message)); } public function buildProviderPageResponse( PhabricatorAuthProvider $provider, $content) { $crumbs = $this->buildApplicationCrumbs(); $viewer = $this->getViewer(); if ($viewer->isLoggedIn()) { $crumbs->addTextCrumb(pht('Link Account'), $provider->getSettingsURI()); } else { $crumbs->addTextCrumb(pht('Login'), $this->getApplicationURI('start/')); $content = array( $this->newCustomStartMessage(), $content, ); } $crumbs->addTextCrumb($provider->getProviderName()); $crumbs->setBorder(true); return $this->newPage() ->setTitle(pht('Login')) ->setCrumbs($crumbs) ->appendChild($content); } public function buildProviderErrorResponse( PhabricatorAuthProvider $provider, $message) { $message = pht( 'Authentication provider ("%s") encountered an error while attempting '. 'to log in. %s', $provider->getProviderName(), $message); return $this->renderError($message); } } diff --git a/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php b/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php index 259e4c6743..0f86614b19 100644 --- a/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php +++ b/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php @@ -1,250 +1,250 @@ getViewer(); if ($viewer->getIsDisabled()) { // We allowed unapproved and disabled users to hit this controller, but // want to kick out disabled users now. return new Aphront400Response(); } $panels = $this->loadPanels(); $multifactor_key = id(new PhabricatorMultiFactorSettingsPanel()) ->getPanelKey(); $panel_key = $request->getURIData('pageKey'); if (!strlen($panel_key)) { $panel_key = $multifactor_key; } if (!isset($panels[$panel_key])) { return new Aphront404Response(); } $nav = $this->newNavigation(); $nav->selectFilter($panel_key); $panel = $panels[$panel_key]; $viewer->updateMultiFactorEnrollment(); if ($panel_key === $multifactor_key) { $header_text = pht('Add Multi-Factor Auth'); $help = $this->newGuidance(); $panel->setIsEnrollment(true); } else { $header_text = $panel->getPanelName(); $help = null; } $response = $panel ->setController($this) ->setNavigation($nav) ->processRequest($request); if (($response instanceof AphrontResponse) || ($response instanceof AphrontResponseProducerInterface)) { return $response; } $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb(pht('Add Multi-Factor Auth')) ->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader($header_text); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter( array( $help, $response, )); return $this->newPage() ->setTitle(pht('Add Multi-Factor Authentication')) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($view); } private function loadPanels() { $viewer = $this->getViewer(); $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer); $panels = PhabricatorSettingsPanel::getAllDisplayPanels(); $base_uri = $this->newEnrollBaseURI(); $result = array(); foreach ($panels as $key => $panel) { $panel ->setPreferences($preferences) ->setViewer($viewer) ->setUser($viewer) ->setOverrideURI(urisprintf('%s%s/', $base_uri, $key)); if (!$panel->isEnabled()) { continue; } if (!$panel->isUserPanel()) { continue; } if (!$panel->isMultiFactorEnrollmentPanel()) { continue; } if (!empty($result[$key])) { throw new Exception(pht( "Two settings panels share the same panel key ('%s'): %s, %s.", $key, get_class($panel), get_class($result[$key]))); } $result[$key] = $panel; } return $result; } private function newNavigation() { $viewer = $this->getViewer(); $enroll_uri = $this->newEnrollBaseURI(); $nav = id(new AphrontSideNavFilterView()) ->setBaseURI(new PhutilURI($enroll_uri)); $multifactor_key = id(new PhabricatorMultiFactorSettingsPanel()) ->getPanelKey(); $nav->addFilter( $multifactor_key, pht('Enroll in MFA'), null, 'fa-exclamation-triangle blue'); $panels = $this->loadPanels(); if ($panels) { $nav->addLabel(pht('Settings')); } foreach ($panels as $panel_key => $panel) { if ($panel_key === $multifactor_key) { continue; } $nav->addFilter( $panel->getPanelKey(), $panel->getPanelName(), null, $panel->getPanelMenuIcon()); } return $nav; } private function newEnrollBaseURI() { return $this->getApplicationURI('enroll/'); } private function newGuidance() { $viewer = $this->getViewer(); if ($viewer->getIsEnrolledInMultiFactor()) { $guidance = pht( '{icon check, color="green"} **Setup Complete!**'. "\n\n". 'You have successfully configured multi-factor authentication '. 'for your account.'. "\n\n". 'You can make adjustments from the [[ /settings/ | Settings ]] panel '. 'later.'); return $this->newDialog() ->setTitle(pht('Multi-Factor Authentication Setup Complete')) ->setWidth(AphrontDialogView::WIDTH_FULL) ->appendChild(new PHUIRemarkupView($viewer, $guidance)) ->addCancelButton('/', pht('Continue')); } $views = array(); $messages = array(); $messages[] = pht( - 'Before you can use Phabricator, you need to add multi-factor '. + 'Before you can use this software, you need to add multi-factor '. 'authentication to your account. Multi-factor authentication helps '. 'secure your account by making it more difficult for attackers to '. 'gain access or take sensitive actions.'); $view = id(new PHUIInfoView()) ->setTitle(pht('Add Multi-Factor Authentication To Your Account')) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setErrors($messages); $views[] = $view; $providers = id(new PhabricatorAuthFactorProviderQuery()) ->setViewer($viewer) ->withStatuses( array( PhabricatorAuthFactorProviderStatus::STATUS_ACTIVE, )) ->execute(); if (!$providers) { $messages = array(); $required_key = 'security.require-multi-factor-auth'; $messages[] = pht( 'This install has the configuration option "%s" enabled, but does '. 'not have any active multifactor providers configured. This means '. 'you are required to add MFA, but are also prevented from doing so. '. 'An administrator must disable "%s" or enable an MFA provider to '. 'allow you to continue.', $required_key, $required_key); $view = id(new PHUIInfoView()) ->setTitle(pht('Multi-Factor Authentication is Misconfigured')) ->setSeverity(PHUIInfoView::SEVERITY_ERROR) ->setErrors($messages); $views[] = $view; } return $views; } } diff --git a/src/applications/auth/controller/PhabricatorAuthSetExternalController.php b/src/applications/auth/controller/PhabricatorAuthSetExternalController.php index 51dfcab53f..8b0a44b9dc 100644 --- a/src/applications/auth/controller/PhabricatorAuthSetExternalController.php +++ b/src/applications/auth/controller/PhabricatorAuthSetExternalController.php @@ -1,110 +1,111 @@ getViewer(); $configs = id(new PhabricatorAuthProviderConfigQuery()) ->setViewer($viewer) ->withIsEnabled(true) ->execute(); $linkable = array(); foreach ($configs as $config) { if (!$config->getShouldAllowLink()) { continue; } // For now, only buttons get to appear here: for example, we can't // reasonably embed an entire LDAP form into this UI. $provider = $config->getProvider(); if (!$provider->isLoginFormAButton()) { continue; } $linkable[] = $config; } if (!$linkable) { return $this->newDialog() ->setTitle(pht('No Linkable External Providers')) ->appendParagraph( pht( 'Currently, there are no configured external auth providers '. 'which you can link your account to.')) ->addCancelButton('/'); } $text = PhabricatorAuthMessage::loadMessageText( $viewer, PhabricatorAuthLinkMessageType::MESSAGEKEY); if (!strlen($text)) { $text = pht( - 'You can link your Phabricator account to an external account to '. + 'You can link your %s account to an external account to '. 'allow you to log in more easily in the future. To continue, choose '. 'an account to link below. If you prefer not to link your account, '. - 'you can skip this step.'); + 'you can skip this step.', + PlatformSymbols::getPlatformServerName()); } $remarkup_view = new PHUIRemarkupView($viewer, $text); $remarkup_view = phutil_tag( 'div', array( 'class' => 'phui-object-box-instructions', ), $remarkup_view); PhabricatorCookies::setClientIDCookie($request); $view = array(); foreach ($configs as $config) { $provider = $config->getProvider(); $form = $provider->buildLinkForm($this); if ($provider->isLoginFormAButton()) { require_celerity_resource('auth-css'); $form = phutil_tag( 'div', array( 'class' => 'phabricator-link-button pl', ), $form); } $view[] = $form; } $form = id(new AphrontFormView()) ->setViewer($viewer) ->appendControl( id(new AphrontFormSubmitControl()) ->addCancelButton('/', pht('Skip This Step'))); $header = id(new PHUIHeaderView()) ->setHeader(pht('Link External Account')); $box = id(new PHUIObjectBoxView()) ->setViewer($viewer) ->setHeader($header) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($remarkup_view) ->appendChild($view) ->appendChild($form); $main_view = id(new PHUITwoColumnView()) ->setFooter($box); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb(pht('Link External Account')) ->setBorder(true); return $this->newPage() ->setTitle(pht('Link External Account')) ->setCrumbs($crumbs) ->appendChild($main_view); } } diff --git a/src/applications/auth/controller/PhabricatorAuthStartController.php b/src/applications/auth/controller/PhabricatorAuthStartController.php index 0c42f53556..5789740e14 100644 --- a/src/applications/auth/controller/PhabricatorAuthStartController.php +++ b/src/applications/auth/controller/PhabricatorAuthStartController.php @@ -1,340 +1,340 @@ 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->replaceQueryParam('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->removeQueryParam('cleared'); return id(new AphrontRedirectResponse())->setURI($redirect_uri); } $providers = PhabricatorAuthProvider::getAllEnabledProviders(); foreach ($providers as $key => $provider) { if (!$provider->shouldAllowLogin()) { unset($providers[$key]); } } $configs = array(); foreach ($providers as $provider) { $configs[] = $provider->getProviderConfig(); } 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 account.', - 'phabricator/bin/auth recover ')); + 'This server 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 account.', + './bin/auth recover ')); } $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); } $invite_message = null; if ($invite) { $invite_message = $this->renderInviteHeader($invite); } $custom_message = $this->newCustomStartMessage(); $email_login = $this->newEmailLoginView($configs); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Login')); $crumbs->setBorder(true); $title = pht('Login'); $view = array( $invite_message, $custom_message, $out, $email_login, ); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view); } private function processAjaxRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); // We end up here if the user clicks a workflow link that they need to // login to use. We give them a dialog saying "You need to login...". if ($request->isDialogFormPost()) { return id(new AphrontRedirectResponse())->setURI( $request->getRequestURI()); } // Often, users end up here by clicking a disabled action link in the UI // (for example, they might click "Edit Subtasks" on a Maniphest task // page). After they log in we want to send them back to that main object // page if we can, since it's confusing to end up on a standalone page with // only a dialog (particularly if that dialog is another error, // like a policy exception). $via_header = AphrontRequest::getViaHeaderName(); $via_uri = AphrontRequest::getHTTPHeader($via_header); if (strlen($via_uri)) { PhabricatorCookies::setNextURICookie($request, $via_uri, $force = true); } return $this->newDialog() ->setTitle(pht('Login Required')) ->appendParagraph(pht('You must log in to take this action.')) ->addSubmitButton(pht('Log In')) ->addCancelButton('/'); } private function processConduitRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); // A common source of errors in Conduit client configuration is getting // the request path wrong. The client will end up here, so make some // effort to give them a comprehensible error message. $request_path = $this->getRequest()->getPath(); $conduit_path = '/api/'; $example_path = '/api/conduit.ping'; $message = pht( 'ERROR: You are making a Conduit API request to "%s", but the correct '. 'HTTP request path to use in order to access a Conduit method is "%s" '. '(for example, "%s"). Check your configuration.', $request_path, $conduit_path, $example_path); return id(new AphrontPlainTextResponse())->setContent($message); } protected function renderError($message) { return $this->renderErrorPage( pht('Authentication Failure'), array($message)); } private function tryAutoLogin(array $providers) { $request = $this->getRequest(); // If the user just logged out, don't immediately log them in again. if ($request->getURIData('loggedout')) { return null; } // If we have more than one provider, we can't autologin because we // don't know which one the user wants. if (count($providers) != 1) { return null; } $provider = head($providers); if (!$provider->supportsAutoLogin()) { return null; } $config = $provider->getProviderConfig(); if (!$config->getShouldAutoLogin()) { return null; } $auto_uri = $provider->getAutoLoginURI($request); return id(new AphrontRedirectResponse()) ->setIsExternal(true) ->setURI($auto_uri); } private function newEmailLoginView(array $configs) { assert_instances_of($configs, 'PhabricatorAuthProviderConfig'); // Check if password auth is enabled. If it is, the password login form // renders a "Forgot password?" link, so we don't need to provide a // supplemental link. $has_password = false; foreach ($configs as $config) { $provider = $config->getProvider(); if ($provider instanceof PhabricatorPasswordAuthProvider) { $has_password = true; } } if ($has_password) { return null; } $view = array( pht('Trouble logging in?'), ' ', phutil_tag( 'a', array( 'href' => '/login/email/', ), pht('Send a login link to your email address.')), ); return phutil_tag( 'div', array( 'class' => 'auth-custom-message', ), $view); } } diff --git a/src/applications/auth/controller/PhabricatorAuthUnlinkController.php b/src/applications/auth/controller/PhabricatorAuthUnlinkController.php index ede9d9d94a..a4843a7ccd 100644 --- a/src/applications/auth/controller/PhabricatorAuthUnlinkController.php +++ b/src/applications/auth/controller/PhabricatorAuthUnlinkController.php @@ -1,141 +1,141 @@ getViewer(); $id = $request->getURIData('id'); $account = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$account) { return new Aphront404Response(); } $done_uri = '/settings/panel/external/'; $config = $account->getProviderConfig(); $provider = $config->getProvider(); if (!$provider->shouldAllowAccountUnlink()) { return $this->renderNotUnlinkableErrorDialog($provider, $done_uri); } $confirmations = $request->getStrList('confirmations'); $confirmations = array_fuse($confirmations); if (!$request->isFormOrHisecPost() || !isset($confirmations['unlink'])) { return $this->renderConfirmDialog($confirmations, $config, $done_uri); } // Check that this account isn't the only account which can be used to // login. We warn you when you remove your only login account. if ($account->isUsableForLogin()) { $other_accounts = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->execute(); $valid_accounts = 0; foreach ($other_accounts as $other_account) { if ($other_account->isUsableForLogin()) { $valid_accounts++; } } if ($valid_accounts < 2) { if (!isset($confirmations['only'])) { return $this->renderOnlyUsableAccountConfirmDialog( $confirmations, $done_uri); } } } $workflow_key = sprintf( 'account.unlink(%s)', $account->getPHID()); $hisec_token = id(new PhabricatorAuthSessionEngine()) ->setWorkflowKey($workflow_key) ->requireHighSecurityToken($viewer, $request, $done_uri); $account->unlinkAccount(); id(new PhabricatorAuthSessionEngine())->terminateLoginSessions( $viewer, new PhutilOpaqueEnvelope( $request->getCookie(PhabricatorCookies::COOKIE_SESSION))); return id(new AphrontRedirectResponse())->setURI($done_uri); } private function renderNotUnlinkableErrorDialog( PhabricatorAuthProvider $provider, $done_uri) { return $this->newDialog() ->setTitle(pht('Permanent Account Link')) ->appendChild( pht( 'You can not unlink this account because the administrator has '. - 'configured Phabricator to make links to "%s" accounts permanent.', + 'configured this server to make links to "%s" accounts permanent.', $provider->getProviderName())) ->addCancelButton($done_uri); } private function renderOnlyUsableAccountConfirmDialog( array $confirmations, $done_uri) { $confirmations[] = 'only'; return $this->newDialog() ->setTitle(pht('Unlink Your Only Login Account?')) ->addHiddenInput('confirmations', implode(',', $confirmations)) ->appendParagraph( pht( 'This is the only external login account linked to your Phabicator '. 'account. If you remove it, you may no longer be able to log in.')) ->appendParagraph( pht( 'If you lose access to your account, you can recover access by '. 'sending yourself an email login link from the login screen.')) ->addCancelButton($done_uri) ->addSubmitButton(pht('Unlink External Account')); } private function renderConfirmDialog( array $confirmations, PhabricatorAuthProviderConfig $config, $done_uri) { $confirmations[] = 'unlink'; $provider = $config->getProvider(); $title = pht('Unlink "%s" Account?', $provider->getProviderName()); $body = pht( 'You will no longer be able to use your %s account to '. - 'log in to Phabricator.', + 'log in.', $provider->getProviderName()); return $this->newDialog() ->setTitle($title) ->addHiddenInput('confirmations', implode(',', $confirmations)) ->appendParagraph($body) ->appendParagraph( pht( 'Note: Unlinking an authentication provider will terminate any '. 'other active login sessions.')) ->addSubmitButton(pht('Unlink Account')) ->addCancelButton($done_uri); } } diff --git a/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php b/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php index bf3410139d..2f15460eac 100644 --- a/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php +++ b/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php @@ -1,63 +1,62 @@ getViewer(); $email = $viewer->loadPrimaryEmail(); if ($viewer->getIsEmailVerified()) { return id(new AphrontRedirectResponse())->setURI('/'); } $email_address = $email->getAddress(); $sent = null; if ($request->isFormPost()) { $email->sendVerificationEmail($viewer); $sent = new PHUIInfoView(); $sent->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $sent->setTitle(pht('Email Sent')); $sent->appendChild( pht( 'Another verification email was sent to %s.', phutil_tag('strong', array(), $email_address))); } $must_verify = pht( 'You must verify your email address to log in. You should have a '. - 'new email message from Phabricator with verification instructions '. - 'in your inbox (%s).', + 'new email message with verification instructions in your inbox (%s).', phutil_tag('strong', array(), $email_address)); $send_again = pht( 'If you did not receive an email, you can click the button below '. 'to try sending another one.'); $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Check Your Email')) ->appendParagraph($must_verify) ->appendParagraph($send_again) ->addSubmitButton(pht('Send Another Email')); $view = array( $sent, $dialog, ); return $this->newPage() ->setTitle(pht('Must Verify Email')) ->appendChild($view); } } diff --git a/src/applications/auth/controller/config/PhabricatorAuthDisableController.php b/src/applications/auth/controller/config/PhabricatorAuthDisableController.php index 252f159ec4..15b5461186 100644 --- a/src/applications/auth/controller/config/PhabricatorAuthDisableController.php +++ b/src/applications/auth/controller/config/PhabricatorAuthDisableController.php @@ -1,89 +1,89 @@ requireApplicationCapability( AuthManageProvidersCapability::CAPABILITY); $viewer = $this->getViewer(); $config_id = $request->getURIData('id'); $action = $request->getURIData('action'); $config = id(new PhabricatorAuthProviderConfigQuery()) ->setViewer($viewer) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->withIDs(array($config_id)) ->executeOne(); if (!$config) { return new Aphront404Response(); } $is_enable = ($action === 'enable'); $done_uri = $config->getURI(); if ($request->isDialogFormPost()) { $xactions = array(); $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_ENABLE) ->setNewValue((int)$is_enable); $editor = id(new PhabricatorAuthProviderConfigEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->applyTransactions($config, $xactions); return id(new AphrontRedirectResponse())->setURI($done_uri); } if ($is_enable) { $title = pht('Enable Provider?'); if ($config->getShouldAllowRegistration()) { $body = pht( 'Do you want to enable this provider? Users will be able to use '. - 'their existing external accounts to register new Phabricator '. - 'accounts and log in using linked accounts.'); + 'their existing external accounts to register new accounts and '. + 'log in using linked accounts.'); } else { $body = pht( 'Do you want to enable this provider? Users will be able to log '. - 'in to Phabricator using linked accounts.'); + 'in using linked accounts.'); } $button = pht('Enable Provider'); } else { // TODO: We could tailor this a bit more. In particular, we could // check if this is the last provider and either prevent if from // being disabled or force the user through like 35 prompts. We could // also check if it's the last provider linked to the acting user's // account and pop a warning like "YOU WILL NO LONGER BE ABLE TO LOGIN // YOU GOOF, YOU PROBABLY DO NOT MEAN TO DO THIS". None of this is // critical and we can wait to see how users manage to shoot themselves // in the feet. // `bin/auth` can recover from these types of mistakes. $title = pht('Disable Provider?'); $body = pht( 'Do you want to disable this provider? Users will not be able to '. 'register or log in using linked accounts. If there are any users '. 'without other linked authentication mechanisms, they will no longer '. 'be able to log in. If you disable all providers, no one will be '. 'able to log in.'); $button = pht('Disable Provider'); } return $this->newDialog() ->setTitle($title) ->appendChild($body) ->addCancelButton($done_uri) ->addSubmitButton($button); } } diff --git a/src/applications/auth/controller/config/PhabricatorAuthEditController.php b/src/applications/auth/controller/config/PhabricatorAuthEditController.php index f602c4fb24..693fc5bffd 100644 --- a/src/applications/auth/controller/config/PhabricatorAuthEditController.php +++ b/src/applications/auth/controller/config/PhabricatorAuthEditController.php @@ -1,398 +1,397 @@ requireApplicationCapability( AuthManageProvidersCapability::CAPABILITY); $viewer = $this->getViewer(); $provider_class = $request->getStr('provider'); $config_id = $request->getURIData('id'); if ($config_id) { $config = id(new PhabricatorAuthProviderConfigQuery()) ->setViewer($viewer) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->withIDs(array($config_id)) ->executeOne(); if (!$config) { return new Aphront404Response(); } $provider = $config->getProvider(); if (!$provider) { return new Aphront404Response(); } $is_new = false; } else { $provider = null; $providers = PhabricatorAuthProvider::getAllBaseProviders(); foreach ($providers as $candidate_provider) { if (get_class($candidate_provider) === $provider_class) { $provider = $candidate_provider; break; } } if (!$provider) { return new Aphront404Response(); } // TODO: When we have multi-auth providers, support them here. $configs = id(new PhabricatorAuthProviderConfigQuery()) ->setViewer($viewer) ->withProviderClasses(array(get_class($provider))) ->execute(); if ($configs) { $id = head($configs)->getID(); $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setMethod('GET') ->setSubmitURI($this->getApplicationURI('config/edit/'.$id.'/')) ->setTitle(pht('Provider Already Configured')) ->appendChild( pht( 'This provider ("%s") already exists, and you can not add more '. 'than one instance of it. You can edit the existing provider, '. 'or you can choose a different provider.', $provider->getProviderName())) ->addCancelButton($this->getApplicationURI('config/new/')) ->addSubmitButton(pht('Edit Existing Provider')); return id(new AphrontDialogResponse())->setDialog($dialog); } $config = $provider->getDefaultProviderConfig(); $provider->attachProviderConfig($config); $is_new = true; } $errors = array(); $validation_exception = null; $v_login = $config->getShouldAllowLogin(); $v_registration = $config->getShouldAllowRegistration(); $v_link = $config->getShouldAllowLink(); $v_unlink = $config->getShouldAllowUnlink(); $v_trust_email = $config->getShouldTrustEmails(); $v_auto_login = $config->getShouldAutoLogin(); if ($request->isFormPost()) { $properties = $provider->readFormValuesFromRequest($request); list($errors, $issues, $properties) = $provider->processEditForm( $request, $properties); $xactions = array(); if (!$errors) { if ($is_new) { if (!strlen($config->getProviderType())) { $config->setProviderType($provider->getProviderType()); } if (!strlen($config->getProviderDomain())) { $config->setProviderDomain($provider->getProviderDomain()); } } $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_LOGIN) ->setNewValue($request->getInt('allowLogin', 0)); $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_REGISTRATION) ->setNewValue($request->getInt('allowRegistration', 0)); $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_LINK) ->setNewValue($request->getInt('allowLink', 0)); $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_UNLINK) ->setNewValue($request->getInt('allowUnlink', 0)); $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_TRUST_EMAILS) ->setNewValue($request->getInt('trustEmails', 0)); if ($provider->supportsAutoLogin()) { $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_AUTO_LOGIN) ->setNewValue($request->getInt('autoLogin', 0)); } foreach ($properties as $key => $value) { $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) ->setTransactionType( PhabricatorAuthProviderConfigTransaction::TYPE_PROPERTY) ->setMetadataValue('auth:property', $key) ->setNewValue($value); } if ($is_new) { $config->save(); } $editor = id(new PhabricatorAuthProviderConfigEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($config, $xactions); $next_uri = $config->getURI(); return id(new AphrontRedirectResponse())->setURI($next_uri); } catch (Exception $ex) { $validation_exception = $ex; } } } else { $properties = $provider->readFormValuesFromProvider(); $issues = array(); } if ($is_new) { if ($provider->hasSetupStep()) { $button = pht('Next Step'); } else { $button = pht('Add Provider'); } $crumb = pht('Add Provider'); $title = pht('Add Auth Provider'); $header_icon = 'fa-plus-square'; $cancel_uri = $this->getApplicationURI('/config/new/'); } else { $button = pht('Save'); $crumb = pht('Edit Provider'); $title = pht('Edit Auth Provider'); $header_icon = 'fa-pencil'; $cancel_uri = $config->getURI(); } $header = id(new PHUIHeaderView()) ->setHeader(pht('%s: %s', $title, $provider->getProviderName())) ->setHeaderIcon($header_icon); if (!$is_new) { if ($config->getIsEnabled()) { $status_name = pht('Enabled'); $status_color = 'green'; $status_icon = 'fa-check'; $header->setStatus($status_icon, $status_color, $status_name); } else { $status_name = pht('Disabled'); $status_color = 'indigo'; $status_icon = 'fa-ban'; $header->setStatus($status_icon, $status_color, $status_name); } } $config_name = 'auth.email-domains'; $config_href = '/config/edit/'.$config_name.'/'; $email_domains = PhabricatorEnv::getEnvConfig($config_name); if ($email_domains) { $registration_warning = pht( 'Users will only be able to register with a verified email address '. 'at one of the configured [[ %s | %s ]] domains: **%s**', $config_href, $config_name, implode(', ', $email_domains)); } else { $registration_warning = pht( "NOTE: Any user who can browse to this install's login page will be ". - "able to register a Phabricator account. To restrict who can register ". + "able to register an account. To restrict who can register ". "an account, configure [[ %s | %s ]].", $config_href, $config_name); } $str_login = array( phutil_tag('strong', array(), pht('Allow Login:')), ' ', pht( 'Allow users to log in using this provider. If you disable login, '. 'users can still use account integrations for this provider.'), ); $str_registration = array( phutil_tag('strong', array(), pht('Allow Registration:')), ' ', pht( - 'Allow users to register new Phabricator accounts using this '. - 'provider. If you disable registration, users can still use this '. - 'provider to log in to existing accounts, but will not be able to '. - 'create new accounts.'), + 'Allow users to register new accounts using this provider. If you '. + 'disable registration, users can still use this provider to log in '. + 'to existing accounts, but will not be able to create new accounts.'), ); $str_link = hsprintf( '%s: %s', pht('Allow Linking Accounts'), pht( 'Allow users to link account credentials for this provider to '. - 'existing Phabricator accounts. There is normally no reason to '. - 'disable this unless you are trying to move away from a provider '. - 'and want to stop users from creating new account links.')); + 'existing accounts. There is normally no reason to disable this '. + 'unless you are trying to move away from a provider and want to '. + 'stop users from creating new account links.')); $str_unlink = hsprintf( '%s: %s', pht('Allow Unlinking Accounts'), pht( 'Allow users to unlink account credentials for this provider from '. - 'existing Phabricator accounts. If you disable this, Phabricator '. - 'accounts will be permanently bound to provider accounts.')); + 'existing accounts. If you disable this, accounts will be '. + 'permanently bound to provider accounts.')); $str_trusted_email = hsprintf( '%s: %s', pht('Trust Email Addresses'), pht( - 'Phabricator will skip email verification for accounts registered '. + 'Skip email verification for accounts registered '. 'through this provider.')); $str_auto_login = hsprintf( '%s: %s', pht('Allow Auto Login'), pht( - 'Phabricator will automatically login with this provider if it is '. + 'Automatically log in with this provider if it is '. 'the only available provider.')); $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('provider', $provider_class) ->appendChild( id(new AphrontFormCheckboxControl()) ->setLabel(pht('Allow')) ->addCheckbox( 'allowLogin', 1, $str_login, $v_login)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'allowRegistration', 1, $str_registration, $v_registration)) ->appendRemarkupInstructions($registration_warning) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'allowLink', 1, $str_link, $v_link)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'allowUnlink', 1, $str_unlink, $v_unlink)); if ($provider->shouldAllowEmailTrustConfiguration()) { $form->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'trustEmails', 1, $str_trusted_email, $v_trust_email)); } if ($provider->supportsAutoLogin()) { $form->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'autoLogin', 1, $str_auto_login, $v_auto_login)); } $provider->extendEditForm($request, $form, $properties, $issues); $locked_config_key = 'auth.lock-config'; $is_locked = PhabricatorEnv::getEnvConfig($locked_config_key); $locked_warning = null; if ($is_locked && !$validation_exception) { $message = pht( 'Authentication provider configuration is locked, and can not be '. 'changed without being unlocked. See the configuration setting %s '. 'for details.', phutil_tag( 'a', array( 'href' => '/config/edit/'.$locked_config_key, ), $locked_config_key)); $locked_warning = id(new PHUIInfoView()) ->setViewer($viewer) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setErrors(array($message)); } $form ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setDisabled($is_locked) ->setValue($button)); $help = $provider->getConfigurationHelp(); if ($help) { $form->appendChild(id(new PHUIFormDividerControl())); $form->appendRemarkupInstructions($help); } $footer = $provider->renderConfigurationFooter(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($crumb); $crumbs->setBorder(true); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Provider')) ->setFormErrors($errors) ->setValidationException($validation_exception) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter(array( $locked_warning, $form_box, $footer, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view); } } diff --git a/src/applications/auth/controller/config/PhabricatorAuthListController.php b/src/applications/auth/controller/config/PhabricatorAuthListController.php index b25c791e27..690aa4e57c 100644 --- a/src/applications/auth/controller/config/PhabricatorAuthListController.php +++ b/src/applications/auth/controller/config/PhabricatorAuthListController.php @@ -1,122 +1,121 @@ getViewer(); $configs = id(new PhabricatorAuthProviderConfigQuery()) ->setViewer($viewer) ->execute(); $list = new PHUIObjectItemListView(); $can_manage = $this->hasApplicationCapability( AuthManageProvidersCapability::CAPABILITY); $is_locked = PhabricatorEnv::getEnvConfig('auth.lock-config'); foreach ($configs as $config) { $item = new PHUIObjectItemView(); $id = $config->getID(); $view_uri = $config->getURI(); $provider = $config->getProvider(); $name = $provider->getProviderName(); $item ->setHeader($name) ->setHref($view_uri); $domain = $provider->getProviderDomain(); if ($domain !== 'self') { $item->addAttribute($domain); } if ($config->getShouldAllowRegistration()) { $item->addAttribute(pht('Allows Registration')); } else { $item->addAttribute(pht('Does Not Allow Registration')); } if ($config->getIsEnabled()) { $item->setStatusIcon('fa-check-circle green'); } else { $item->setStatusIcon('fa-ban red'); $item->addIcon('fa-ban grey', pht('Disabled')); } $list->addItem($item); } $list->setNoDataString( pht( '%s You have not added authentication providers yet. Use "%s" to add '. - 'a provider, which will let users register new Phabricator accounts '. - 'and log in.', + 'a provider, which will let users register new accounts and log in.', phutil_tag( 'strong', array(), pht('No Providers Configured:')), phutil_tag( 'a', array( 'href' => $this->getApplicationURI('config/new/'), ), pht('Add Provider')))); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Login and Registration')); $crumbs->setBorder(true); $guidance_context = id(new PhabricatorAuthProvidersGuidanceContext()) ->setCanManage($can_manage); $guidance = id(new PhabricatorGuidanceEngine()) ->setViewer($viewer) ->setGuidanceContext($guidance_context) ->newInfoView(); $is_disabled = (!$can_manage || $is_locked); $button = id(new PHUIButtonView()) ->setTag('a') ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) ->setIcon('fa-plus') ->setDisabled($is_disabled) ->setWorkflow($is_disabled) ->setHref($this->getApplicationURI('config/new/')) ->setText(pht('Add Provider')); $list->setFlush(true); $list = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Providers')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($list); $title = pht('Login and Registration Providers'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setHeaderIcon('fa-key') ->addActionLink($button); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter( array( $guidance, $list, )); $nav = $this->newNavigation() ->setCrumbs($crumbs) ->appendChild($view); $nav->selectFilter('login'); return $this->newPage() ->setTitle($title) ->appendChild($nav); } } diff --git a/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php b/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php index 32482a582a..d4d41f1d83 100644 --- a/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php +++ b/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php @@ -1,127 +1,127 @@ setViewer(PhabricatorUser::getOmnipotentUser()) ->withIsEnabled(true) ->execute(); $allows_registration = false; foreach ($configs as $config) { $provider = $config->getProvider(); if ($provider->shouldAllowRegistration()) { $allows_registration = true; break; } } // If no provider allows registration, we don't need provide any warnings // about registration being too open. if (!$allows_registration) { return array(); } $domains_key = 'auth.email-domains'; $domains_link = $this->renderConfigLink($domains_key); $domains_value = PhabricatorEnv::getEnvConfig($domains_key); $approval_key = 'auth.require-approval'; $approval_link = $this->renderConfigLink($approval_key); $approval_value = PhabricatorEnv::getEnvConfig($approval_key); $results = array(); if ($domains_value) { $message = pht( - 'Phabricator is configured with an email domain whitelist (in %s), so '. + 'This server is configured with an email domain whitelist (in %s), so '. 'only users with a verified email address at one of these %s '. 'allowed domain(s) will be able to register an account: %s', $domains_link, phutil_count($domains_value), phutil_tag('strong', array(), implode(', ', $domains_value))); $results[] = $this->newGuidance('core.auth.email-domains.on') ->setMessage($message); } else { $message = pht( - 'Anyone who can browse to this Phabricator install will be able to '. + 'Anyone who can browse to this this server will be able to '. 'register an account. To add email domain restrictions, configure '. '%s.', $domains_link); $results[] = $this->newGuidance('core.auth.email-domains.off') ->setMessage($message); } if ($approval_value) { $message = pht( 'Administrative approvals are enabled (in %s), so all new users must '. 'have their accounts approved by an administrator.', $approval_link); $results[] = $this->newGuidance('core.auth.require-approval.on') ->setMessage($message); } else { $message = pht( 'Administrative approvals are disabled, so users who register will '. 'be able to use their accounts immediately. To enable approvals, '. 'configure %s.', $approval_link); $results[] = $this->newGuidance('core.auth.require-approval.off') ->setMessage($message); } if (!$domains_value && !$approval_value) { $message = pht( 'You can safely ignore these warnings if the install itself has '. 'access controls (for example, it is deployed on a VPN) or if all of '. 'the configured providers have access controls (for example, they are '. 'all private LDAP or OAuth servers).'); $results[] = $this->newWarning('core.auth.warning') ->setMessage($message); } $locked_config_key = 'auth.lock-config'; $is_locked = PhabricatorEnv::getEnvConfig($locked_config_key); if ($is_locked) { $message = pht( 'Authentication provider configuration is locked, and can not be '. 'changed without being unlocked. See the configuration setting %s '. 'for details.', phutil_tag( 'a', array( 'href' => '/config/edit/'.$locked_config_key, ), $locked_config_key)); $results[] = $this->newWarning('auth.locked-config') ->setPriority(500) ->setMessage($message); } return $results; } private function renderConfigLink($key) { return phutil_tag( 'a', array( 'href' => '/config/edit/'.$key.'/', 'target' => '_blank', ), $key); } }