Skip to content

Commit

Permalink
Config - add an option to lock policy settings
Browse files Browse the repository at this point in the history
Summary: Fixes T6947

Test Plan:
locked people.create.user and noted the UI only showed a link to the existing policy with no way to edit it.

tried to set the config to all the various bad things and saw helpful error messages telling me what I did wrong.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T6947

Differential Revision: https://secure.phabricator.com/D11358
  • Loading branch information
bobtrahan committed Jan 13, 2015
1 parent 7e78a3f commit 8cfc37f
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/__phutil_library_map__.php
Expand Up @@ -2864,6 +2864,7 @@
'PhrictionTransactionComment' => 'applications/phriction/storage/PhrictionTransactionComment.php',
'PhrictionTransactionEditor' => 'applications/phriction/editor/PhrictionTransactionEditor.php',
'PhrictionTransactionQuery' => 'applications/phriction/query/PhrictionTransactionQuery.php',
'PolicyLockOptionType' => 'applications/policy/config/PolicyLockOptionType.php',
'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php',
'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php',
'PonderAnswerCommentController' => 'applications/ponder/controller/PonderAnswerCommentController.php',
Expand Down Expand Up @@ -6194,6 +6195,7 @@
'PhrictionTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PhrictionTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhrictionTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PolicyLockOptionType' => 'PhabricatorConfigJSONOptionType',
'PonderAddAnswerView' => 'AphrontView',
'PonderAnswer' => array(
'PonderDAO',
Expand Down
Expand Up @@ -3,23 +3,17 @@
final class PhabricatorApplicationEditController
extends PhabricatorApplicationsController {

private $application;

public function shouldRequireAdmin() {
return true;
}

public function willProcessRequest(array $data) {
$this->application = $data['application'];
}

public function processRequest() {
$request = $this->getRequest();
public function handleRequest(AphrontRequest $request) {
$user = $request->getUser();
$application = $request->getURIData('application');

$application = id(new PhabricatorApplicationQuery())
->setViewer($user)
->withClasses(array($this->application))
->withClasses(array($application))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
Expand Down Expand Up @@ -107,7 +101,7 @@ public function processRequest() {
$user,
$config_entry,
$value,
PhabricatorContentSource::newFromRequest($this->getRequest()));
PhabricatorContentSource::newFromRequest($request));
}

return id(new AphrontRedirectResponse())->setURI($view_uri);
Expand All @@ -120,12 +114,15 @@ public function processRequest() {
$form = id(new AphrontFormView())
->setUser($user);

$locked_policies = PhabricatorEnv::getEnvConfig('policy.locked');
$locked_map = array_fill_keys($locked_policies, true);
foreach ($application->getCapabilities() as $capability) {
$label = $application->getCapabilityLabel($capability);
$can_edit = $application->isCapabilityEditable($capability);
$locked = idx($locked_map, $capability);
$caption = $application->getCapabilityCaption($capability);

if (!$can_edit) {
if (!$can_edit || $locked) {
$form->appendChild(
id(new AphrontFormStaticControl())
->setLabel($label)
Expand All @@ -135,6 +132,7 @@ public function processRequest() {
$form->appendChild(
id(new AphrontFormPolicyControl())
->setUser($user)
->setDisabled(idx($locked_map, $capability))
->setCapability($capability)
->setPolicyObject($application)
->setPolicies($policies)
Expand Down
16 changes: 16 additions & 0 deletions src/applications/policy/config/PhabricatorPolicyConfigOptions.php
Expand Up @@ -12,6 +12,12 @@ public function getDescription() {
}

public function getOptions() {
$policy_locked_type = 'custom:PolicyLockOptionType';
$policy_locked_example = array(
'people.create.users' => 'admin',);
$json = new PhutilJSON();
$policy_locked_example = $json->encodeFormatted($policy_locked_example);

return array(
$this->newOption('policy.allow-public', 'bool', false)
->setBoolOptions(
Expand Down Expand Up @@ -39,6 +45,16 @@ public function getOptions() {
"With this setting disabled, the 'Public' policy is not ".
"available, and the most open policy is 'All Users' (which means ".
"users must have accounts and be logged in to view things).")),
$this->newOption('policy.locked', $policy_locked_type, array())
->setSummary(pht(
'Lock specific application policies so they can not be edited.'))
->setDescription(pht(
'Phabricator has application policies which can dictate whether '.
'users can take certain actions, such as creating new users. '."\n\n".
'This setting allows for "locking" these policies such that no '.
'further edits can be made on a per-policy basis.'))
->addExample($policy_locked_example,
pht('Lock Create User Policy To Admins')),
);
}

Expand Down
63 changes: 63 additions & 0 deletions src/applications/policy/config/PolicyLockOptionType.php
@@ -0,0 +1,63 @@
<?php

final class PolicyLockOptionType
extends PhabricatorConfigJSONOptionType {

public function validateOption(PhabricatorConfigOption $option, $value) {
$capabilities = id(new PhutilSymbolLoader())
->setAncestorClass('PhabricatorPolicyCapability')
->loadObjects();
$capabilities = mpull($capabilities, null, 'getCapabilityKey');

$policy_phids = array();
foreach ($value as $capability_key => $policy) {
$capability = idx($capabilities, $capability_key);
if (!$capability) {
throw new Exception(pht(
'Capability "%s" does not exist.', $capability_key));
}
if (phid_get_type($policy) !=
PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
$policy_phids[$policy] = $policy;
} else {
try {
$policy_object = PhabricatorPolicyQuery::getGlobalPolicy($policy);
// this exception is not helpful here as its about global policy;
// throw a better exception
} catch (Exception $ex) {
throw new Exception(pht(
'Capability "%s" has invalid policy "%s".',
$capability_key,
$policy));
}
}

if ($policy == PhabricatorPolicies::POLICY_PUBLIC) {
if (!$capability->shouldAllowPublicPolicySetting()) {
throw new Exception(pht(
'Capability "%s" does not support public policy.',
$capability_key));
}
}
}

if ($policy_phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPhids($policy_phids)
->execute();
$handles = mpull($handles, null, 'getPHID');
foreach ($value as $capability_key => $policy) {
$handle = $handles[$policy];
if (!$handle->isComplete()) {
throw new Exception(pht(
'Capability "%s" has invalid policy "%s"; "%s" does not exist.',
$capability_key,
$policy,
$policy));
}
}
}
}

}

0 comments on commit 8cfc37f

Please sign in to comment.