Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14845528
D19935.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
37 KB
Referenced Files
None
Subscribers
None
D19935.id.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D19935: Add a skeleton for configurable MFA provider types
Attached
Detach File
Event Timeline
Log In to Comment