@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add a skeleton for configurable MFA provider types

Summary:
Ref T13222. Ref T13231. See PHI912. I'm planning to turn MFA providers into concrete objects, so you can disable and configure them.

Currently, we only support TOTP, which doesn't require any configuration, but other provider types (like Duo or Yubikey OTP) do require some configuration (server URIs, API keys, etc). TOTP //could// also have some configuration, like "bits of entropy" or "allowed window size" or whatever, if we want.

Add concrete objects for this and standard transaction / policy / query support. These objects don't do anything interesting yet and don't actually interact with MFA, this is just skeleton code for now.

Test Plan:
{F6090444}

{F6090445}

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13231, T13222

Differential Revision: https://secure.phabricator.com/D19935

+871 -40
+9
resources/sql/autopatches/20181228.auth.01.provider.sql
··· 1 + CREATE TABLE {$NAMESPACE}_auth.auth_factorprovider ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + providerFactorKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}, 5 + status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 6 + properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 7 + dateCreated INT UNSIGNED NOT NULL, 8 + dateModified INT UNSIGNED NOT NULL 9 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+19
resources/sql/autopatches/20181228.auth.02.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_auth.auth_factorprovidertransaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + authorPHID VARBINARY(64) NOT NULL, 5 + objectPHID VARBINARY(64) NOT NULL, 6 + viewPolicy VARBINARY(64) NOT NULL, 7 + editPolicy VARBINARY(64) NOT NULL, 8 + commentPHID VARBINARY(64) DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) NOT NULL, 11 + oldValue LONGTEXT NOT NULL, 12 + newValue LONGTEXT NOT NULL, 13 + contentSource LONGTEXT NOT NULL, 14 + metadata LONGTEXT NOT NULL, 15 + dateCreated INT UNSIGNED NOT NULL, 16 + dateModified INT UNSIGNED NOT NULL, 17 + UNIQUE KEY `key_phid` (`phid`), 18 + KEY `key_object` (`objectPHID`) 19 + ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};
+2
resources/sql/autopatches/20181228.auth.03.name.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_factorprovider 2 + ADD name VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT};
+34 -1
src/__phutil_library_map__.php
··· 2190 2190 'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php', 2191 2191 'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php', 2192 2192 'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php', 2193 + 'PhabricatorAuthAuthFactorProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php', 2193 2194 'PhabricatorAuthAuthProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthProviderPHIDType.php', 2194 2195 'PhabricatorAuthCSRFEngine' => 'applications/auth/engine/PhabricatorAuthCSRFEngine.php', 2195 2196 'PhabricatorAuthChallenge' => 'applications/auth/storage/PhabricatorAuthChallenge.php', ··· 2207 2208 'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php', 2208 2209 'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php', 2209 2210 'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php', 2211 + 'PhabricatorAuthFactorProvider' => 'applications/auth/storage/PhabricatorAuthFactorProvider.php', 2212 + 'PhabricatorAuthFactorProviderController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php', 2213 + 'PhabricatorAuthFactorProviderEditController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php', 2214 + 'PhabricatorAuthFactorProviderEditEngine' => 'applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php', 2215 + 'PhabricatorAuthFactorProviderEditor' => 'applications/auth/editor/PhabricatorAuthFactorProviderEditor.php', 2216 + 'PhabricatorAuthFactorProviderListController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php', 2217 + 'PhabricatorAuthFactorProviderNameTransaction' => 'applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php', 2218 + 'PhabricatorAuthFactorProviderQuery' => 'applications/auth/query/PhabricatorAuthFactorProviderQuery.php', 2219 + 'PhabricatorAuthFactorProviderTransaction' => 'applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php', 2220 + 'PhabricatorAuthFactorProviderTransactionQuery' => 'applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php', 2221 + 'PhabricatorAuthFactorProviderTransactionType' => 'applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php', 2222 + 'PhabricatorAuthFactorProviderViewController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php', 2210 2223 'PhabricatorAuthFactorResult' => 'applications/auth/factor/PhabricatorAuthFactorResult.php', 2211 2224 'PhabricatorAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php', 2212 2225 'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php', ··· 2277 2290 'PhabricatorAuthProviderConfigQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigQuery.php', 2278 2291 'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php', 2279 2292 'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php', 2293 + 'PhabricatorAuthProviderController' => 'applications/auth/controller/config/PhabricatorAuthProviderController.php', 2280 2294 'PhabricatorAuthProvidersGuidanceContext' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceContext.php', 2281 2295 'PhabricatorAuthProvidersGuidanceEngineExtension' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php', 2282 2296 'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php', ··· 7835 7849 'PhabricatorAuthAccountView' => 'AphrontView', 7836 7850 'PhabricatorAuthApplication' => 'PhabricatorApplication', 7837 7851 'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType', 7852 + 'PhabricatorAuthAuthFactorProviderPHIDType' => 'PhabricatorPHIDType', 7838 7853 'PhabricatorAuthAuthProviderPHIDType' => 'PhabricatorPHIDType', 7839 7854 'PhabricatorAuthCSRFEngine' => 'Phobject', 7840 7855 'PhabricatorAuthChallenge' => array( ··· 7855 7870 'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController', 7856 7871 'PhabricatorAuthFactor' => 'Phobject', 7857 7872 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', 7873 + 'PhabricatorAuthFactorProvider' => array( 7874 + 'PhabricatorAuthDAO', 7875 + 'PhabricatorApplicationTransactionInterface', 7876 + 'PhabricatorPolicyInterface', 7877 + 'PhabricatorExtendedPolicyInterface', 7878 + ), 7879 + 'PhabricatorAuthFactorProviderController' => 'PhabricatorAuthProviderController', 7880 + 'PhabricatorAuthFactorProviderEditController' => 'PhabricatorAuthFactorProviderController', 7881 + 'PhabricatorAuthFactorProviderEditEngine' => 'PhabricatorEditEngine', 7882 + 'PhabricatorAuthFactorProviderEditor' => 'PhabricatorApplicationTransactionEditor', 7883 + 'PhabricatorAuthFactorProviderListController' => 'PhabricatorAuthProviderController', 7884 + 'PhabricatorAuthFactorProviderNameTransaction' => 'PhabricatorAuthFactorProviderTransactionType', 7885 + 'PhabricatorAuthFactorProviderQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7886 + 'PhabricatorAuthFactorProviderTransaction' => 'PhabricatorModularTransaction', 7887 + 'PhabricatorAuthFactorProviderTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7888 + 'PhabricatorAuthFactorProviderTransactionType' => 'PhabricatorModularTransactionType', 7889 + 'PhabricatorAuthFactorProviderViewController' => 'PhabricatorAuthFactorProviderController', 7858 7890 'PhabricatorAuthFactorResult' => 'Phobject', 7859 7891 'PhabricatorAuthFactorTestCase' => 'PhabricatorTestCase', 7860 7892 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', ··· 7931 7963 'PhabricatorApplicationTransactionInterface', 7932 7964 'PhabricatorPolicyInterface', 7933 7965 ), 7934 - 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthController', 7966 + 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthProviderController', 7935 7967 'PhabricatorAuthProviderConfigEditor' => 'PhabricatorApplicationTransactionEditor', 7936 7968 'PhabricatorAuthProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7937 7969 'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction', 7938 7970 'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7971 + 'PhabricatorAuthProviderController' => 'PhabricatorAuthController', 7939 7972 'PhabricatorAuthProvidersGuidanceContext' => 'PhabricatorGuidanceContext', 7940 7973 'PhabricatorAuthProvidersGuidanceEngineExtension' => 'PhabricatorGuidanceEngineExtension', 7941 7974 'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
+9
src/applications/auth/application/PhabricatorAuthApplication.php
··· 85 85 'view/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyViewController', 86 86 ), 87 87 'password/' => 'PhabricatorAuthSetPasswordController', 88 + 89 + 'mfa/' => array( 90 + $this->getQueryRoutePattern() => 91 + 'PhabricatorAuthFactorProviderListController', 92 + $this->getEditRoutePattern('edit/') => 93 + 'PhabricatorAuthFactorProviderEditController', 94 + '(?P<id>[1-9]\d*)/' => 95 + 'PhabricatorAuthFactorProviderViewController', 96 + ), 88 97 ), 89 98 90 99 '/oauth/(?P<provider>\w+)/login/'
+15 -10
src/applications/auth/controller/config/PhabricatorAuthListController.php
··· 91 91 pht('Add Authentication Provider')))); 92 92 93 93 $crumbs = $this->buildApplicationCrumbs(); 94 - $crumbs->addTextCrumb(pht('Auth Providers')); 94 + $crumbs->addTextCrumb(pht('Login and Registration')); 95 95 $crumbs->setBorder(true); 96 96 97 97 $guidance_context = new PhabricatorAuthProvidersGuidanceContext(); ··· 102 102 ->newInfoView(); 103 103 104 104 $button = id(new PHUIButtonView()) 105 - ->setTag('a') 106 - ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) 107 - ->setHref($this->getApplicationURI('config/new/')) 108 - ->setIcon('fa-plus') 109 - ->setDisabled(!$can_manage) 110 - ->setText(pht('Add Provider')); 105 + ->setTag('a') 106 + ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) 107 + ->setHref($this->getApplicationURI('config/new/')) 108 + ->setIcon('fa-plus') 109 + ->setDisabled(!$can_manage) 110 + ->setText(pht('Add Provider')); 111 111 112 112 $list->setFlush(true); 113 113 $list = id(new PHUIObjectBoxView()) ··· 115 115 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 116 116 ->appendChild($list); 117 117 118 - $title = pht('Auth Providers'); 118 + $title = pht('Login and Registration Providers'); 119 119 $header = id(new PHUIHeaderView()) 120 120 ->setHeader($title) 121 121 ->setHeaderIcon('fa-key') ··· 128 128 $list, 129 129 )); 130 130 131 - return $this->newPage() 132 - ->setTitle($title) 131 + $nav = $this->newNavigation() 133 132 ->setCrumbs($crumbs) 134 133 ->appendChild($view); 134 + 135 + $nav->selectFilter('login'); 136 + 137 + return $this->newPage() 138 + ->setTitle($title) 139 + ->appendChild($nav); 135 140 } 136 141 137 142 }
+1 -29
src/applications/auth/controller/config/PhabricatorAuthProviderConfigController.php
··· 1 1 <?php 2 2 3 3 abstract class PhabricatorAuthProviderConfigController 4 - extends PhabricatorAuthController { 5 - 6 - protected function buildSideNavView($for_app = false) { 7 - $nav = new AphrontSideNavFilterView(); 8 - $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 9 - 10 - if ($for_app) { 11 - $nav->addLabel(pht('Create')); 12 - $nav->addFilter('', 13 - pht('Add Authentication Provider'), 14 - $this->getApplicationURI('/config/new/')); 15 - } 16 - return $nav; 17 - } 18 - 19 - public function buildApplicationMenu() { 20 - return $this->buildSideNavView($for_app = true)->getMenu(); 21 - } 22 - 23 - protected function buildApplicationCrumbs() { 24 - $crumbs = parent::buildApplicationCrumbs(); 25 - 26 - $can_create = $this->hasApplicationCapability( 27 - AuthManageProvidersCapability::CAPABILITY); 28 - 29 - return $crumbs; 30 - } 31 - 32 - } 4 + extends PhabricatorAuthProviderController {}
+43
src/applications/auth/controller/config/PhabricatorAuthProviderController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorAuthProviderController 4 + extends PhabricatorAuthController { 5 + 6 + protected function newNavigation() { 7 + $viewer = $this->getViewer(); 8 + 9 + $nav = id(new AphrontSideNavFilterView()) 10 + ->setBaseURI(new PhutilURI($this->getApplicationURI())) 11 + ->setViewer($viewer); 12 + 13 + $nav->addMenuItem( 14 + id(new PHUIListItemView()) 15 + ->setName(pht('Authentication')) 16 + ->setType(PHUIListItemView::TYPE_LABEL)); 17 + 18 + $nav->addMenuItem( 19 + id(new PHUIListItemView()) 20 + ->setKey('login') 21 + ->setName(pht('Login and Registration')) 22 + ->setType(PHUIListItemView::TYPE_LINK) 23 + ->setHref($this->getApplicationURI('/')) 24 + ->setIcon('fa-key')); 25 + 26 + $nav->addMenuItem( 27 + id(new PHUIListItemView()) 28 + ->setKey('mfa') 29 + ->setName(pht('Multi-Factor')) 30 + ->setType(PHUIListItemView::TYPE_LINK) 31 + ->setHref($this->getApplicationURI('mfa/')) 32 + ->setIcon('fa-mobile')); 33 + 34 + $nav->selectFilter(null); 35 + 36 + return $nav; 37 + } 38 + 39 + public function buildApplicationMenu() { 40 + return $this->newNavigation()->getMenu(); 41 + } 42 + 43 + }
+11
src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorAuthFactorProviderController 4 + extends PhabricatorAuthProviderController { 5 + 6 + protected function buildApplicationCrumbs() { 7 + return parent::buildApplicationCrumbs() 8 + ->addTextCrumb(pht('Multi-Factor'), $this->getApplicationURI('mfa/')); 9 + } 10 + 11 + }
+65
src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderEditController 4 + extends PhabricatorAuthFactorProviderController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $this->requireApplicationCapability( 8 + AuthManageProvidersCapability::CAPABILITY); 9 + 10 + $engine = id(new PhabricatorAuthFactorProviderEditEngine()) 11 + ->setController($this); 12 + 13 + $id = $request->getURIData('id'); 14 + if (!$id) { 15 + $factor_key = $request->getStr('providerFactorKey'); 16 + 17 + $map = PhabricatorAuthFactor::getAllFactors(); 18 + $factor = idx($map, $factor_key); 19 + if (!$factor) { 20 + return $this->buildFactorSelectionResponse(); 21 + } 22 + 23 + $engine 24 + ->addContextParameter('providerFactorKey', $factor_key) 25 + ->setProviderFactor($factor); 26 + } 27 + 28 + return $engine->buildResponse(); 29 + } 30 + 31 + private function buildFactorSelectionResponse() { 32 + $request = $this->getRequest(); 33 + $viewer = $this->getViewer(); 34 + 35 + $cancel_uri = $this->getApplicationURI('mfa/'); 36 + 37 + $factors = PhabricatorAuthFactor::getAllFactors(); 38 + 39 + $menu = id(new PHUIObjectItemListView()) 40 + ->setUser($viewer) 41 + ->setBig(true) 42 + ->setFlush(true); 43 + 44 + foreach ($factors as $factor_key => $factor) { 45 + $factor_uri = id(new PhutilURI('/mfa/edit/')) 46 + ->setQueryParam('providerFactorKey', $factor_key); 47 + $factor_uri = $this->getApplicationURI($factor_uri); 48 + 49 + $item = id(new PHUIObjectItemView()) 50 + ->setHeader($factor->getFactorName()) 51 + ->setHref($factor_uri) 52 + ->setClickable(true) 53 + ->setImageIcon($factor->newIconView()) 54 + ->addAttribute($factor->getFactorCreateHelp()); 55 + 56 + $menu->addItem($item); 57 + } 58 + 59 + return $this->newDialog() 60 + ->setTitle(pht('Choose Provider Type')) 61 + ->appendChild($menu) 62 + ->addCancelButton($cancel_uri); 63 + } 64 + 65 + }
+72
src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderListController 4 + extends PhabricatorAuthProviderController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $this->getViewer(); 8 + 9 + $can_manage = $this->hasApplicationCapability( 10 + AuthManageProvidersCapability::CAPABILITY); 11 + 12 + $providers = id(new PhabricatorAuthFactorProviderQuery()) 13 + ->setViewer($viewer) 14 + ->execute(); 15 + 16 + $list = new PHUIObjectItemListView(); 17 + foreach ($providers as $provider) { 18 + $item = id(new PHUIObjectItemView()) 19 + ->setObjectName($provider->getObjectName()) 20 + ->setHeader($provider->getDisplayName()) 21 + ->setHref($provider->getURI()); 22 + 23 + $list->addItem($item); 24 + } 25 + 26 + $list->setNoDataString( 27 + pht('You have not configured any multi-factor providers yet.')); 28 + 29 + $crumbs = $this->buildApplicationCrumbs() 30 + ->addTextCrumb(pht('Multi-Factor')) 31 + ->setBorder(true); 32 + 33 + $button = id(new PHUIButtonView()) 34 + ->setTag('a') 35 + ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) 36 + ->setHref($this->getApplicationURI('mfa/edit/')) 37 + ->setIcon('fa-plus') 38 + ->setDisabled(!$can_manage) 39 + ->setWorkflow(true) 40 + ->setText(pht('Add MFA Provider')); 41 + 42 + $list->setFlush(true); 43 + $list = id(new PHUIObjectBoxView()) 44 + ->setHeaderText(pht('MFA Providers')) 45 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 46 + ->appendChild($list); 47 + 48 + $title = pht('MFA Providers'); 49 + $header = id(new PHUIHeaderView()) 50 + ->setHeader($title) 51 + ->setHeaderIcon('fa-mobile') 52 + ->addActionLink($button); 53 + 54 + $view = id(new PHUITwoColumnView()) 55 + ->setHeader($header) 56 + ->setFooter( 57 + array( 58 + $list, 59 + )); 60 + 61 + $nav = $this->newNavigation() 62 + ->setCrumbs($crumbs) 63 + ->appendChild($view); 64 + 65 + $nav->selectFilter('mfa'); 66 + 67 + return $this->newPage() 68 + ->setTitle($title) 69 + ->appendChild($nav); 70 + } 71 + 72 + }
+100
src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderViewController 4 + extends PhabricatorAuthFactorProviderController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $this->getViewer(); 8 + 9 + $this->requireApplicationCapability( 10 + AuthManageProvidersCapability::CAPABILITY); 11 + 12 + $provider = id(new PhabricatorAuthFactorProviderQuery()) 13 + ->setViewer($viewer) 14 + ->withIDs(array($request->getURIData('id'))) 15 + ->executeOne(); 16 + if (!$provider) { 17 + return new Aphront404Response(); 18 + } 19 + 20 + $crumbs = $this->buildApplicationCrumbs() 21 + ->addTextCrumb($provider->getObjectName()) 22 + ->setBorder(true); 23 + 24 + $header = $this->buildHeaderView($provider); 25 + $properties = $this->buildPropertiesView($provider); 26 + $curtain = $this->buildCurtain($provider); 27 + 28 + 29 + $timeline = $this->buildTransactionTimeline( 30 + $provider, 31 + new PhabricatorAuthFactorProviderTransactionQuery()); 32 + $timeline->setShouldTerminate(true); 33 + 34 + $view = id(new PHUITwoColumnView()) 35 + ->setHeader($header) 36 + ->setCurtain($curtain) 37 + ->setMainColumn( 38 + array( 39 + $timeline, 40 + )) 41 + ->addPropertySection(pht('Details'), $properties); 42 + 43 + return $this->newPage() 44 + ->setTitle($provider->getDisplayName()) 45 + ->setCrumbs($crumbs) 46 + ->setPageObjectPHIDs( 47 + array( 48 + $provider->getPHID(), 49 + )) 50 + ->appendChild($view); 51 + } 52 + 53 + private function buildHeaderView(PhabricatorAuthFactorProvider $provider) { 54 + $viewer = $this->getViewer(); 55 + 56 + $view = id(new PHUIHeaderView()) 57 + ->setViewer($viewer) 58 + ->setHeader($provider->getDisplayName()) 59 + ->setPolicyObject($provider); 60 + 61 + return $view; 62 + } 63 + 64 + private function buildPropertiesView( 65 + PhabricatorAuthFactorProvider $provider) { 66 + $viewer = $this->getViewer(); 67 + 68 + $view = id(new PHUIPropertyListView()) 69 + ->setViewer($viewer); 70 + 71 + $view->addProperty( 72 + pht('Factor Type'), 73 + $provider->getFactor()->getFactorName()); 74 + 75 + return $view; 76 + } 77 + 78 + private function buildCurtain(PhabricatorAuthFactorProvider $provider) { 79 + $viewer = $this->getViewer(); 80 + $id = $provider->getID(); 81 + 82 + $can_edit = PhabricatorPolicyFilter::hasCapability( 83 + $viewer, 84 + $provider, 85 + PhabricatorPolicyCapability::CAN_EDIT); 86 + 87 + $curtain = $this->newCurtainView($provider); 88 + 89 + $curtain->addAction( 90 + id(new PhabricatorActionView()) 91 + ->setName(pht('Edit MFA Provider')) 92 + ->setIcon('fa-pencil') 93 + ->setHref($this->getApplicationURI("mfa/edit/{$id}/")) 94 + ->setDisabled(!$can_edit) 95 + ->setWorkflow(!$can_edit)); 96 + 97 + return $curtain; 98 + } 99 + 100 + }
+115
src/applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + private $providerFactor; 7 + 8 + const ENGINECONST = 'auth.factor.provider'; 9 + 10 + public function isEngineConfigurable() { 11 + return false; 12 + } 13 + 14 + public function getEngineName() { 15 + return pht('MFA Providers'); 16 + } 17 + 18 + public function getSummaryHeader() { 19 + return pht('Edit MFA Providers'); 20 + } 21 + 22 + public function getSummaryText() { 23 + return pht('This engine is used to edit MFA providers.'); 24 + } 25 + 26 + public function getEngineApplicationClass() { 27 + return 'PhabricatorAuthApplication'; 28 + } 29 + 30 + public function setProviderFactor(PhabricatorAuthFactor $factor) { 31 + $this->providerFactor = $factor; 32 + return $this; 33 + } 34 + 35 + public function getProviderFactor() { 36 + return $this->providerFactor; 37 + } 38 + 39 + protected function newEditableObject() { 40 + $factor = $this->getProviderFactor(); 41 + if ($factor) { 42 + $provider = PhabricatorAuthFactorProvider::initializeNewProvider($factor); 43 + } else { 44 + $provider = new PhabricatorAuthFactorProvider(); 45 + } 46 + 47 + return $provider; 48 + } 49 + 50 + protected function newObjectQuery() { 51 + return new PhabricatorAuthFactorProviderQuery(); 52 + } 53 + 54 + protected function getObjectCreateTitleText($object) { 55 + return pht('Create MFA Provider'); 56 + } 57 + 58 + protected function getObjectCreateButtonText($object) { 59 + return pht('Create MFA Provider'); 60 + } 61 + 62 + protected function getObjectEditTitleText($object) { 63 + return pht('Edit MFA Provider'); 64 + } 65 + 66 + protected function getObjectEditShortText($object) { 67 + return $object->getObjectName(); 68 + } 69 + 70 + protected function getObjectCreateShortText() { 71 + return pht('Create MFA Provider'); 72 + } 73 + 74 + protected function getObjectName() { 75 + return pht('MFA Provider'); 76 + } 77 + 78 + protected function getEditorURI() { 79 + return '/auth/mfa/edit/'; 80 + } 81 + 82 + protected function getObjectCreateCancelURI($object) { 83 + return '/auth/mfa/'; 84 + } 85 + 86 + protected function getObjectViewURI($object) { 87 + return $object->getURI(); 88 + } 89 + 90 + protected function getCreateNewObjectPolicy() { 91 + return $this->getApplication()->getPolicy( 92 + AuthManageProvidersCapability::CAPABILITY); 93 + } 94 + 95 + protected function buildCustomEditFields($object) { 96 + $factor_name = $object->getFactor()->getFactorName(); 97 + 98 + return array( 99 + id(new PhabricatorStaticEditField()) 100 + ->setKey('displayType') 101 + ->setLabel(pht('Factor Type')) 102 + ->setDescription(pht('Type of the MFA provider.')) 103 + ->setValue($factor_name), 104 + id(new PhabricatorTextEditField()) 105 + ->setKey('name') 106 + ->setTransactionType( 107 + PhabricatorAuthFactorProviderNameTransaction::TRANSACTIONTYPE) 108 + ->setLabel(pht('Name')) 109 + ->setDescription(pht('Display name for the MFA provider.')) 110 + ->setValue($object->getName()) 111 + ->setPlaceholder($factor_name), 112 + ); 113 + } 114 + 115 + }
+22
src/applications/auth/editor/PhabricatorAuthFactorProviderEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorAuthApplication'; 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('MFA Providers'); 12 + } 13 + 14 + public function getCreateObjectTitle($author, $object) { 15 + return pht('%s created this MFA provider.', $author); 16 + } 17 + 18 + public function getCreateObjectTitleForFeed($author, $object) { 19 + return pht('%s created %s.', $author, $object); 20 + } 21 + 22 + }
+6
src/applications/auth/factor/PhabricatorAuthFactor.php
··· 4 4 5 5 abstract public function getFactorName(); 6 6 abstract public function getFactorKey(); 7 + abstract public function getFactorCreateHelp(); 7 8 abstract public function getFactorDescription(); 8 9 abstract public function processAddFactorForm( 9 10 AphrontFormView $form, ··· 37 38 38 39 protected function newResult() { 39 40 return new PhabricatorAuthFactorResult(); 41 + } 42 + 43 + public function newIconView() { 44 + return id(new PHUIIconView()) 45 + ->setIcon('fa-mobile'); 40 46 } 41 47 42 48 protected function newChallenge(
+6
src/applications/auth/factor/PhabricatorTOTPAuthFactor.php
··· 12 12 return pht('Mobile Phone App (TOTP)'); 13 13 } 14 14 15 + public function getFactorCreateHelp() { 16 + return pht( 17 + 'Allow users to attach a mobile authenticator application (like '. 18 + 'Google Authenticator) to their account.'); 19 + } 20 + 15 21 public function getFactorDescription() { 16 22 return pht( 17 23 'Attach a mobile authenticator application (like Authy '.
+40
src/applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthAuthFactorProviderPHIDType 4 + extends PhabricatorPHIDType { 5 + 6 + const TYPECONST = 'FPRV'; 7 + 8 + public function getTypeName() { 9 + return pht('MFA Provider'); 10 + } 11 + 12 + public function newObject() { 13 + return new PhabricatorAuthFactorProvider(); 14 + } 15 + 16 + public function getPHIDTypeApplicationClass() { 17 + return 'PhabricatorAuthApplication'; 18 + } 19 + 20 + protected function buildQueryForObjects( 21 + PhabricatorObjectQuery $query, 22 + array $phids) { 23 + 24 + return id(new PhabricatorAuthFactorProviderQuery()) 25 + ->withPHIDs($phids); 26 + } 27 + 28 + public function loadHandles( 29 + PhabricatorHandleQuery $query, 30 + array $handles, 31 + array $objects) { 32 + 33 + foreach ($handles as $phid => $handle) { 34 + $provider = $objects[$phid]; 35 + 36 + $handle->setURI($provider->getURI()); 37 + } 38 + } 39 + 40 + }
+67
src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + 9 + public function withIDs(array $ids) { 10 + $this->ids = $ids; 11 + return $this; 12 + } 13 + 14 + public function withPHIDs(array $phids) { 15 + $this->phids = $phids; 16 + return $this; 17 + } 18 + public function newResultObject() { 19 + return new PhabricatorAuthFactorProvider(); 20 + } 21 + 22 + protected function loadPage() { 23 + return $this->loadStandardPage($this->newResultObject()); 24 + } 25 + 26 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 27 + $where = parent::buildWhereClauseParts($conn); 28 + 29 + if ($this->ids !== null) { 30 + $where[] = qsprintf( 31 + $conn, 32 + 'id IN (%Ld)', 33 + $this->ids); 34 + } 35 + 36 + if ($this->phids !== null) { 37 + $where[] = qsprintf( 38 + $conn, 39 + 'phid IN (%Ls)', 40 + $this->phids); 41 + } 42 + 43 + return $where; 44 + } 45 + 46 + protected function willFilterPage(array $providers) { 47 + $map = PhabricatorAuthFactor::getAllFactors(); 48 + foreach ($providers as $key => $provider) { 49 + $factor_key = $provider->getProviderFactorKey(); 50 + $factor = idx($map, $factor_key); 51 + 52 + if (!$factor) { 53 + unset($providers[$key]); 54 + continue; 55 + } 56 + 57 + $provider->attachFactor($factor); 58 + } 59 + 60 + return $providers; 61 + } 62 + 63 + public function getQueryApplicationClass() { 64 + return 'PhabricatorAuthApplication'; 65 + } 66 + 67 + }
+10
src/applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhabricatorAuthFactorProviderTransaction(); 8 + } 9 + 10 + }
+134
src/applications/auth/storage/PhabricatorAuthFactorProvider.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProvider 4 + extends PhabricatorAuthDAO 5 + implements 6 + PhabricatorApplicationTransactionInterface, 7 + PhabricatorPolicyInterface, 8 + PhabricatorExtendedPolicyInterface { 9 + 10 + protected $providerFactorKey; 11 + protected $name; 12 + protected $status; 13 + protected $properties = array(); 14 + 15 + private $factor = self::ATTACHABLE; 16 + 17 + const STATUS_ACTIVE = 'active'; 18 + const STATUS_DEPRECATED = 'deprecated'; 19 + const STATUS_DISABLED = 'disabled'; 20 + 21 + public static function initializeNewProvider(PhabricatorAuthFactor $factor) { 22 + return id(new self()) 23 + ->setProviderFactorKey($factor->getFactorKey()) 24 + ->attachFactor($factor) 25 + ->setStatus(self::STATUS_ACTIVE); 26 + } 27 + 28 + protected function getConfiguration() { 29 + return array( 30 + self::CONFIG_SERIALIZATION => array( 31 + 'properties' => self::SERIALIZATION_JSON, 32 + ), 33 + self::CONFIG_AUX_PHID => true, 34 + self::CONFIG_COLUMN_SCHEMA => array( 35 + 'providerFactorKey' => 'text64', 36 + 'name' => 'text255', 37 + 'status' => 'text32', 38 + ), 39 + ) + parent::getConfiguration(); 40 + } 41 + 42 + public function getPHIDType() { 43 + return PhabricatorAuthAuthFactorProviderPHIDType::TYPECONST; 44 + } 45 + 46 + public function getURI() { 47 + return '/auth/mfa/'.$this->getID().'/'; 48 + } 49 + 50 + public function getObjectName() { 51 + return pht('MFA Provider %d', $this->getID()); 52 + } 53 + 54 + public function getAuthFactorProviderProperty($key, $default = null) { 55 + return idx($this->properties, $key, $default); 56 + } 57 + 58 + public function setAuthFactorProviderProperty($key, $value) { 59 + $this->properties[$key] = $value; 60 + return $this; 61 + } 62 + 63 + public function attachFactor(PhabricatorAuthFactor $factor) { 64 + $this->factor = $factor; 65 + return $this; 66 + } 67 + 68 + public function getFactor() { 69 + return $this->assertAttached($this->factor); 70 + } 71 + 72 + public function getDisplayName() { 73 + $name = $this->getName(); 74 + if (strlen($name)) { 75 + return $name; 76 + } 77 + 78 + return $this->getFactor()->getFactorName(); 79 + } 80 + 81 + 82 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 83 + 84 + 85 + public function getApplicationTransactionEditor() { 86 + return new PhabricatorAuthFactorProviderEditor(); 87 + } 88 + 89 + public function getApplicationTransactionTemplate() { 90 + return new PhabricatorAuthFactorProviderTransaction(); 91 + } 92 + 93 + 94 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 95 + 96 + 97 + public function getCapabilities() { 98 + return array( 99 + PhabricatorPolicyCapability::CAN_VIEW, 100 + PhabricatorPolicyCapability::CAN_EDIT, 101 + ); 102 + } 103 + 104 + public function getPolicy($capability) { 105 + return PhabricatorPolicies::getMostOpenPolicy(); 106 + } 107 + 108 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 109 + return false; 110 + } 111 + 112 + 113 + /* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ 114 + 115 + 116 + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { 117 + $extended = array(); 118 + 119 + switch ($capability) { 120 + case PhabricatorPolicyCapability::CAN_VIEW: 121 + break; 122 + case PhabricatorPolicyCapability::CAN_EDIT: 123 + $extended[] = array( 124 + new PhabricatorAuthApplication(), 125 + AuthManageProvidersCapability::CAPABILITY, 126 + ); 127 + break; 128 + } 129 + 130 + return $extended; 131 + } 132 + 133 + 134 + }
+18
src/applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderTransaction 4 + extends PhabricatorModularTransaction { 5 + 6 + public function getApplicationName() { 7 + return 'auth'; 8 + } 9 + 10 + public function getApplicationTransactionType() { 11 + return PhabricatorAuthAuthFactorProviderPHIDType::TYPECONST; 12 + } 13 + 14 + public function getBaseTransactionClass() { 15 + return 'PhabricatorAuthFactorProviderTransactionType'; 16 + } 17 + 18 + }
+69
src/applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthFactorProviderNameTransaction 4 + extends PhabricatorAuthFactorProviderTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'name'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getName(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setName($value); 14 + } 15 + 16 + public function getTitle() { 17 + $old = $this->getOldValue(); 18 + $new = $this->getNewValue(); 19 + 20 + if (!strlen($old)) { 21 + return pht( 22 + '%s named this provider %s.', 23 + $this->renderAuthor(), 24 + $this->renderNewValue()); 25 + } else if (!strlen($new)) { 26 + return pht( 27 + '%s removed the name (%s) of this provider.', 28 + $this->renderAuthor(), 29 + $this->renderOldValue()); 30 + } else { 31 + return pht( 32 + '%s renamed this provider from %s to %s.', 33 + $this->renderAuthor(), 34 + $this->renderOldValue(), 35 + $this->renderNewValue()); 36 + } 37 + } 38 + 39 + public function validateTransactions($object, array $xactions) { 40 + $errors = array(); 41 + 42 + $max_length = $object->getColumnMaximumByteLength('name'); 43 + foreach ($xactions as $xaction) { 44 + $new_value = $xaction->getNewValue(); 45 + $new_length = strlen($new_value); 46 + if ($new_length > $max_length) { 47 + $errors[] = $this->newInvalidError( 48 + pht( 49 + 'Provider names can not be longer than %s characters.', 50 + new PhutilNumber($max_length)), 51 + $xaction); 52 + } 53 + } 54 + 55 + return $errors; 56 + } 57 + 58 + public function getTransactionTypeForConduit($xaction) { 59 + return 'name'; 60 + } 61 + 62 + public function getFieldValuesForConduit($xaction, $data) { 63 + return array( 64 + 'old' => $xaction->getOldValue(), 65 + 'new' => $xaction->getNewValue(), 66 + ); 67 + } 68 + 69 + }
+4
src/applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorAuthFactorProviderTransactionType 4 + extends PhabricatorModularTransactionType {}