1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-30 18:52:42 +01:00
phorge-phorge/src/applications/almanac/controller/AlmanacDeviceViewController.php

259 lines
7.2 KiB
PHP
Raw Normal View History

<?php
final class AlmanacDeviceViewController
extends AlmanacDeviceController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$name = $request->getURIData('name');
$device = id(new AlmanacDeviceQuery())
->setViewer($viewer)
->withNames(array($name))
->needProperties(true)
->executeOne();
if (!$device) {
return new Aphront404Response();
}
$title = pht('Device %s', $device->getName());
$properties = $this->buildPropertyList($device);
$actions = $this->buildActionList($device);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($device->getName())
->setPolicyObject($device)
->setHeaderIcon('fa-server');
$issue = null;
Simplify locking of Almanac cluster services Summary: Fixes T6741. Ref T10246. Broadly, we want to protect Almanac cluster services: - Today, against users in the Phacility cluster accidentally breaking their own instances. - In the future, against attackers compromising administrative accounts and adding a new "cluster database" which points at hardware they control. The way this works right now is really complicated: there's a global "can create cluster services" setting, and then separate per-service and per-device locks. Instead, change "Can Create Cluster Services" into "Can Manage Cluster Services". Require this permission (in addition to normal permissions) to edit or create any cluster service. This permission can be locked to "No One" via config (as we do in the Phacility cluster) so we only need this one simple setting. There's also zero reason to individually lock //some// of the cluster services. Also improve extended policy errors. The UI here is still a little heavy-handed, but should be good enough for the moment. Test Plan: - Ran migrations. - Verified that cluster services and bindings reported that they belonged to the cluster. - Edited a cluster binding. - Verified that the bound device was marked as a cluster device - Moved a cluster binding, verified the old device was unmarked as a cluster device. - Tried to edit a cluster device as an unprivileged user, got a sensible error. {F1126552} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15339
2016-02-24 01:23:40 +01:00
if ($device->isClusterDevice()) {
$issue = $this->addClusterMessage(
Simplify locking of Almanac cluster services Summary: Fixes T6741. Ref T10246. Broadly, we want to protect Almanac cluster services: - Today, against users in the Phacility cluster accidentally breaking their own instances. - In the future, against attackers compromising administrative accounts and adding a new "cluster database" which points at hardware they control. The way this works right now is really complicated: there's a global "can create cluster services" setting, and then separate per-service and per-device locks. Instead, change "Can Create Cluster Services" into "Can Manage Cluster Services". Require this permission (in addition to normal permissions) to edit or create any cluster service. This permission can be locked to "No One" via config (as we do in the Phacility cluster) so we only need this one simple setting. There's also zero reason to individually lock //some// of the cluster services. Also improve extended policy errors. The UI here is still a little heavy-handed, but should be good enough for the moment. Test Plan: - Ran migrations. - Verified that cluster services and bindings reported that they belonged to the cluster. - Edited a cluster binding. - Verified that the bound device was marked as a cluster device - Moved a cluster binding, verified the old device was unmarked as a cluster device. - Tried to edit a cluster device as an unprivileged user, got a sensible error. {F1126552} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15339
2016-02-24 01:23:40 +01:00
pht('This device is bound to a cluster service.'),
pht(
Simplify locking of Almanac cluster services Summary: Fixes T6741. Ref T10246. Broadly, we want to protect Almanac cluster services: - Today, against users in the Phacility cluster accidentally breaking their own instances. - In the future, against attackers compromising administrative accounts and adding a new "cluster database" which points at hardware they control. The way this works right now is really complicated: there's a global "can create cluster services" setting, and then separate per-service and per-device locks. Instead, change "Can Create Cluster Services" into "Can Manage Cluster Services". Require this permission (in addition to normal permissions) to edit or create any cluster service. This permission can be locked to "No One" via config (as we do in the Phacility cluster) so we only need this one simple setting. There's also zero reason to individually lock //some// of the cluster services. Also improve extended policy errors. The UI here is still a little heavy-handed, but should be good enough for the moment. Test Plan: - Ran migrations. - Verified that cluster services and bindings reported that they belonged to the cluster. - Edited a cluster binding. - Verified that the bound device was marked as a cluster device - Moved a cluster binding, verified the old device was unmarked as a cluster device. - Tried to edit a cluster device as an unprivileged user, got a sensible error. {F1126552} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15339
2016-02-24 01:23:40 +01:00
'This device is bound to a cluster service. You do not have '.
'permission to manage cluster services, so the device can not '.
'be edited.'));
}
$interfaces = $this->buildInterfaceList($device);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($device->getName());
$crumbs->setBorder(true);
$timeline = $this->buildTransactionTimeline(
$device,
new AlmanacDeviceTransactionQuery());
$timeline->setShouldTerminate(true);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setMainColumn(array(
$issue,
$interfaces,
$this->buildAlmanacPropertiesTable($device),
$this->buildSSHKeysTable($device),
$this->buildServicesTable($device),
$timeline,
))
->setPropertyList($properties)
->setActionList($actions);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
$view,
));
}
private function buildPropertyList(AlmanacDevice $device) {
$viewer = $this->getViewer();
$properties = id(new PHUIPropertyListView())
->setUser($viewer)
->setObject($device);
return $properties;
}
private function buildActionList(AlmanacDevice $device) {
$viewer = $this->getViewer();
$id = $device->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$device,
PhabricatorPolicyCapability::CAN_EDIT);
$actions = id(new PhabricatorActionListView())
->setUser($viewer);
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Device'))
->setHref($this->getApplicationURI("device/edit/{$id}/"))
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
return $actions;
}
private function buildInterfaceList(AlmanacDevice $device) {
$viewer = $this->getViewer();
$id = $device->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$device,
PhabricatorPolicyCapability::CAN_EDIT);
$interfaces = id(new AlmanacInterfaceQuery())
->setViewer($viewer)
->withDevicePHIDs(array($device->getPHID()))
->execute();
$table = id(new AlmanacInterfaceTableView())
->setUser($viewer)
->setInterfaces($interfaces)
->setCanEdit($can_edit);
$header = id(new PHUIHeaderView())
->setHeader(pht('DEVICE INTERFACES'))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setHref($this->getApplicationURI("interface/edit/?deviceID={$id}"))
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit)
->setText(pht('Add Interface'))
->setIcon('fa-plus'));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
private function buildSSHKeysTable(AlmanacDevice $device) {
$viewer = $this->getViewer();
$id = $device->getID();
$device_phid = $device->getPHID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$device,
PhabricatorPolicyCapability::CAN_EDIT);
$keys = id(new PhabricatorAuthSSHKeyQuery())
->setViewer($viewer)
->withObjectPHIDs(array($device_phid))
->execute();
$table = id(new PhabricatorAuthSSHKeyTableView())
->setUser($viewer)
->setKeys($keys)
->setCanEdit($can_edit)
->setShowID(true)
->setShowTrusted(true)
->setNoDataString(pht('This device has no associated SSH public keys.'));
try {
PhabricatorSSHKeyGenerator::assertCanGenerateKeypair();
$can_generate = true;
} catch (Exception $ex) {
$can_generate = false;
}
$generate_uri = '/auth/sshkey/generate/?objectPHID='.$device_phid;
$upload_uri = '/auth/sshkey/upload/?objectPHID='.$device_phid;
$header = id(new PHUIHeaderView())
->setHeader(pht('SSH PUBLIC KEYS'))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setHref($generate_uri)
->setWorkflow(true)
->setDisabled(!$can_edit || !$can_generate)
->setText(pht('Generate Keypair'))
->setIcon(
id(new PHUIIconView())
->setIcon('fa-lock')))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setHref($upload_uri)
->setWorkflow(true)
->setDisabled(!$can_edit)
->setText(pht('Upload Public Key'))
->setIcon(
id(new PHUIIconView())
->setIcon('fa-upload')));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
private function buildServicesTable(AlmanacDevice $device) {
$viewer = $this->getViewer();
// NOTE: We're loading all services so we can show hidden, locked services.
// In general, we let you know about all the things the device is bound to,
// even if you don't have permission to see their details. This is similar
// to exposing the existence of edges in other applications, with the
// addition of always letting you see that locks exist.
$services = id(new AlmanacServiceQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withDevicePHIDs(array($device->getPHID()))
->execute();
$handles = $viewer->loadHandles(mpull($services, 'getPHID'));
Simplify locking of Almanac cluster services Summary: Fixes T6741. Ref T10246. Broadly, we want to protect Almanac cluster services: - Today, against users in the Phacility cluster accidentally breaking their own instances. - In the future, against attackers compromising administrative accounts and adding a new "cluster database" which points at hardware they control. The way this works right now is really complicated: there's a global "can create cluster services" setting, and then separate per-service and per-device locks. Instead, change "Can Create Cluster Services" into "Can Manage Cluster Services". Require this permission (in addition to normal permissions) to edit or create any cluster service. This permission can be locked to "No One" via config (as we do in the Phacility cluster) so we only need this one simple setting. There's also zero reason to individually lock //some// of the cluster services. Also improve extended policy errors. The UI here is still a little heavy-handed, but should be good enough for the moment. Test Plan: - Ran migrations. - Verified that cluster services and bindings reported that they belonged to the cluster. - Edited a cluster binding. - Verified that the bound device was marked as a cluster device - Moved a cluster binding, verified the old device was unmarked as a cluster device. - Tried to edit a cluster device as an unprivileged user, got a sensible error. {F1126552} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15339
2016-02-24 01:23:40 +01:00
$icon_cluster = id(new PHUIIconView())
->setIcon('fa-sitemap');
$rows = array();
foreach ($services as $service) {
$rows[] = array(
Simplify locking of Almanac cluster services Summary: Fixes T6741. Ref T10246. Broadly, we want to protect Almanac cluster services: - Today, against users in the Phacility cluster accidentally breaking their own instances. - In the future, against attackers compromising administrative accounts and adding a new "cluster database" which points at hardware they control. The way this works right now is really complicated: there's a global "can create cluster services" setting, and then separate per-service and per-device locks. Instead, change "Can Create Cluster Services" into "Can Manage Cluster Services". Require this permission (in addition to normal permissions) to edit or create any cluster service. This permission can be locked to "No One" via config (as we do in the Phacility cluster) so we only need this one simple setting. There's also zero reason to individually lock //some// of the cluster services. Also improve extended policy errors. The UI here is still a little heavy-handed, but should be good enough for the moment. Test Plan: - Ran migrations. - Verified that cluster services and bindings reported that they belonged to the cluster. - Edited a cluster binding. - Verified that the bound device was marked as a cluster device - Moved a cluster binding, verified the old device was unmarked as a cluster device. - Tried to edit a cluster device as an unprivileged user, got a sensible error. {F1126552} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15339
2016-02-24 01:23:40 +01:00
($service->isClusterService()
? $icon_cluster
: null),
$handles->renderHandle($service->getPHID()),
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(pht('No services are bound to this device.'))
->setHeaders(
array(
null,
pht('Service'),
))
->setColumnClasses(
array(
null,
'wide pri',
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('BOUND SERVICES'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
}