[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorAuthRegisterController 4 extends PhabricatorAuthController { 5 6 private $accountKey; 7 8 public function shouldRequireLogin() { 9 return false; 10 } 11 12 public function willProcessRequest(array $data) { 13 $this->accountKey = idx($data, 'akey'); 14 } 15 16 public function processRequest() { 17 $request = $this->getRequest(); 18 19 if ($request->getUser()->isLoggedIn()) { 20 return $this->renderError(pht('You are already logged in.')); 21 } 22 23 $is_setup = false; 24 if (strlen($this->accountKey)) { 25 $result = $this->loadAccountForRegistrationOrLinking($this->accountKey); 26 list($account, $provider, $response) = $result; 27 $is_default = false; 28 } else if ($this->isFirstTimeSetup()) { 29 list($account, $provider, $response) = $this->loadSetupAccount(); 30 $is_default = true; 31 $is_setup = true; 32 } else { 33 list($account, $provider, $response) = $this->loadDefaultAccount(); 34 $is_default = true; 35 } 36 37 if ($response) { 38 return $response; 39 } 40 41 if (!$provider->shouldAllowRegistration()) { 42 43 // TODO: This is a routine error if you click "Login" on an external 44 // auth source which doesn't allow registration. The error should be 45 // more tailored. 46 47 return $this->renderError( 48 pht( 49 'The account you are attempting to register with uses an '. 50 'authentication provider ("%s") which does not allow registration. '. 51 'An administrator may have recently disabled registration with this '. 52 'provider.', 53 $provider->getProviderName())); 54 } 55 56 $user = new PhabricatorUser(); 57 58 $default_username = $account->getUsername(); 59 $default_realname = $account->getRealName(); 60 61 $default_email = $account->getEmail(); 62 if (!PhabricatorUserEmail::isValidAddress($default_email)) { 63 $default_email = null; 64 } 65 66 if ($default_email !== null) { 67 // If the account source provided an email, but it's not allowed by 68 // the configuration, roadblock the user. Previously, we let the user 69 // pick a valid email address instead, but this does not align well with 70 // user expectation and it's not clear the cases it enables are valuable. 71 // See discussion in T3472. 72 if (!PhabricatorUserEmail::isAllowedAddress($default_email)) { 73 return $this->renderError( 74 array( 75 pht( 76 'The account you are attempting to register with has an invalid '. 77 'email address (%s). This Phabricator install only allows '. 78 'registration with specific email addresses:', 79 $default_email), 80 phutil_tag('br'), 81 phutil_tag('br'), 82 PhabricatorUserEmail::describeAllowedAddresses(), 83 )); 84 } 85 86 // If the account source provided an email, but another account already 87 // has that email, just pretend we didn't get an email. 88 89 // TODO: See T3340. 90 // TODO: See T3472. 91 92 if ($default_email !== null) { 93 $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 94 'address = %s', 95 $default_email); 96 if ($same_email) { 97 $default_email = null; 98 } 99 } 100 } 101 102 $profile = id(new PhabricatorRegistrationProfile()) 103 ->setDefaultUsername($default_username) 104 ->setDefaultEmail($default_email) 105 ->setDefaultRealName($default_realname) 106 ->setCanEditUsername(true) 107 ->setCanEditEmail(($default_email === null)) 108 ->setCanEditRealName(true) 109 ->setShouldVerifyEmail(false); 110 111 $event_type = PhabricatorEventType::TYPE_AUTH_WILLREGISTERUSER; 112 $event_data = array( 113 'account' => $account, 114 'profile' => $profile, 115 ); 116 117 $event = id(new PhabricatorEvent($event_type, $event_data)) 118 ->setUser($user); 119 PhutilEventEngine::dispatchEvent($event); 120 121 $default_username = $profile->getDefaultUsername(); 122 $default_email = $profile->getDefaultEmail(); 123 $default_realname = $profile->getDefaultRealName(); 124 125 $can_edit_username = $profile->getCanEditUsername(); 126 $can_edit_email = $profile->getCanEditEmail(); 127 $can_edit_realname = $profile->getCanEditRealName(); 128 129 $must_set_password = $provider->shouldRequireRegistrationPassword(); 130 131 $can_edit_anything = $profile->getCanEditAnything() || $must_set_password; 132 $force_verify = $profile->getShouldVerifyEmail(); 133 134 // Automatically verify the administrator's email address during first-time 135 // setup. 136 if ($is_setup) { 137 $force_verify = true; 138 } 139 140 $value_username = $default_username; 141 $value_realname = $default_realname; 142 $value_email = $default_email; 143 $value_password = null; 144 145 $errors = array(); 146 147 $require_real_name = PhabricatorEnv::getEnvConfig('user.require-real-name'); 148 149 $e_username = strlen($value_username) ? null : true; 150 $e_realname = $require_real_name ? true : null; 151 $e_email = strlen($value_email) ? null : true; 152 $e_password = true; 153 $e_captcha = true; 154 155 $min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length'); 156 $min_len = (int)$min_len; 157 158 if ($request->isFormPost() || !$can_edit_anything) { 159 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 160 161 if ($must_set_password) { 162 $e_captcha = pht('Again'); 163 164 $captcha_ok = AphrontFormRecaptchaControl::processCaptcha($request); 165 if (!$captcha_ok) { 166 $errors[] = pht('Captcha response is incorrect, try again.'); 167 $e_captcha = pht('Invalid'); 168 } 169 } 170 171 if ($can_edit_username) { 172 $value_username = $request->getStr('username'); 173 if (!strlen($value_username)) { 174 $e_username = pht('Required'); 175 $errors[] = pht('Username is required.'); 176 } else if (!PhabricatorUser::validateUsername($value_username)) { 177 $e_username = pht('Invalid'); 178 $errors[] = PhabricatorUser::describeValidUsername(); 179 } else { 180 $e_username = null; 181 } 182 } 183 184 if ($must_set_password) { 185 $value_password = $request->getStr('password'); 186 $value_confirm = $request->getStr('confirm'); 187 if (!strlen($value_password)) { 188 $e_password = pht('Required'); 189 $errors[] = pht('You must choose a password.'); 190 } else if ($value_password !== $value_confirm) { 191 $e_password = pht('No Match'); 192 $errors[] = pht('Password and confirmation must match.'); 193 } else if (strlen($value_password) < $min_len) { 194 $e_password = pht('Too Short'); 195 $errors[] = pht( 196 'Password is too short (must be at least %d characters long).', 197 $min_len); 198 } else if ( 199 PhabricatorCommonPasswords::isCommonPassword($value_password)) { 200 201 $e_password = pht('Very Weak'); 202 $errors[] = pht( 203 'Password is pathologically weak. This password is one of the '. 204 'most common passwords in use, and is extremely easy for '. 205 'attackers to guess. You must choose a stronger password.'); 206 } else { 207 $e_password = null; 208 } 209 } 210 211 if ($can_edit_email) { 212 $value_email = $request->getStr('email'); 213 if (!strlen($value_email)) { 214 $e_email = pht('Required'); 215 $errors[] = pht('Email is required.'); 216 } else if (!PhabricatorUserEmail::isValidAddress($value_email)) { 217 $e_email = pht('Invalid'); 218 $errors[] = PhabricatorUserEmail::describeValidAddresses(); 219 } else if (!PhabricatorUserEmail::isAllowedAddress($value_email)) { 220 $e_email = pht('Disallowed'); 221 $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); 222 } else { 223 $e_email = null; 224 } 225 } 226 227 if ($can_edit_realname) { 228 $value_realname = $request->getStr('realName'); 229 if (!strlen($value_realname) && $require_real_name) { 230 $e_realname = pht('Required'); 231 $errors[] = pht('Real name is required.'); 232 } else { 233 $e_realname = null; 234 } 235 } 236 237 if (!$errors) { 238 $image = $this->loadProfilePicture($account); 239 if ($image) { 240 $user->setProfileImagePHID($image->getPHID()); 241 } 242 243 try { 244 if ($force_verify) { 245 $verify_email = true; 246 } else { 247 $verify_email = 248 ($account->getEmailVerified()) && 249 ($value_email === $default_email); 250 } 251 252 if ($provider->shouldTrustEmails() && 253 $value_email === $default_email) { 254 $verify_email = true; 255 } 256 257 $email_obj = id(new PhabricatorUserEmail()) 258 ->setAddress($value_email) 259 ->setIsVerified((int)$verify_email); 260 261 $user->setUsername($value_username); 262 $user->setRealname($value_realname); 263 264 if ($is_setup) { 265 $must_approve = false; 266 } else { 267 $must_approve = PhabricatorEnv::getEnvConfig( 268 'auth.require-approval'); 269 } 270 271 if ($must_approve) { 272 $user->setIsApproved(0); 273 } else { 274 $user->setIsApproved(1); 275 } 276 277 $user->openTransaction(); 278 279 $editor = id(new PhabricatorUserEditor()) 280 ->setActor($user); 281 282 $editor->createNewUser($user, $email_obj); 283 if ($must_set_password) { 284 $envelope = new PhutilOpaqueEnvelope($value_password); 285 $editor->changePassword($user, $envelope); 286 } 287 288 if ($is_setup) { 289 $editor->makeAdminUser($user, true); 290 } 291 292 $account->setUserPHID($user->getPHID()); 293 $provider->willRegisterAccount($account); 294 $account->save(); 295 296 $user->saveTransaction(); 297 298 if (!$email_obj->getIsVerified()) { 299 $email_obj->sendVerificationEmail($user); 300 } 301 302 if ($must_approve) { 303 $this->sendWaitingForApprovalEmail($user); 304 } 305 306 return $this->loginUser($user); 307 } catch (AphrontDuplicateKeyQueryException $exception) { 308 $same_username = id(new PhabricatorUser())->loadOneWhere( 309 'userName = %s', 310 $user->getUserName()); 311 312 $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 313 'address = %s', 314 $value_email); 315 316 if ($same_username) { 317 $e_username = pht('Duplicate'); 318 $errors[] = pht('Another user already has that username.'); 319 } 320 321 if ($same_email) { 322 // TODO: See T3340. 323 $e_email = pht('Duplicate'); 324 $errors[] = pht('Another user already has that email.'); 325 } 326 327 if (!$same_username && !$same_email) { 328 throw $exception; 329 } 330 } 331 } 332 333 unset($unguarded); 334 } 335 336 $form = id(new AphrontFormView()) 337 ->setUser($request->getUser()); 338 339 if (!$is_default) { 340 $form->appendChild( 341 id(new AphrontFormMarkupControl()) 342 ->setLabel(pht('External Account')) 343 ->setValue( 344 id(new PhabricatorAuthAccountView()) 345 ->setUser($request->getUser()) 346 ->setExternalAccount($account) 347 ->setAuthProvider($provider))); 348 } 349 350 351 if ($can_edit_username) { 352 $form->appendChild( 353 id(new AphrontFormTextControl()) 354 ->setLabel(pht('Phabricator Username')) 355 ->setName('username') 356 ->setValue($value_username) 357 ->setError($e_username)); 358 } else { 359 $form->appendChild( 360 id(new AphrontFormMarkupControl()) 361 ->setLabel(pht('Phabricator Username')) 362 ->setValue($value_username) 363 ->setError($e_username)); 364 } 365 366 if ($must_set_password) { 367 $form->appendChild( 368 id(new AphrontFormPasswordControl()) 369 ->setLabel(pht('Password')) 370 ->setName('password') 371 ->setError($e_password) 372 ->setCaption( 373 $min_len 374 ? pht('Minimum length of %d characters.', $min_len) 375 : null)); 376 $form->appendChild( 377 id(new AphrontFormPasswordControl()) 378 ->setLabel(pht('Confirm Password')) 379 ->setName('confirm') 380 ->setError($e_password)); 381 } 382 383 if ($can_edit_email) { 384 $form->appendChild( 385 id(new AphrontFormTextControl()) 386 ->setLabel(pht('Email')) 387 ->setName('email') 388 ->setValue($value_email) 389 ->setCaption(PhabricatorUserEmail::describeAllowedAddresses()) 390 ->setError($e_email)); 391 } 392 393 if ($can_edit_realname) { 394 $form->appendChild( 395 id(new AphrontFormTextControl()) 396 ->setLabel(pht('Real Name')) 397 ->setName('realName') 398 ->setValue($value_realname) 399 ->setError($e_realname)); 400 } 401 402 if ($must_set_password) { 403 $form->appendChild( 404 id(new AphrontFormRecaptchaControl()) 405 ->setLabel(pht('Captcha')) 406 ->setError($e_captcha)); 407 } 408 409 $submit = id(new AphrontFormSubmitControl()); 410 411 if ($is_setup) { 412 $submit 413 ->setValue(pht('Create Admin Account')); 414 } else { 415 $submit 416 ->addCancelButton($this->getApplicationURI('start/')) 417 ->setValue(pht('Register Phabricator Account')); 418 } 419 420 421 $form->appendChild($submit); 422 423 $crumbs = $this->buildApplicationCrumbs(); 424 425 if ($is_setup) { 426 $crumbs->addTextCrumb(pht('Setup Admin Account')); 427 $title = pht('Welcome to Phabricator'); 428 } else { 429 $crumbs->addTextCrumb(pht('Register')); 430 $crumbs->addTextCrumb($provider->getProviderName()); 431 $title = pht('Phabricator Registration'); 432 } 433 434 $welcome_view = null; 435 if ($is_setup) { 436 $welcome_view = id(new AphrontErrorView()) 437 ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) 438 ->setTitle(pht('Welcome to Phabricator')) 439 ->appendChild( 440 pht( 441 'Installation is complete. Register your administrator account '. 442 'below to log in. You will be able to configure options and add '. 443 'other authentication mechanisms (like LDAP or OAuth) later on.')); 444 } 445 446 $object_box = id(new PHUIObjectBoxView()) 447 ->setHeaderText($title) 448 ->setForm($form) 449 ->setFormErrors($errors); 450 451 return $this->buildApplicationPage( 452 array( 453 $crumbs, 454 $welcome_view, 455 $object_box, 456 ), 457 array( 458 'title' => $title, 459 )); 460 } 461 462 private function loadDefaultAccount() { 463 $providers = PhabricatorAuthProvider::getAllEnabledProviders(); 464 $account = null; 465 $provider = null; 466 $response = null; 467 468 foreach ($providers as $key => $candidate_provider) { 469 if (!$candidate_provider->shouldAllowRegistration()) { 470 unset($providers[$key]); 471 continue; 472 } 473 if (!$candidate_provider->isDefaultRegistrationProvider()) { 474 unset($providers[$key]); 475 } 476 } 477 478 if (!$providers) { 479 $response = $this->renderError( 480 pht( 481 'There are no configured default registration providers.')); 482 return array($account, $provider, $response); 483 } else if (count($providers) > 1) { 484 $response = $this->renderError( 485 pht( 486 'There are too many configured default registration providers.')); 487 return array($account, $provider, $response); 488 } 489 490 $provider = head($providers); 491 $account = $provider->getDefaultExternalAccount(); 492 493 return array($account, $provider, $response); 494 } 495 496 private function loadSetupAccount() { 497 $provider = new PhabricatorPasswordAuthProvider(); 498 $provider->attachProviderConfig( 499 id(new PhabricatorAuthProviderConfig()) 500 ->setShouldAllowRegistration(1) 501 ->setShouldAllowLogin(1) 502 ->setIsEnabled(true)); 503 504 $account = $provider->getDefaultExternalAccount(); 505 $response = null; 506 return array($account, $provider, $response); 507 } 508 509 private function loadProfilePicture(PhabricatorExternalAccount $account) { 510 $phid = $account->getProfileImagePHID(); 511 if (!$phid) { 512 return null; 513 } 514 515 // NOTE: Use of omnipotent user is okay here because the registering user 516 // can not control the field value, and we can't use their user object to 517 // do meaningful policy checks anyway since they have not registered yet. 518 // Reaching this means the user holds the account secret key and the 519 // registration secret key, and thus has permission to view the image. 520 521 $file = id(new PhabricatorFileQuery()) 522 ->setViewer(PhabricatorUser::getOmnipotentUser()) 523 ->withPHIDs(array($phid)) 524 ->executeOne(); 525 if (!$file) { 526 return null; 527 } 528 529 try { 530 $xformer = new PhabricatorImageTransformer(); 531 return $xformer->executeProfileTransform( 532 $file, 533 $width = 50, 534 $min_height = 50, 535 $max_height = 50); 536 } catch (Exception $ex) { 537 phlog($ex); 538 return null; 539 } 540 } 541 542 protected function renderError($message) { 543 return $this->renderErrorPage( 544 pht('Registration Failed'), 545 array($message)); 546 } 547 548 private function sendWaitingForApprovalEmail(PhabricatorUser $user) { 549 $title = '[Phabricator] '.pht( 550 'New User "%s" Awaiting Approval', 551 $user->getUsername()); 552 553 $body = new PhabricatorMetaMTAMailBody(); 554 555 $body->addRawSection( 556 pht( 557 'Newly registered user "%s" is awaiting account approval by an '. 558 'administrator.', 559 $user->getUsername())); 560 561 $body->addLinkSection( 562 pht('APPROVAL QUEUE'), 563 PhabricatorEnv::getProductionURI( 564 '/people/query/approval/')); 565 566 $body->addLinkSection( 567 pht('DISABLE APPROVAL QUEUE'), 568 PhabricatorEnv::getProductionURI( 569 '/config/edit/auth.require-approval/')); 570 571 $admins = id(new PhabricatorPeopleQuery()) 572 ->setViewer(PhabricatorUser::getOmnipotentUser()) 573 ->withIsAdmin(true) 574 ->execute(); 575 576 if (!$admins) { 577 return; 578 } 579 580 $mail = id(new PhabricatorMetaMTAMail()) 581 ->addTos(mpull($admins, 'getPHID')) 582 ->setSubject($title) 583 ->setBody($body->render()) 584 ->saveAndSend(); 585 } 586 587 }
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 |