protected function getOptions() { $capability = $this->capability; $options = array(); foreach ($this->policies as $policy) { if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) { // Never expose "Public" for capabilities which don't support it. $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { continue; } } $policy_short_name = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(28)->truncateString($policy->getName()); $options[$policy->getType()][$policy->getPHID()] = array('name' => $policy_short_name, 'full' => $policy->getName(), 'icon' => $policy->getIcon()); } // If we were passed several custom policy options, throw away the ones // which aren't the value for this capability. For example, an object might // have a custom view pollicy and a custom edit policy. When we render // the selector for "Can View", we don't want to show the "Can Edit" // custom policy -- if we did, the menu would look like this: // // Custom // Custom Policy // Custom Policy // // ...where one is the "view" custom policy, and one is the "edit" custom // policy. $type_custom = PhabricatorPolicyType::TYPE_CUSTOM; if (!empty($options[$type_custom])) { $options[$type_custom] = array_select_keys($options[$type_custom], array($this->getValue())); } // If there aren't any custom policies, add a placeholder policy so we // render a menu item. This allows the user to switch to a custom policy. if (empty($options[$type_custom])) { $placeholder = new PhabricatorPolicy(); $placeholder->setName(pht('Custom Policy...')); $options[$type_custom][$this->getCustomPolicyPlaceholder()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon()); } $options = array_select_keys($options, array(PhabricatorPolicyType::TYPE_GLOBAL, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT)); return $options; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $phid = $request->getURIData('phid'); $capability = $request->getURIData('capability'); $object = id(new PhabricatorObjectQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne(); if (!$object) { return new Aphront404Response(); } $policies = PhabricatorPolicyQuery::loadPolicies($viewer, $object); $policy = idx($policies, $capability); if (!$policy) { return new Aphront404Response(); } $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne(); $object_uri = nonempty($handle->getURI(), '/'); $explanation = PhabricatorPolicy::getPolicyExplanation($viewer, $policy->getPHID()); $auto_info = (array) $object->describeAutomaticCapability($capability); $auto_info = array_merge(array($explanation), $auto_info); $auto_info = array_filter($auto_info); foreach ($auto_info as $key => $info) { $auto_info[$key] = phutil_tag('li', array(), $info); } if ($auto_info) { $auto_info = phutil_tag('ul', array(), $auto_info); } $capability_name = $capability; $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if ($capobj) { $capability_name = $capobj->getCapabilityName(); } $dialog = id(new AphrontDialogView())->setUser($viewer)->setClass('aphront-access-dialog'); $this->appendSpaceInformation($dialog, $object, $policy, $capability); $intro = pht('Users with the "%s" capability for this object:', $capability_name); $object_name = pht('%s %s', $handle->getTypeName(), $handle->getObjectName()); $dialog->setTitle(pht('Policy Details: %s', $object_name))->appendParagraph($intro)->appendChild($auto_info)->addCancelButton($object_uri, pht('Done')); $this->appendStrengthInformation($dialog, $object, $policy, $capability); return $dialog; }
public function rejectObject(PhabricatorPolicyInterface $object, $policy, $capability) { if (!$this->raisePolicyExceptions) { return; } if ($this->viewer->isOmnipotent()) { // Never raise policy exceptions for the omnipotent viewer. Although we // will never normally issue a policy rejection for the omnipotent // viewer, we can end up here when queries blanket reject objects that // have failed to load, without distinguishing between nonexistent and // nonvisible objects. return; } $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); $rejection = null; if ($capobj) { $rejection = $capobj->describeCapabilityRejection(); $capability_name = $capobj->getCapabilityName(); } else { $capability_name = $capability; } if (!$rejection) { // We couldn't find the capability object, or it doesn't provide a // tailored rejection string. $rejection = pht('You do not have the required capability ("%s") to do whatever you ' . 'are trying to do.', $capability); } $more = PhabricatorPolicy::getPolicyExplanation($this->viewer, $policy); $exceptions = $object->describeAutomaticCapability($capability); $details = array_filter(array_merge(array($more), (array) $exceptions)); $access_denied = $this->renderAccessDenied($object); $full_message = pht('[%s] (%s) %s // %s', $access_denied, $capability_name, $rejection, implode(' ', $details)); $exception = id(new PhabricatorPolicyException($full_message))->setTitle($access_denied)->setObjectPHID($object->getPHID())->setRejection($rejection)->setCapability($capability)->setCapabilityName($capability_name)->setMoreInfo($details); throw $exception; }
public final function getCapabilityLabel($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht('Can Use Application'); case PhabricatorPolicyCapability::CAN_EDIT: return pht('Can Configure Application'); } $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if ($capobj) { return $capobj->getCapabilityName(); } return null; }
public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); $application = $request->getURIData('application'); $application = id(new PhabricatorApplicationQuery())->setViewer($user)->withClasses(array($application))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$application) { return new Aphront404Response(); } $title = $application->getName(); $view_uri = $this->getApplicationURI('view/' . get_class($application) . '/'); $policies = id(new PhabricatorPolicyQuery())->setViewer($user)->setObject($application)->execute(); if ($request->isFormPost()) { $result = array(); foreach ($application->getCapabilities() as $capability) { $old = $application->getPolicy($capability); $new = $request->getStr('policy:' . $capability); if ($old == $new) { // No change to the setting. continue; } if (empty($policies[$new])) { // Not a standard policy, check for a custom policy. $policy = id(new PhabricatorPolicyQuery())->setViewer($user)->withPHIDs(array($new))->executeOne(); if (!$policy) { // Not a custom policy either. Can't set the policy to something // invalid, so skip this. continue; } } if ($new == PhabricatorPolicies::POLICY_PUBLIC) { $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { // Can't set non-public policies to public. continue; } } $result[$capability] = $new; } if ($result) { $key = 'phabricator.application-settings'; $config_entry = PhabricatorConfigEntry::loadConfigEntry($key); $value = $config_entry->getValue(); $phid = $application->getPHID(); if (empty($value[$phid])) { $value[$application->getPHID()] = array(); } if (empty($value[$phid]['policy'])) { $value[$phid]['policy'] = array(); } $value[$phid]['policy'] = $result + $value[$phid]['policy']; // Don't allow users to make policy edits which would lock them out of // applications, since they would be unable to undo those actions. PhabricatorEnv::overrideConfig($key, $value); PhabricatorPolicyFilter::mustRetainCapability($user, $application, PhabricatorPolicyCapability::CAN_VIEW); PhabricatorPolicyFilter::mustRetainCapability($user, $application, PhabricatorPolicyCapability::CAN_EDIT); PhabricatorConfigEditor::storeNewValue($user, $config_entry, $value, PhabricatorContentSource::newFromRequest($request)); } return id(new AphrontRedirectResponse())->setURI($view_uri); } $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions($user, $application); $form = id(new AphrontFormView())->setUser($user); $locked_policies = PhabricatorEnv::getEnvConfig('policy.locked'); foreach ($application->getCapabilities() as $capability) { $label = $application->getCapabilityLabel($capability); $can_edit = $application->isCapabilityEditable($capability); $locked = idx($locked_policies, $capability); $caption = $application->getCapabilityCaption($capability); if (!$can_edit || $locked) { $form->appendChild(id(new AphrontFormStaticControl())->setLabel($label)->setValue(idx($descriptions, $capability))->setCaption($caption)); } else { $control = id(new AphrontFormPolicyControl())->setUser($user)->setDisabled($locked)->setCapability($capability)->setPolicyObject($application)->setPolicies($policies)->setLabel($label)->setName('policy:' . $capability)->setCaption($caption); $template = $application->getCapabilityTemplatePHIDType($capability); if ($template) { $phid_types = PhabricatorPHIDType::getAllTypes(); $phid_type = idx($phid_types, $template); if ($phid_type) { $template_object = $phid_type->newObject(); if ($template_object) { $template_policies = id(new PhabricatorPolicyQuery())->setViewer($user)->setObject($template_object)->execute(); // NOTE: We want to expose both any object template policies // (like "Subscribers") and any custom policy. $all_policies = $template_policies + $policies; $control->setPolicies($all_policies); $control->setTemplateObject($template_object); } } $control->setTemplatePHIDType($template); } $form->appendControl($control); } } $form->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save Policies'))->addCancelButton($view_uri)); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($application->getName(), $view_uri); $crumbs->addTextCrumb(pht('Edit Policies')); $header = id(new PHUIHeaderView())->setHeader(pht('Edit Policies: %s', $application->getName())); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->setForm($form); return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => $title)); }
protected function getOptions() { $capability = $this->capability; $policies = $this->policies; // Exclude object policies which don't make sense here. This primarily // filters object policies associated from template capabilities (like // "Default Task View Policy" being set to "Task Author") so they aren't // made available on non-template capabilities (like "Can Bulk Edit"). foreach ($policies as $key => $policy) { if ($policy->getType() != PhabricatorPolicyType::TYPE_OBJECT) { continue; } $rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy->getPHID()); if (!$rule) { continue; } $target = nonempty($this->templateObject, $this->object); if (!$rule->canApplyToObject($target)) { unset($policies[$key]); continue; } } $options = array(); foreach ($policies as $policy) { if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) { // Never expose "Public" for capabilities which don't support it. $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { continue; } } $policy_short_name = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(28)->truncateString($policy->getName()); $options[$policy->getType()][$policy->getPHID()] = array('name' => $policy_short_name, 'full' => $policy->getName(), 'icon' => $policy->getIcon()); } // If we were passed several custom policy options, throw away the ones // which aren't the value for this capability. For example, an object might // have a custom view pollicy and a custom edit policy. When we render // the selector for "Can View", we don't want to show the "Can Edit" // custom policy -- if we did, the menu would look like this: // // Custom // Custom Policy // Custom Policy // // ...where one is the "view" custom policy, and one is the "edit" custom // policy. $type_custom = PhabricatorPolicyType::TYPE_CUSTOM; if (!empty($options[$type_custom])) { $options[$type_custom] = array_select_keys($options[$type_custom], array($this->getValue())); } // If there aren't any custom policies, add a placeholder policy so we // render a menu item. This allows the user to switch to a custom policy. if (empty($options[$type_custom])) { $placeholder = new PhabricatorPolicy(); $placeholder->setName(pht('Custom Policy...')); $options[$type_custom][$this->getCustomPolicyPlaceholder()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon()); } $options = array_select_keys($options, array(PhabricatorPolicyType::TYPE_GLOBAL, PhabricatorPolicyType::TYPE_OBJECT, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT)); return $options; }
public function rejectObject(PhabricatorPolicyInterface $object, $policy, $capability) { if (!$this->raisePolicyExceptions) { return; } if ($this->viewer->isOmnipotent()) { // Never raise policy exceptions for the omnipotent viewer. Although we // will never normally issue a policy rejection for the omnipotent // viewer, we can end up here when queries blanket reject objects that // have failed to load, without distinguishing between nonexistent and // nonvisible objects. return; } $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); $rejection = null; if ($capobj) { $rejection = $capobj->describeCapabilityRejection(); $capability_name = $capobj->getCapabilityName(); } else { $capability_name = $capability; } if (!$rejection) { // We couldn't find the capability object, or it doesn't provide a // tailored rejection string. $rejection = pht('You do not have the required capability ("%s") to do whatever you ' . 'are trying to do.', $capability); } $more = PhabricatorPolicy::getPolicyExplanation($this->viewer, $policy); $exceptions = $object->describeAutomaticCapability($capability); $details = array_filter(array_merge(array($more), (array) $exceptions)); // NOTE: Not every type of policy object has a real PHID; just load an // empty handle if a real PHID isn't available. $phid = nonempty($object->getPHID(), PhabricatorPHIDConstants::PHID_VOID); $handle = id(new PhabricatorHandleQuery())->setViewer($this->viewer)->withPHIDs(array($phid))->executeOne(); $object_name = pht('%s %s', $handle->getTypeName(), $handle->getObjectName()); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { $title = pht('Access Denied: %s', $object_name); } else { $title = pht('You Shall Not Pass: %s', $object_name); } $full_message = pht('[%s] (%s) %s // %s', $title, $capability_name, $rejection, implode(' ', $details)); $exception = id(new PhabricatorPolicyException($full_message))->setTitle($title)->setRejection($rejection)->setCapabilityName($capability_name)->setMoreInfo($details); throw $exception; }
private function getCapabilityName($capability) { $capability_name = $capability; $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if ($capobj) { $capability_name = $capobj->getCapabilityName(); } return $capability_name; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $object_phid = $request->getURIData('objectPHID'); if ($object_phid) { $object = id(new PhabricatorObjectQuery())->setViewer($viewer)->withPHIDs(array($object_phid))->executeOne(); if (!$object) { return new Aphront404Response(); } } else { $object_type = $request->getURIData('objectType'); if (!$object_type) { $object_type = $request->getURIData('templateType'); } $phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer); if (empty($phid_types[$object_type])) { return new Aphront404Response(); } $object = $phid_types[$object_type]->newObject(); if (!$object) { return new Aphront404Response(); } } $action_options = array(PhabricatorPolicy::ACTION_ALLOW => pht('Allow'), PhabricatorPolicy::ACTION_DENY => pht('Deny')); $rules = id(new PhutilClassMapQuery())->setAncestorClass('PhabricatorPolicyRule')->execute(); foreach ($rules as $key => $rule) { if (!$rule->canApplyToObject($object)) { unset($rules[$key]); } } $rules = msort($rules, 'getRuleOrder'); $default_rule = array('action' => head_key($action_options), 'rule' => head_key($rules), 'value' => null); $phid = $request->getURIData('phid'); if ($phid) { $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->withPHIDs(array($phid))->execute(); if (!$policies) { return new Aphront404Response(); } $policy = head($policies); } else { $policy = id(new PhabricatorPolicy())->setRules(array($default_rule))->setDefaultAction(PhabricatorPolicy::ACTION_DENY); } $root_id = celerity_generate_unique_node_id(); $default_action = $policy->getDefaultAction(); $rule_data = $policy->getRules(); $errors = array(); if ($request->isFormPost()) { $data = $request->getStr('rules'); try { $data = phutil_json_decode($data); } catch (PhutilJSONParserException $ex) { throw new PhutilProxyException(pht('Failed to JSON decode rule data!'), $ex); } $rule_data = array(); foreach ($data as $rule) { $action = idx($rule, 'action'); switch ($action) { case 'allow': case 'deny': break; default: throw new Exception(pht("Invalid action '%s'!", $action)); } $rule_class = idx($rule, 'rule'); if (empty($rules[$rule_class])) { throw new Exception(pht("Invalid rule class '%s'!", $rule_class)); } $rule_obj = $rules[$rule_class]; $value = $rule_obj->getValueForStorage(idx($rule, 'value')); $rule_data[] = array('action' => $action, 'rule' => $rule_class, 'value' => $value); } // Filter out nonsense rules, like a "users" rule without any users // actually specified. $valid_rules = array(); foreach ($rule_data as $rule) { $rule_class = $rule['rule']; if ($rules[$rule_class]->ruleHasEffect($rule['value'])) { $valid_rules[] = $rule; } } if (!$valid_rules) { $errors[] = pht('None of these policy rules have any effect.'); } // NOTE: Policies are immutable once created, and we always create a new // policy here. If we didn't, we would need to lock this endpoint down, // as users could otherwise just go edit the policies of objects with // custom policies. if (!$errors) { $new_policy = new PhabricatorPolicy(); $new_policy->setRules($valid_rules); $new_policy->setDefaultAction($request->getStr('default')); $new_policy->save(); $data = array('phid' => $new_policy->getPHID(), 'info' => array('name' => $new_policy->getName(), 'full' => $new_policy->getName(), 'icon' => $new_policy->getIcon())); return id(new AphrontAjaxResponse())->setContent($data); } } // Convert rule values to display format (for example, expanding PHIDs // into tokens). foreach ($rule_data as $key => $rule) { $rule_data[$key]['value'] = $rules[$rule['rule']]->getValueForDisplay($viewer, $rule['value']); } $default_select = AphrontFormSelectControl::renderSelectTag($default_action, $action_options, array('name' => 'default')); if ($errors) { $errors = id(new PHUIInfoView())->setErrors($errors); } $form = id(new PHUIFormLayoutView())->appendChild($errors)->appendChild(javelin_tag('input', array('type' => 'hidden', 'name' => 'rules', 'sigil' => 'rules')))->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Rules'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-rule', 'mustcapture' => true), pht('New Rule')))->setDescription(pht('These rules are processed in order.'))->setContent(javelin_tag('table', array('sigil' => 'rules', 'class' => 'policy-rules-table'), '')))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('If No Rules Match'))->setValue(pht('%s all other users.', $default_select))); $form = phutil_tag('div', array('id' => $root_id), $form); $rule_options = mpull($rules, 'getRuleDescription'); $type_map = mpull($rules, 'getValueControlType'); $templates = mpull($rules, 'getValueControlTemplate'); require_celerity_resource('policy-edit-css'); Javelin::initBehavior('policy-rule-editor', array('rootID' => $root_id, 'actions' => $action_options, 'rules' => $rule_options, 'types' => $type_map, 'templates' => $templates, 'data' => $rule_data, 'defaultRule' => $default_rule)); $title = pht('Custom Policy'); $key = $request->getStr('capability'); if ($key) { $capability = PhabricatorPolicyCapability::getCapabilityByKey($key); $title = pht('Custom "%s" Policy', $capability->getCapabilityName()); } $dialog = id(new AphrontDialogView())->setWidth(AphrontDialogView::WIDTH_FULL)->setUser($viewer)->setTitle($title)->appendChild($form)->addSubmitButton(pht('Save Policy'))->addCancelButton('#'); return id(new AphrontDialogResponse())->setDialog($dialog); }
public function testGetCapabilityMap() { PhabricatorPolicyCapability::getCapabilityMap(); $this->assertTrue(true); }
protected function getOptions() { $capability = $this->capability; $policies = $this->policies; $viewer = $this->getUser(); // Check if we're missing the policy for the current control value. This // is unusual, but can occur if the user is submitting a form and selected // an unusual project as a policy but the change has not been saved yet. $policy_map = mpull($policies, null, 'getPHID'); $value = $this->getValue(); if ($value && empty($policy_map[$value])) { $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($value))->executeOne(); if ($handle->isComplete()) { $policies[] = PhabricatorPolicy::newFromPolicyAndHandle($value, $handle); } } // Exclude object policies which don't make sense here. This primarily // filters object policies associated from template capabilities (like // "Default Task View Policy" being set to "Task Author") so they aren't // made available on non-template capabilities (like "Can Bulk Edit"). foreach ($policies as $key => $policy) { if ($policy->getType() != PhabricatorPolicyType::TYPE_OBJECT) { continue; } $rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy->getPHID()); if (!$rule) { continue; } $target = nonempty($this->templateObject, $this->object); if (!$rule->canApplyToObject($target)) { unset($policies[$key]); continue; } } $options = array(); foreach ($policies as $policy) { if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) { // Never expose "Public" for capabilities which don't support it. $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { continue; } } $policy_short_name = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(28)->truncateString($policy->getName()); $options[$policy->getType()][$policy->getPHID()] = array('name' => $policy_short_name, 'full' => $policy->getName(), 'icon' => $policy->getIcon(), 'sort' => phutil_utf8_strtolower($policy->getName())); } $type_project = PhabricatorPolicyType::TYPE_PROJECT; // Make sure we have a "Projects" group before we adjust it. if (empty($options[$type_project])) { $options[$type_project] = array(); } $options[$type_project] = isort($options[$type_project], 'sort'); $placeholder = id(new PhabricatorPolicy())->setName(pht('Other Project...'))->setIcon('fa-search'); $options[$type_project][$this->getSelectProjectKey()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon()); // If we were passed several custom policy options, throw away the ones // which aren't the value for this capability. For example, an object might // have a custom view policy and a custom edit policy. When we render // the selector for "Can View", we don't want to show the "Can Edit" // custom policy -- if we did, the menu would look like this: // // Custom // Custom Policy // Custom Policy // // ...where one is the "view" custom policy, and one is the "edit" custom // policy. $type_custom = PhabricatorPolicyType::TYPE_CUSTOM; if (!empty($options[$type_custom])) { $options[$type_custom] = array_select_keys($options[$type_custom], array($this->getValue())); } // If there aren't any custom policies, add a placeholder policy so we // render a menu item. This allows the user to switch to a custom policy. if (empty($options[$type_custom])) { $placeholder = new PhabricatorPolicy(); $placeholder->setName(pht('Custom Policy...')); $options[$type_custom][$this->getSelectCustomKey()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon()); } $options = array_select_keys($options, array(PhabricatorPolicyType::TYPE_GLOBAL, PhabricatorPolicyType::TYPE_OBJECT, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT)); return $options; }