Page MenuHomePhabricator

D19935.id.diff
No OneTemporary

D19935.id.diff

diff --git a/resources/sql/autopatches/20181228.auth.01.provider.sql b/resources/sql/autopatches/20181228.auth.01.provider.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20181228.auth.01.provider.sql
@@ -0,0 +1,9 @@
+CREATE TABLE {$NAMESPACE}_auth.auth_factorprovider (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ providerFactorKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
+ status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
+ properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20181228.auth.02.xaction.sql b/resources/sql/autopatches/20181228.auth.02.xaction.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20181228.auth.02.xaction.sql
@@ -0,0 +1,19 @@
+CREATE TABLE {$NAMESPACE}_auth.auth_factorprovidertransaction (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ objectPHID VARBINARY(64) NOT NULL,
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ commentPHID VARBINARY(64) DEFAULT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) NOT NULL,
+ oldValue LONGTEXT NOT NULL,
+ newValue LONGTEXT NOT NULL,
+ contentSource LONGTEXT NOT NULL,
+ metadata LONGTEXT NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (`phid`),
+ KEY `key_object` (`objectPHID`)
+) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20181228.auth.03.name.sql b/resources/sql/autopatches/20181228.auth.03.name.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20181228.auth.03.name.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_auth.auth_factorprovider
+ ADD name VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2190,6 +2190,7 @@
'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php',
'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php',
'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php',
+ 'PhabricatorAuthAuthFactorProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php',
'PhabricatorAuthAuthProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthProviderPHIDType.php',
'PhabricatorAuthCSRFEngine' => 'applications/auth/engine/PhabricatorAuthCSRFEngine.php',
'PhabricatorAuthChallenge' => 'applications/auth/storage/PhabricatorAuthChallenge.php',
@@ -2207,6 +2208,18 @@
'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php',
'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php',
'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php',
+ 'PhabricatorAuthFactorProvider' => 'applications/auth/storage/PhabricatorAuthFactorProvider.php',
+ 'PhabricatorAuthFactorProviderController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php',
+ 'PhabricatorAuthFactorProviderEditController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php',
+ 'PhabricatorAuthFactorProviderEditEngine' => 'applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php',
+ 'PhabricatorAuthFactorProviderEditor' => 'applications/auth/editor/PhabricatorAuthFactorProviderEditor.php',
+ 'PhabricatorAuthFactorProviderListController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php',
+ 'PhabricatorAuthFactorProviderNameTransaction' => 'applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php',
+ 'PhabricatorAuthFactorProviderQuery' => 'applications/auth/query/PhabricatorAuthFactorProviderQuery.php',
+ 'PhabricatorAuthFactorProviderTransaction' => 'applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php',
+ 'PhabricatorAuthFactorProviderTransactionQuery' => 'applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php',
+ 'PhabricatorAuthFactorProviderTransactionType' => 'applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php',
+ 'PhabricatorAuthFactorProviderViewController' => 'applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php',
'PhabricatorAuthFactorResult' => 'applications/auth/factor/PhabricatorAuthFactorResult.php',
'PhabricatorAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php',
'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php',
@@ -2277,6 +2290,7 @@
'PhabricatorAuthProviderConfigQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigQuery.php',
'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php',
'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php',
+ 'PhabricatorAuthProviderController' => 'applications/auth/controller/config/PhabricatorAuthProviderController.php',
'PhabricatorAuthProvidersGuidanceContext' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceContext.php',
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php',
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php',
@@ -7835,6 +7849,7 @@
'PhabricatorAuthAccountView' => 'AphrontView',
'PhabricatorAuthApplication' => 'PhabricatorApplication',
'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorAuthAuthFactorProviderPHIDType' => 'PhabricatorPHIDType',
'PhabricatorAuthAuthProviderPHIDType' => 'PhabricatorPHIDType',
'PhabricatorAuthCSRFEngine' => 'Phobject',
'PhabricatorAuthChallenge' => array(
@@ -7855,6 +7870,23 @@
'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthFactor' => 'Phobject',
'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO',
+ 'PhabricatorAuthFactorProvider' => array(
+ 'PhabricatorAuthDAO',
+ 'PhabricatorApplicationTransactionInterface',
+ 'PhabricatorPolicyInterface',
+ 'PhabricatorExtendedPolicyInterface',
+ ),
+ 'PhabricatorAuthFactorProviderController' => 'PhabricatorAuthProviderController',
+ 'PhabricatorAuthFactorProviderEditController' => 'PhabricatorAuthFactorProviderController',
+ 'PhabricatorAuthFactorProviderEditEngine' => 'PhabricatorEditEngine',
+ 'PhabricatorAuthFactorProviderEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'PhabricatorAuthFactorProviderListController' => 'PhabricatorAuthProviderController',
+ 'PhabricatorAuthFactorProviderNameTransaction' => 'PhabricatorAuthFactorProviderTransactionType',
+ 'PhabricatorAuthFactorProviderQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorAuthFactorProviderTransaction' => 'PhabricatorModularTransaction',
+ 'PhabricatorAuthFactorProviderTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorAuthFactorProviderTransactionType' => 'PhabricatorModularTransactionType',
+ 'PhabricatorAuthFactorProviderViewController' => 'PhabricatorAuthFactorProviderController',
'PhabricatorAuthFactorResult' => 'Phobject',
'PhabricatorAuthFactorTestCase' => 'PhabricatorTestCase',
'PhabricatorAuthFinishController' => 'PhabricatorAuthController',
@@ -7931,11 +7963,12 @@
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
),
- 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthController',
+ 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthProviderController',
'PhabricatorAuthProviderConfigEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorAuthProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorAuthProviderController' => 'PhabricatorAuthController',
'PhabricatorAuthProvidersGuidanceContext' => 'PhabricatorGuidanceContext',
'PhabricatorAuthProvidersGuidanceEngineExtension' => 'PhabricatorGuidanceEngineExtension',
'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod',
diff --git a/src/applications/auth/application/PhabricatorAuthApplication.php b/src/applications/auth/application/PhabricatorAuthApplication.php
--- a/src/applications/auth/application/PhabricatorAuthApplication.php
+++ b/src/applications/auth/application/PhabricatorAuthApplication.php
@@ -85,6 +85,15 @@
'view/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyViewController',
),
'password/' => 'PhabricatorAuthSetPasswordController',
+
+ 'mfa/' => array(
+ $this->getQueryRoutePattern() =>
+ 'PhabricatorAuthFactorProviderListController',
+ $this->getEditRoutePattern('edit/') =>
+ 'PhabricatorAuthFactorProviderEditController',
+ '(?P<id>[1-9]\d*)/' =>
+ 'PhabricatorAuthFactorProviderViewController',
+ ),
),
'/oauth/(?P<provider>\w+)/login/'
diff --git a/src/applications/auth/controller/config/PhabricatorAuthListController.php b/src/applications/auth/controller/config/PhabricatorAuthListController.php
--- a/src/applications/auth/controller/config/PhabricatorAuthListController.php
+++ b/src/applications/auth/controller/config/PhabricatorAuthListController.php
@@ -91,7 +91,7 @@
pht('Add Authentication Provider'))));
$crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(pht('Auth Providers'));
+ $crumbs->addTextCrumb(pht('Login and Registration'));
$crumbs->setBorder(true);
$guidance_context = new PhabricatorAuthProvidersGuidanceContext();
@@ -102,12 +102,12 @@
->newInfoView();
$button = id(new PHUIButtonView())
- ->setTag('a')
- ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
- ->setHref($this->getApplicationURI('config/new/'))
- ->setIcon('fa-plus')
- ->setDisabled(!$can_manage)
- ->setText(pht('Add Provider'));
+ ->setTag('a')
+ ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
+ ->setHref($this->getApplicationURI('config/new/'))
+ ->setIcon('fa-plus')
+ ->setDisabled(!$can_manage)
+ ->setText(pht('Add Provider'));
$list->setFlush(true);
$list = id(new PHUIObjectBoxView())
@@ -115,7 +115,7 @@
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($list);
- $title = pht('Auth Providers');
+ $title = pht('Login and Registration Providers');
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon('fa-key')
@@ -128,10 +128,15 @@
$list,
));
- return $this->newPage()
- ->setTitle($title)
+ $nav = $this->newNavigation()
->setCrumbs($crumbs)
->appendChild($view);
+
+ $nav->selectFilter('login');
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->appendChild($nav);
}
}
diff --git a/src/applications/auth/controller/config/PhabricatorAuthProviderConfigController.php b/src/applications/auth/controller/config/PhabricatorAuthProviderConfigController.php
--- a/src/applications/auth/controller/config/PhabricatorAuthProviderConfigController.php
+++ b/src/applications/auth/controller/config/PhabricatorAuthProviderConfigController.php
@@ -1,32 +1,4 @@
<?php
abstract class PhabricatorAuthProviderConfigController
- extends PhabricatorAuthController {
-
- protected function buildSideNavView($for_app = false) {
- $nav = new AphrontSideNavFilterView();
- $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
-
- if ($for_app) {
- $nav->addLabel(pht('Create'));
- $nav->addFilter('',
- pht('Add Authentication Provider'),
- $this->getApplicationURI('/config/new/'));
- }
- return $nav;
- }
-
- public function buildApplicationMenu() {
- return $this->buildSideNavView($for_app = true)->getMenu();
- }
-
- protected function buildApplicationCrumbs() {
- $crumbs = parent::buildApplicationCrumbs();
-
- $can_create = $this->hasApplicationCapability(
- AuthManageProvidersCapability::CAPABILITY);
-
- return $crumbs;
- }
-
-}
+ extends PhabricatorAuthProviderController {}
diff --git a/src/applications/auth/controller/config/PhabricatorAuthProviderController.php b/src/applications/auth/controller/config/PhabricatorAuthProviderController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/config/PhabricatorAuthProviderController.php
@@ -0,0 +1,43 @@
+<?php
+
+abstract class PhabricatorAuthProviderController
+ extends PhabricatorAuthController {
+
+ protected function newNavigation() {
+ $viewer = $this->getViewer();
+
+ $nav = id(new AphrontSideNavFilterView())
+ ->setBaseURI(new PhutilURI($this->getApplicationURI()))
+ ->setViewer($viewer);
+
+ $nav->addMenuItem(
+ id(new PHUIListItemView())
+ ->setName(pht('Authentication'))
+ ->setType(PHUIListItemView::TYPE_LABEL));
+
+ $nav->addMenuItem(
+ id(new PHUIListItemView())
+ ->setKey('login')
+ ->setName(pht('Login and Registration'))
+ ->setType(PHUIListItemView::TYPE_LINK)
+ ->setHref($this->getApplicationURI('/'))
+ ->setIcon('fa-key'));
+
+ $nav->addMenuItem(
+ id(new PHUIListItemView())
+ ->setKey('mfa')
+ ->setName(pht('Multi-Factor'))
+ ->setType(PHUIListItemView::TYPE_LINK)
+ ->setHref($this->getApplicationURI('mfa/'))
+ ->setIcon('fa-mobile'));
+
+ $nav->selectFilter(null);
+
+ return $nav;
+ }
+
+ public function buildApplicationMenu() {
+ return $this->newNavigation()->getMenu();
+ }
+
+}
diff --git a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderController.php
@@ -0,0 +1,11 @@
+<?php
+
+abstract class PhabricatorAuthFactorProviderController
+ extends PhabricatorAuthProviderController {
+
+ protected function buildApplicationCrumbs() {
+ return parent::buildApplicationCrumbs()
+ ->addTextCrumb(pht('Multi-Factor'), $this->getApplicationURI('mfa/'));
+ }
+
+}
diff --git a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderEditController.php
@@ -0,0 +1,65 @@
+<?php
+
+final class PhabricatorAuthFactorProviderEditController
+ extends PhabricatorAuthFactorProviderController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $this->requireApplicationCapability(
+ AuthManageProvidersCapability::CAPABILITY);
+
+ $engine = id(new PhabricatorAuthFactorProviderEditEngine())
+ ->setController($this);
+
+ $id = $request->getURIData('id');
+ if (!$id) {
+ $factor_key = $request->getStr('providerFactorKey');
+
+ $map = PhabricatorAuthFactor::getAllFactors();
+ $factor = idx($map, $factor_key);
+ if (!$factor) {
+ return $this->buildFactorSelectionResponse();
+ }
+
+ $engine
+ ->addContextParameter('providerFactorKey', $factor_key)
+ ->setProviderFactor($factor);
+ }
+
+ return $engine->buildResponse();
+ }
+
+ private function buildFactorSelectionResponse() {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $cancel_uri = $this->getApplicationURI('mfa/');
+
+ $factors = PhabricatorAuthFactor::getAllFactors();
+
+ $menu = id(new PHUIObjectItemListView())
+ ->setUser($viewer)
+ ->setBig(true)
+ ->setFlush(true);
+
+ foreach ($factors as $factor_key => $factor) {
+ $factor_uri = id(new PhutilURI('/mfa/edit/'))
+ ->setQueryParam('providerFactorKey', $factor_key);
+ $factor_uri = $this->getApplicationURI($factor_uri);
+
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($factor->getFactorName())
+ ->setHref($factor_uri)
+ ->setClickable(true)
+ ->setImageIcon($factor->newIconView())
+ ->addAttribute($factor->getFactorCreateHelp());
+
+ $menu->addItem($item);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Choose Provider Type'))
+ ->appendChild($menu)
+ ->addCancelButton($cancel_uri);
+ }
+
+}
diff --git a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderListController.php
@@ -0,0 +1,72 @@
+<?php
+
+final class PhabricatorAuthFactorProviderListController
+ extends PhabricatorAuthProviderController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $can_manage = $this->hasApplicationCapability(
+ AuthManageProvidersCapability::CAPABILITY);
+
+ $providers = id(new PhabricatorAuthFactorProviderQuery())
+ ->setViewer($viewer)
+ ->execute();
+
+ $list = new PHUIObjectItemListView();
+ foreach ($providers as $provider) {
+ $item = id(new PHUIObjectItemView())
+ ->setObjectName($provider->getObjectName())
+ ->setHeader($provider->getDisplayName())
+ ->setHref($provider->getURI());
+
+ $list->addItem($item);
+ }
+
+ $list->setNoDataString(
+ pht('You have not configured any multi-factor providers yet.'));
+
+ $crumbs = $this->buildApplicationCrumbs()
+ ->addTextCrumb(pht('Multi-Factor'))
+ ->setBorder(true);
+
+ $button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
+ ->setHref($this->getApplicationURI('mfa/edit/'))
+ ->setIcon('fa-plus')
+ ->setDisabled(!$can_manage)
+ ->setWorkflow(true)
+ ->setText(pht('Add MFA Provider'));
+
+ $list->setFlush(true);
+ $list = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('MFA Providers'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($list);
+
+ $title = pht('MFA Providers');
+ $header = id(new PHUIHeaderView())
+ ->setHeader($title)
+ ->setHeaderIcon('fa-mobile')
+ ->addActionLink($button);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter(
+ array(
+ $list,
+ ));
+
+ $nav = $this->newNavigation()
+ ->setCrumbs($crumbs)
+ ->appendChild($view);
+
+ $nav->selectFilter('mfa');
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->appendChild($nav);
+ }
+
+}
diff --git a/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/mfa/PhabricatorAuthFactorProviderViewController.php
@@ -0,0 +1,100 @@
+<?php
+
+final class PhabricatorAuthFactorProviderViewController
+ extends PhabricatorAuthFactorProviderController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $this->requireApplicationCapability(
+ AuthManageProvidersCapability::CAPABILITY);
+
+ $provider = id(new PhabricatorAuthFactorProviderQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($request->getURIData('id')))
+ ->executeOne();
+ if (!$provider) {
+ return new Aphront404Response();
+ }
+
+ $crumbs = $this->buildApplicationCrumbs()
+ ->addTextCrumb($provider->getObjectName())
+ ->setBorder(true);
+
+ $header = $this->buildHeaderView($provider);
+ $properties = $this->buildPropertiesView($provider);
+ $curtain = $this->buildCurtain($provider);
+
+
+ $timeline = $this->buildTransactionTimeline(
+ $provider,
+ new PhabricatorAuthFactorProviderTransactionQuery());
+ $timeline->setShouldTerminate(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->setMainColumn(
+ array(
+ $timeline,
+ ))
+ ->addPropertySection(pht('Details'), $properties);
+
+ return $this->newPage()
+ ->setTitle($provider->getDisplayName())
+ ->setCrumbs($crumbs)
+ ->setPageObjectPHIDs(
+ array(
+ $provider->getPHID(),
+ ))
+ ->appendChild($view);
+ }
+
+ private function buildHeaderView(PhabricatorAuthFactorProvider $provider) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PHUIHeaderView())
+ ->setViewer($viewer)
+ ->setHeader($provider->getDisplayName())
+ ->setPolicyObject($provider);
+
+ return $view;
+ }
+
+ private function buildPropertiesView(
+ PhabricatorAuthFactorProvider $provider) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PHUIPropertyListView())
+ ->setViewer($viewer);
+
+ $view->addProperty(
+ pht('Factor Type'),
+ $provider->getFactor()->getFactorName());
+
+ return $view;
+ }
+
+ private function buildCurtain(PhabricatorAuthFactorProvider $provider) {
+ $viewer = $this->getViewer();
+ $id = $provider->getID();
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $provider,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $curtain = $this->newCurtainView($provider);
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit MFA Provider'))
+ ->setIcon('fa-pencil')
+ ->setHref($this->getApplicationURI("mfa/edit/{$id}/"))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit));
+
+ return $curtain;
+ }
+
+}
diff --git a/src/applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php b/src/applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/editor/PhabricatorAuthFactorProviderEditEngine.php
@@ -0,0 +1,115 @@
+<?php
+
+final class PhabricatorAuthFactorProviderEditEngine
+ extends PhabricatorEditEngine {
+
+ private $providerFactor;
+
+ const ENGINECONST = 'auth.factor.provider';
+
+ public function isEngineConfigurable() {
+ return false;
+ }
+
+ public function getEngineName() {
+ return pht('MFA Providers');
+ }
+
+ public function getSummaryHeader() {
+ return pht('Edit MFA Providers');
+ }
+
+ public function getSummaryText() {
+ return pht('This engine is used to edit MFA providers.');
+ }
+
+ public function getEngineApplicationClass() {
+ return 'PhabricatorAuthApplication';
+ }
+
+ public function setProviderFactor(PhabricatorAuthFactor $factor) {
+ $this->providerFactor = $factor;
+ return $this;
+ }
+
+ public function getProviderFactor() {
+ return $this->providerFactor;
+ }
+
+ protected function newEditableObject() {
+ $factor = $this->getProviderFactor();
+ if ($factor) {
+ $provider = PhabricatorAuthFactorProvider::initializeNewProvider($factor);
+ } else {
+ $provider = new PhabricatorAuthFactorProvider();
+ }
+
+ return $provider;
+ }
+
+ protected function newObjectQuery() {
+ return new PhabricatorAuthFactorProviderQuery();
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create MFA Provider');
+ }
+
+ protected function getObjectCreateButtonText($object) {
+ return pht('Create MFA Provider');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit MFA Provider');
+ }
+
+ protected function getObjectEditShortText($object) {
+ return $object->getObjectName();
+ }
+
+ protected function getObjectCreateShortText() {
+ return pht('Create MFA Provider');
+ }
+
+ protected function getObjectName() {
+ return pht('MFA Provider');
+ }
+
+ protected function getEditorURI() {
+ return '/auth/mfa/edit/';
+ }
+
+ protected function getObjectCreateCancelURI($object) {
+ return '/auth/mfa/';
+ }
+
+ protected function getObjectViewURI($object) {
+ return $object->getURI();
+ }
+
+ protected function getCreateNewObjectPolicy() {
+ return $this->getApplication()->getPolicy(
+ AuthManageProvidersCapability::CAPABILITY);
+ }
+
+ protected function buildCustomEditFields($object) {
+ $factor_name = $object->getFactor()->getFactorName();
+
+ return array(
+ id(new PhabricatorStaticEditField())
+ ->setKey('displayType')
+ ->setLabel(pht('Factor Type'))
+ ->setDescription(pht('Type of the MFA provider.'))
+ ->setValue($factor_name),
+ id(new PhabricatorTextEditField())
+ ->setKey('name')
+ ->setTransactionType(
+ PhabricatorAuthFactorProviderNameTransaction::TRANSACTIONTYPE)
+ ->setLabel(pht('Name'))
+ ->setDescription(pht('Display name for the MFA provider.'))
+ ->setValue($object->getName())
+ ->setPlaceholder($factor_name),
+ );
+ }
+
+}
diff --git a/src/applications/auth/editor/PhabricatorAuthFactorProviderEditor.php b/src/applications/auth/editor/PhabricatorAuthFactorProviderEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/editor/PhabricatorAuthFactorProviderEditor.php
@@ -0,0 +1,22 @@
+<?php
+
+final class PhabricatorAuthFactorProviderEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorAuthApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('MFA Providers');
+ }
+
+ public function getCreateObjectTitle($author, $object) {
+ return pht('%s created this MFA provider.', $author);
+ }
+
+ public function getCreateObjectTitleForFeed($author, $object) {
+ return pht('%s created %s.', $author, $object);
+ }
+
+}
diff --git a/src/applications/auth/factor/PhabricatorAuthFactor.php b/src/applications/auth/factor/PhabricatorAuthFactor.php
--- a/src/applications/auth/factor/PhabricatorAuthFactor.php
+++ b/src/applications/auth/factor/PhabricatorAuthFactor.php
@@ -4,6 +4,7 @@
abstract public function getFactorName();
abstract public function getFactorKey();
+ abstract public function getFactorCreateHelp();
abstract public function getFactorDescription();
abstract public function processAddFactorForm(
AphrontFormView $form,
@@ -39,6 +40,11 @@
return new PhabricatorAuthFactorResult();
}
+ public function newIconView() {
+ return id(new PHUIIconView())
+ ->setIcon('fa-mobile');
+ }
+
protected function newChallenge(
PhabricatorAuthFactorConfig $config,
PhabricatorUser $viewer) {
diff --git a/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php b/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php
--- a/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php
+++ b/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php
@@ -12,6 +12,12 @@
return pht('Mobile Phone App (TOTP)');
}
+ public function getFactorCreateHelp() {
+ return pht(
+ 'Allow users to attach a mobile authenticator application (like '.
+ 'Google Authenticator) to their account.');
+ }
+
public function getFactorDescription() {
return pht(
'Attach a mobile authenticator application (like Authy '.
diff --git a/src/applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php b/src/applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/phid/PhabricatorAuthAuthFactorProviderPHIDType.php
@@ -0,0 +1,40 @@
+<?php
+
+final class PhabricatorAuthAuthFactorProviderPHIDType
+ extends PhabricatorPHIDType {
+
+ const TYPECONST = 'FPRV';
+
+ public function getTypeName() {
+ return pht('MFA Provider');
+ }
+
+ public function newObject() {
+ return new PhabricatorAuthFactorProvider();
+ }
+
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorAuthApplication';
+ }
+
+ protected function buildQueryForObjects(
+ PhabricatorObjectQuery $query,
+ array $phids) {
+
+ return id(new PhabricatorAuthFactorProviderQuery())
+ ->withPHIDs($phids);
+ }
+
+ public function loadHandles(
+ PhabricatorHandleQuery $query,
+ array $handles,
+ array $objects) {
+
+ foreach ($handles as $phid => $handle) {
+ $provider = $objects[$phid];
+
+ $handle->setURI($provider->getURI());
+ }
+ }
+
+}
diff --git a/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php b/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php
@@ -0,0 +1,67 @@
+<?php
+
+final class PhabricatorAuthFactorProviderQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $phids;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+ public function newResultObject() {
+ return new PhabricatorAuthFactorProvider();
+ }
+
+ protected function loadPage() {
+ return $this->loadStandardPage($this->newResultObject());
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ return $where;
+ }
+
+ protected function willFilterPage(array $providers) {
+ $map = PhabricatorAuthFactor::getAllFactors();
+ foreach ($providers as $key => $provider) {
+ $factor_key = $provider->getProviderFactorKey();
+ $factor = idx($map, $factor_key);
+
+ if (!$factor) {
+ unset($providers[$key]);
+ continue;
+ }
+
+ $provider->attachFactor($factor);
+ }
+
+ return $providers;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorAuthApplication';
+ }
+
+}
diff --git a/src/applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php b/src/applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/query/PhabricatorAuthFactorProviderTransactionQuery.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorAuthFactorProviderTransactionQuery
+ extends PhabricatorApplicationTransactionQuery {
+
+ public function getTemplateApplicationTransaction() {
+ return new PhabricatorAuthFactorProviderTransaction();
+ }
+
+}
diff --git a/src/applications/auth/storage/PhabricatorAuthFactorProvider.php b/src/applications/auth/storage/PhabricatorAuthFactorProvider.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/storage/PhabricatorAuthFactorProvider.php
@@ -0,0 +1,134 @@
+<?php
+
+final class PhabricatorAuthFactorProvider
+ extends PhabricatorAuthDAO
+ implements
+ PhabricatorApplicationTransactionInterface,
+ PhabricatorPolicyInterface,
+ PhabricatorExtendedPolicyInterface {
+
+ protected $providerFactorKey;
+ protected $name;
+ protected $status;
+ protected $properties = array();
+
+ private $factor = self::ATTACHABLE;
+
+ const STATUS_ACTIVE = 'active';
+ const STATUS_DEPRECATED = 'deprecated';
+ const STATUS_DISABLED = 'disabled';
+
+ public static function initializeNewProvider(PhabricatorAuthFactor $factor) {
+ return id(new self())
+ ->setProviderFactorKey($factor->getFactorKey())
+ ->attachFactor($factor)
+ ->setStatus(self::STATUS_ACTIVE);
+ }
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_SERIALIZATION => array(
+ 'properties' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'providerFactorKey' => 'text64',
+ 'name' => 'text255',
+ 'status' => 'text32',
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function getPHIDType() {
+ return PhabricatorAuthAuthFactorProviderPHIDType::TYPECONST;
+ }
+
+ public function getURI() {
+ return '/auth/mfa/'.$this->getID().'/';
+ }
+
+ public function getObjectName() {
+ return pht('MFA Provider %d', $this->getID());
+ }
+
+ public function getAuthFactorProviderProperty($key, $default = null) {
+ return idx($this->properties, $key, $default);
+ }
+
+ public function setAuthFactorProviderProperty($key, $value) {
+ $this->properties[$key] = $value;
+ return $this;
+ }
+
+ public function attachFactor(PhabricatorAuthFactor $factor) {
+ $this->factor = $factor;
+ return $this;
+ }
+
+ public function getFactor() {
+ return $this->assertAttached($this->factor);
+ }
+
+ public function getDisplayName() {
+ $name = $this->getName();
+ if (strlen($name)) {
+ return $name;
+ }
+
+ return $this->getFactor()->getFactorName();
+ }
+
+
+/* -( PhabricatorApplicationTransactionInterface )------------------------- */
+
+
+ public function getApplicationTransactionEditor() {
+ return new PhabricatorAuthFactorProviderEditor();
+ }
+
+ public function getApplicationTransactionTemplate() {
+ return new PhabricatorAuthFactorProviderTransaction();
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return PhabricatorPolicies::getMostOpenPolicy();
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return false;
+ }
+
+
+/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
+
+
+ public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
+ $extended = array();
+
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ break;
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ $extended[] = array(
+ new PhabricatorAuthApplication(),
+ AuthManageProvidersCapability::CAPABILITY,
+ );
+ break;
+ }
+
+ return $extended;
+ }
+
+
+}
diff --git a/src/applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php b/src/applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/storage/PhabricatorAuthFactorProviderTransaction.php
@@ -0,0 +1,18 @@
+<?php
+
+final class PhabricatorAuthFactorProviderTransaction
+ extends PhabricatorModularTransaction {
+
+ public function getApplicationName() {
+ return 'auth';
+ }
+
+ public function getApplicationTransactionType() {
+ return PhabricatorAuthAuthFactorProviderPHIDType::TYPECONST;
+ }
+
+ public function getBaseTransactionClass() {
+ return 'PhabricatorAuthFactorProviderTransactionType';
+ }
+
+}
diff --git a/src/applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php b/src/applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/xaction/PhabricatorAuthFactorProviderNameTransaction.php
@@ -0,0 +1,69 @@
+<?php
+
+final class PhabricatorAuthFactorProviderNameTransaction
+ extends PhabricatorAuthFactorProviderTransactionType {
+
+ const TRANSACTIONTYPE = 'name';
+
+ public function generateOldValue($object) {
+ return $object->getName();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setName($value);
+ }
+
+ public function getTitle() {
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ if (!strlen($old)) {
+ return pht(
+ '%s named this provider %s.',
+ $this->renderAuthor(),
+ $this->renderNewValue());
+ } else if (!strlen($new)) {
+ return pht(
+ '%s removed the name (%s) of this provider.',
+ $this->renderAuthor(),
+ $this->renderOldValue());
+ } else {
+ return pht(
+ '%s renamed this provider from %s to %s.',
+ $this->renderAuthor(),
+ $this->renderOldValue(),
+ $this->renderNewValue());
+ }
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $errors = array();
+
+ $max_length = $object->getColumnMaximumByteLength('name');
+ foreach ($xactions as $xaction) {
+ $new_value = $xaction->getNewValue();
+ $new_length = strlen($new_value);
+ if ($new_length > $max_length) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Provider names can not be longer than %s characters.',
+ new PhutilNumber($max_length)),
+ $xaction);
+ }
+ }
+
+ return $errors;
+ }
+
+ public function getTransactionTypeForConduit($xaction) {
+ return 'name';
+ }
+
+ public function getFieldValuesForConduit($xaction, $data) {
+ return array(
+ 'old' => $xaction->getOldValue(),
+ 'new' => $xaction->getNewValue(),
+ );
+ }
+
+}
diff --git a/src/applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php b/src/applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/xaction/PhabricatorAuthFactorProviderTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class PhabricatorAuthFactorProviderTransactionType
+ extends PhabricatorModularTransactionType {}

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 3, 11:39 PM (5 h, 20 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7088068
Default Alt Text
D19935.id.diff (37 KB)

Event Timeline