[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 abstract class PhabricatorAuthController extends PhabricatorController { 4 5 public function buildStandardPageResponse($view, array $data) { 6 $page = $this->buildStandardPageView(); 7 8 $page->setApplicationName(pht('Login')); 9 $page->setBaseURI('/login/'); 10 $page->setTitle(idx($data, 'title')); 11 $page->appendChild($view); 12 13 $response = new AphrontWebpageResponse(); 14 return $response->setContent($page->render()); 15 } 16 17 protected function renderErrorPage($title, array $messages) { 18 $view = new AphrontErrorView(); 19 $view->setTitle($title); 20 $view->setErrors($messages); 21 22 return $this->buildApplicationPage( 23 $view, 24 array( 25 'title' => $title, 26 )); 27 28 } 29 30 /** 31 * Returns true if this install is newly setup (i.e., there are no user 32 * accounts yet). In this case, we enter a special mode to permit creation 33 * of the first account form the web UI. 34 */ 35 protected function isFirstTimeSetup() { 36 // If there are any auth providers, this isn't first time setup, even if 37 // we don't have accounts. 38 if (PhabricatorAuthProvider::getAllEnabledProviders()) { 39 return false; 40 } 41 42 // Otherwise, check if there are any user accounts. If not, we're in first 43 // time setup. 44 $any_users = id(new PhabricatorPeopleQuery()) 45 ->setViewer(PhabricatorUser::getOmnipotentUser()) 46 ->setLimit(1) 47 ->execute(); 48 49 return !$any_users; 50 } 51 52 53 /** 54 * Log a user into a web session and return an @{class:AphrontResponse} which 55 * corresponds to continuing the login process. 56 * 57 * Normally, this is a redirect to the validation controller which makes sure 58 * the user's cookies are set. However, event listeners can intercept this 59 * event and do something else if they prefer. 60 * 61 * @param PhabricatorUser User to log the viewer in as. 62 * @return AphrontResponse Response which continues the login process. 63 */ 64 protected function loginUser(PhabricatorUser $user) { 65 66 $response = $this->buildLoginValidateResponse($user); 67 $session_type = PhabricatorAuthSession::TYPE_WEB; 68 69 $event_type = PhabricatorEventType::TYPE_AUTH_WILLLOGINUSER; 70 $event_data = array( 71 'user' => $user, 72 'type' => $session_type, 73 'response' => $response, 74 'shouldLogin' => true, 75 ); 76 77 $event = id(new PhabricatorEvent($event_type, $event_data)) 78 ->setUser($user); 79 PhutilEventEngine::dispatchEvent($event); 80 81 $should_login = $event->getValue('shouldLogin'); 82 if ($should_login) { 83 $session_key = id(new PhabricatorAuthSessionEngine()) 84 ->establishSession($session_type, $user->getPHID(), $partial = true); 85 86 // NOTE: We allow disabled users to login and roadblock them later, so 87 // there's no check for users being disabled here. 88 89 $request = $this->getRequest(); 90 $request->setCookie( 91 PhabricatorCookies::COOKIE_USERNAME, 92 $user->getUsername()); 93 $request->setCookie( 94 PhabricatorCookies::COOKIE_SESSION, 95 $session_key); 96 97 $this->clearRegistrationCookies(); 98 } 99 100 return $event->getValue('response'); 101 } 102 103 protected function clearRegistrationCookies() { 104 $request = $this->getRequest(); 105 106 // Clear the registration key. 107 $request->clearCookie(PhabricatorCookies::COOKIE_REGISTRATION); 108 109 // Clear the client ID / OAuth state key. 110 $request->clearCookie(PhabricatorCookies::COOKIE_CLIENTID); 111 } 112 113 private function buildLoginValidateResponse(PhabricatorUser $user) { 114 $validate_uri = new PhutilURI($this->getApplicationURI('validate/')); 115 $validate_uri->setQueryParam('expect', $user->getUsername()); 116 117 return id(new AphrontRedirectResponse())->setURI((string)$validate_uri); 118 } 119 120 protected function renderError($message) { 121 return $this->renderErrorPage( 122 pht('Authentication Error'), 123 array( 124 $message, 125 )); 126 } 127 128 protected function loadAccountForRegistrationOrLinking($account_key) { 129 $request = $this->getRequest(); 130 $viewer = $request->getUser(); 131 132 $account = null; 133 $provider = null; 134 $response = null; 135 136 if (!$account_key) { 137 $response = $this->renderError( 138 pht('Request did not include account key.')); 139 return array($account, $provider, $response); 140 } 141 142 // NOTE: We're using the omnipotent user because the actual user may not 143 // be logged in yet, and because we want to tailor an error message to 144 // distinguish between "not usable" and "does not exist". We do explicit 145 // checks later on to make sure this account is valid for the intended 146 // operation. This requires edit permission for completeness and consistency 147 // but it won't actually be meaningfully checked because we're using the 148 // ominpotent user. 149 150 $account = id(new PhabricatorExternalAccountQuery()) 151 ->setViewer(PhabricatorUser::getOmnipotentUser()) 152 ->withAccountSecrets(array($account_key)) 153 ->needImages(true) 154 ->requireCapabilities( 155 array( 156 PhabricatorPolicyCapability::CAN_VIEW, 157 PhabricatorPolicyCapability::CAN_EDIT, 158 )) 159 ->executeOne(); 160 161 if (!$account) { 162 $response = $this->renderError(pht('No valid linkable account.')); 163 return array($account, $provider, $response); 164 } 165 166 if ($account->getUserPHID()) { 167 if ($account->getUserPHID() != $viewer->getPHID()) { 168 $response = $this->renderError( 169 pht( 170 'The account you are attempting to register or link is already '. 171 'linked to another user.')); 172 } else { 173 $response = $this->renderError( 174 pht( 175 'The account you are attempting to link is already linked '. 176 'to your account.')); 177 } 178 return array($account, $provider, $response); 179 } 180 181 $registration_key = $request->getCookie( 182 PhabricatorCookies::COOKIE_REGISTRATION); 183 184 // NOTE: This registration key check is not strictly necessary, because 185 // we're only creating new accounts, not linking existing accounts. It 186 // might be more hassle than it is worth, especially for email. 187 // 188 // The attack this prevents is getting to the registration screen, then 189 // copy/pasting the URL and getting someone else to click it and complete 190 // the process. They end up with an account bound to credentials you 191 // control. This doesn't really let you do anything meaningful, though, 192 // since you could have simply completed the process yourself. 193 194 if (!$registration_key) { 195 $response = $this->renderError( 196 pht( 197 'Your browser did not submit a registration key with the request. '. 198 'You must use the same browser to begin and complete registration. '. 199 'Check that cookies are enabled and try again.')); 200 return array($account, $provider, $response); 201 } 202 203 // We store the digest of the key rather than the key itself to prevent a 204 // theoretical attacker with read-only access to the database from 205 // hijacking registration sessions. 206 207 $actual = $account->getProperty('registrationKey'); 208 $expect = PhabricatorHash::digest($registration_key); 209 if ($actual !== $expect) { 210 $response = $this->renderError( 211 pht( 212 'Your browser submitted a different registration key than the one '. 213 'associated with this account. You may need to clear your cookies.')); 214 return array($account, $provider, $response); 215 } 216 217 $other_account = id(new PhabricatorExternalAccount())->loadAllWhere( 218 'accountType = %s AND accountDomain = %s AND accountID = %s 219 AND id != %d', 220 $account->getAccountType(), 221 $account->getAccountDomain(), 222 $account->getAccountID(), 223 $account->getID()); 224 225 if ($other_account) { 226 $response = $this->renderError( 227 pht( 228 'The account you are attempting to register with already belongs '. 229 'to another user.')); 230 return array($account, $provider, $response); 231 } 232 233 $provider = PhabricatorAuthProvider::getEnabledProviderByKey( 234 $account->getProviderKey()); 235 236 if (!$provider) { 237 $response = $this->renderError( 238 pht( 239 'The account you are attempting to register with uses a nonexistent '. 240 'or disabled authentication provider (with key "%s"). An '. 241 'administrator may have recently disabled this provider.', 242 $account->getProviderKey())); 243 return array($account, $provider, $response); 244 } 245 246 return array($account, $provider, null); 247 } 248 249 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |