@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 250 lines 6.6 kB view raw
1<?php 2 3final class PhabricatorAuthNeedsMultiFactorController 4 extends PhabricatorAuthController { 5 6 public function shouldRequireMultiFactorEnrollment() { 7 // Users need access to this controller in order to enroll in multi-factor 8 // auth. 9 return false; 10 } 11 12 public function shouldRequireEnabledUser() { 13 // Users who haven't been approved yet are allowed to enroll in MFA. We'll 14 // kick disabled users out later. 15 return false; 16 } 17 18 public function shouldRequireEmailVerification() { 19 // Users who haven't verified their email addresses yet can still enroll 20 // in MFA. 21 return false; 22 } 23 24 public function handleRequest(AphrontRequest $request) { 25 $viewer = $this->getViewer(); 26 27 if ($viewer->getIsDisabled()) { 28 // We allowed unapproved and disabled users to hit this controller, but 29 // want to kick out disabled users now. 30 return new Aphront400Response(); 31 } 32 33 $panels = $this->loadPanels(); 34 35 $multifactor_key = id(new PhabricatorMultiFactorSettingsPanel()) 36 ->getPanelKey(); 37 38 $panel_key = $request->getURIData('pageKey'); 39 if (!phutil_nonempty_string($panel_key)) { 40 $panel_key = $multifactor_key; 41 } 42 43 if (!isset($panels[$panel_key])) { 44 return new Aphront404Response(); 45 } 46 47 $nav = $this->newNavigation(); 48 $nav->selectFilter($panel_key); 49 50 $panel = $panels[$panel_key]; 51 52 $viewer->updateMultiFactorEnrollment(); 53 54 if ($panel_key === $multifactor_key) { 55 $header_text = pht('Add Multi-Factor Auth'); 56 $help = $this->newGuidance(); 57 $panel->setIsEnrollment(true); 58 } else { 59 $header_text = $panel->getPanelName(); 60 $help = null; 61 } 62 63 $response = $panel 64 ->setController($this) 65 ->setNavigation($nav) 66 ->processRequest($request); 67 68 if (($response instanceof AphrontResponse) || 69 ($response instanceof AphrontResponseProducerInterface)) { 70 return $response; 71 } 72 73 $crumbs = $this->buildApplicationCrumbs() 74 ->addTextCrumb(pht('Add Multi-Factor Auth')) 75 ->setBorder(true); 76 77 $header = id(new PHUIHeaderView()) 78 ->setHeader($header_text); 79 80 $view = id(new PHUITwoColumnView()) 81 ->setHeader($header) 82 ->setFooter( 83 array( 84 $help, 85 $response, 86 )); 87 88 return $this->newPage() 89 ->setTitle(pht('Add Multi-Factor Authentication')) 90 ->setCrumbs($crumbs) 91 ->setNavigation($nav) 92 ->appendChild($view); 93 94 } 95 96 private function loadPanels() { 97 $viewer = $this->getViewer(); 98 $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer); 99 100 $panels = PhabricatorSettingsPanel::getAllDisplayPanels(); 101 $base_uri = $this->newEnrollBaseURI(); 102 103 $result = array(); 104 foreach ($panels as $key => $panel) { 105 $panel 106 ->setPreferences($preferences) 107 ->setViewer($viewer) 108 ->setUser($viewer) 109 ->setOverrideURI(urisprintf('%s%s/', $base_uri, $key)); 110 111 if (!$panel->isEnabled()) { 112 continue; 113 } 114 115 if (!$panel->isUserPanel()) { 116 continue; 117 } 118 119 if (!$panel->isMultiFactorEnrollmentPanel()) { 120 continue; 121 } 122 123 if (!empty($result[$key])) { 124 throw new Exception(pht( 125 "Two settings panels share the same panel key ('%s'): %s, %s.", 126 $key, 127 get_class($panel), 128 get_class($result[$key]))); 129 } 130 131 $result[$key] = $panel; 132 } 133 134 return $result; 135 } 136 137 138 private function newNavigation() { 139 $viewer = $this->getViewer(); 140 141 $enroll_uri = $this->newEnrollBaseURI(); 142 143 $nav = id(new AphrontSideNavFilterView()) 144 ->setBaseURI(new PhutilURI($enroll_uri)); 145 146 $multifactor_key = id(new PhabricatorMultiFactorSettingsPanel()) 147 ->getPanelKey(); 148 149 $nav->addFilter( 150 $multifactor_key, 151 pht('Enroll in MFA'), 152 null, 153 'fa-exclamation-triangle blue'); 154 155 $panels = $this->loadPanels(); 156 157 if ($panels) { 158 $nav->addLabel(pht('Settings')); 159 } 160 161 foreach ($panels as $panel_key => $panel) { 162 if ($panel_key === $multifactor_key) { 163 continue; 164 } 165 166 $nav->addFilter( 167 $panel->getPanelKey(), 168 $panel->getPanelName(), 169 null, 170 $panel->getPanelMenuIcon()); 171 } 172 173 return $nav; 174 } 175 176 private function newEnrollBaseURI() { 177 return $this->getApplicationURI('enroll/'); 178 } 179 180 private function newGuidance() { 181 $viewer = $this->getViewer(); 182 183 if ($viewer->getIsEnrolledInMultiFactor()) { 184 $guidance = pht( 185 '{icon check, color="green"} **Setup Complete!**'. 186 "\n\n". 187 'You have successfully configured multi-factor authentication '. 188 'for your account.'. 189 "\n\n". 190 'You can make adjustments from the [[ /settings/ | Settings ]] panel '. 191 'later.'); 192 193 return $this->newDialog() 194 ->setTitle(pht('Multi-Factor Authentication Setup Complete')) 195 ->setWidth(AphrontDialogView::WIDTH_FULL) 196 ->appendChild(new PHUIRemarkupView($viewer, $guidance)) 197 ->addCancelButton('/', pht('Continue')); 198 } 199 200 $views = array(); 201 202 $messages = array(); 203 204 $messages[] = pht( 205 'Before you can use this software, you need to add multi-factor '. 206 'authentication to your account. Multi-factor authentication helps '. 207 'secure your account by making it more difficult for attackers to '. 208 'gain access or take sensitive actions.'); 209 210 $view = id(new PHUIInfoView()) 211 ->setTitle(pht('Add Multi-Factor Authentication To Your Account')) 212 ->setSeverity(PHUIInfoView::SEVERITY_WARNING) 213 ->setErrors($messages); 214 215 $views[] = $view; 216 217 218 $providers = id(new PhabricatorAuthFactorProviderQuery()) 219 ->setViewer($viewer) 220 ->withStatuses( 221 array( 222 PhabricatorAuthFactorProviderStatus::STATUS_ACTIVE, 223 )) 224 ->execute(); 225 if (!$providers) { 226 $messages = array(); 227 228 $required_key = 'security.require-multi-factor-auth'; 229 230 $messages[] = pht( 231 'This install has the configuration option "%s" enabled, but does '. 232 'not have any active multifactor providers configured. This means '. 233 'you are required to add MFA, but are also prevented from doing so. '. 234 'An administrator must disable "%s" or enable an MFA provider to '. 235 'allow you to continue.', 236 $required_key, 237 $required_key); 238 239 $view = id(new PHUIInfoView()) 240 ->setTitle(pht('Multi-Factor Authentication is Misconfigured')) 241 ->setSeverity(PHUIInfoView::SEVERITY_ERROR) 242 ->setErrors($messages); 243 244 $views[] = $view; 245 } 246 247 return $views; 248 } 249 250}