summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Perry2016-08-17 15:07:40 (GMT)
committerJakob Perry2016-08-17 15:08:19 (GMT)
commit98421099f812ceb02534c0d292399a2ad12b0362 (patch)
treee1a531c320771a67dbe4fc45a58f4e84ff0af01d
parent3c7f39f77984141fcef77221e88cbbf90bc287fe (diff)
Improve access checks for panels routes
-rw-r--r--UPGRADE.txt12
-rw-r--r--includes/plugins.inc25
-rw-r--r--panels.install70
-rw-r--r--panels.module87
-rw-r--r--panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php13
-rw-r--r--panels_mini/panels_mini.install58
-rw-r--r--panels_mini/panels_mini.module7
-rw-r--r--panels_mini/plugins/panels_storage/panels_mini.inc22
-rw-r--r--panels_node/panels_node.install60
-rw-r--r--panels_node/panels_node.module11
-rw-r--r--panels_node/plugins/panels_storage/panels_node.inc25
-rw-r--r--plugins/display_renderers/panels_renderer_editor.class.php34
-rw-r--r--plugins/display_renderers/panels_renderer_standard.class.php13
-rw-r--r--plugins/panels_storage/page_manager.inc19
-rw-r--r--plugins/task_handlers/panel_context.inc17
15 files changed, 470 insertions, 3 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt
index d1a42f2..05c0c98 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -11,7 +11,7 @@ Upgrading from Panels-6.x-3.x to Panels-7.x-3.x
- panels_plugin_get_function() deprecated.
- - panels_required_context removed. These were deprecated long ago and
+ - panels_required_context removed. These were deprecated long ago and
existed only to prevent crashes.
- panels_optional_context removed.
@@ -20,3 +20,13 @@ Upgrading from Panels-6.x-3.x to Panels-7.x-3.x
- display_renderer class is now in 'renderer', not 'handler'.
+Upgrading task handlers from Panels 7.x-3.5 or older to Panels 7.x-3.6 and newer:
+
+ - You must specify a storage type for any panels display using your custom task handler.
+ For examples, see panels_update_7306.
+
+ - When creating whatever stores the panel, a storage id and storage type must be defined.
+ See panels_mini.module for examples inside panels_mini_save and panels_mini_panels_cache_get.
+
+ - A display access plugin must be defined.
+ See panels_mini/plugins/panels_storage/panels_mini.inc for an example plugin.
diff --git a/includes/plugins.inc b/includes/plugins.inc
index 00f28c4..be5cd25 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -479,6 +479,31 @@ function panels_get_renderer_pipelines($sort = TRUE) {
}
/**
+ * Fetch metadata on a specific panels_storage plugin.
+ *
+ * @param $storage
+ * Name of a panel_storage plugin.
+ *
+ * @return
+ * An array with information about the requested panels_storage plugin
+ */
+function panels_get_panels_storage_plugin($storage) {
+ ctools_include('plugins');
+ return ctools_get_plugins('panels', 'panels_storage', $storage);
+}
+
+/**
+ * Fetch metadata for all panels_storage plugins.
+ *
+ * @return
+ * An array of arrays with information about all available panels_storage plugins.
+ */
+function panels_get_panels_storage_plugins() {
+ ctools_include('plugins');
+ return ctools_get_plugins('panels', 'panels_storage');
+}
+
+/**
* Get a function from a plugin, if it exists.
*
* @param $plugin
diff --git a/panels.install b/panels.install
index 7a9e7f7..ebb93e0 100644
--- a/panels.install
+++ b/panels.install
@@ -47,7 +47,25 @@ function panels_requirements_install() {
function panels_schema() {
// This should always point to our 'current' schema. This makes it relatively
// easy to keep a record of schema as we make changes to it.
- return panels_schema_7();
+ return panels_schema_8();
+}
+
+function panels_schema_8() {
+ $schema = panels_schema_7();
+
+ // Add the storage type and id columns.
+ $schema['panels_display']['fields']['storage_type'] = array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'default' => '',
+ );
+ $schema['panels_display']['fields']['storage_id'] = array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'default' => '',
+ );
+
+ return $schema;
}
function panels_schema_7() {
@@ -520,3 +538,53 @@ function panels_update_7304() {
}
}
}
+
+/**
+ * Add the "storage_type" and "storage_id" columns to "panels_display".
+ */
+function panels_update_7305() {
+ $schema = panels_schema_8();
+
+ $new_fields = array(
+ 'panels_display' => array('storage_type', 'storage_id'),
+ );
+
+ foreach ($new_fields as $table => $fields) {
+ foreach ($fields as $field_name) {
+ db_add_field($table, $field_name, $schema[$table]['fields'][$field_name]);
+ }
+ }
+}
+
+/**
+ * Set the storage type and id on existing page manager panels displays.
+ */
+function panels_update_7306() {
+ if (!db_table_exists('page_manager_handlers')) {
+ return t('Skipping update - page_manager is not installed.');
+ }
+
+ // Get all page_manager_handlers that have a panels context.
+ $result = db_query("SELECT pm.name, pm.conf FROM {page_manager_handlers} pm WHERE pm.handler = 'panel_context'");
+ $page_manager_panels = array();
+ foreach ($result as $row) {
+ $conf = unserialize($row->conf);
+ if (isset($conf['did'])) {
+ $page_manager_panels[$conf['did']] = $row->name;
+ }
+ }
+
+ if (!empty($page_manager_panels)) {
+ // Check panels displays that only have empty storage types
+ $result = db_query("SELECT pd.did FROM {panels_display} pd WHERE pd.did IN (:dids) AND storage_type = ''", array(':dids' => array_keys($page_manager_panels)));
+ foreach ($result as $row) {
+ db_update('panels_display')
+ ->fields(array(
+ 'storage_type' => 'page_manager',
+ 'storage_id' => $page_manager_panels[$row->did],
+ ))
+ ->condition('did', $row->did)
+ ->execute();
+ }
+ }
+}
diff --git a/panels.module b/panels.module
index 0193153..45ca031 100644
--- a/panels.module
+++ b/panels.module
@@ -409,6 +409,7 @@ function panels_ctools_plugin_type() {
'display_renderers' => array(
'classes' => array('renderer'),
),
+ 'panels_storage' => array(),
);
}
@@ -775,6 +776,55 @@ class panels_display {
}
return $output;
}
+
+ /**
+ * Determine if the given user can perform the requested operation.
+ *
+ * @param string $op
+ * An operation like: create, read, update, or delete.
+ * @param object $account
+ * (optional) The account to check access for.
+ *
+ * @return bool
+ * TRUE if access is granted; otherwise FALSE.
+ */
+ function access($op, $account = NULL) {
+ global $user;
+
+ if (!$account) {
+ $account = $user;
+ }
+
+ // Even administrators need to go through the access system. However, to
+ // support legacy plugins, user 1 gets full access no matter what.
+ if ($account->uid == 1) {
+ return TRUE;
+ }
+
+ if (!in_array($op, array('create', 'read', 'update', 'delete', 'change layout'))) {
+ return FALSE;
+ }
+
+ if (empty($this->storage_type) || empty($this->storage_id)) {
+ return FALSE;
+ }
+
+ if ($this->storage_type == 'unknown') {
+ return FALSE;
+ }
+
+ $storage_plugin = panels_get_panels_storage_plugin($this->storage_type);
+ if (!$storage_plugin) {
+ return FALSE;
+ }
+
+ $access_callback = panels_plugin_get_function('panels_storage', $storage_plugin, 'access callback');
+ if (!$access_callback) {
+ return FALSE;
+ }
+
+ return $access_callback($this->storage_type, $this->storage_id, $op, $account);
+ }
}
/**
@@ -1415,6 +1465,11 @@ function panels_ajax_router() {
ctools_include('cleanstring');
$renderer->clean_key = ctools_cleanstring($cache_key);
+ $op = $renderer->get_panels_storage_op_for_ajax($method);
+ if (!$cache->display->access($op)) {
+ return MENU_ACCESS_DENIED;
+ }
+
$output = call_user_func_array(array($renderer, $method), $args);
if (empty($output) && !empty($renderer->commands)) {
@@ -1726,6 +1781,38 @@ function panels_page_wizard_panels_cache_set($key, $cache) {
page_manager_set_wizard_cache($wizard_cache);
}
+/**
+ * Alter the page wizard basic page, when panels is selected, to inject page
+ * manager as the storage plugin for panels.
+ * @param $form
+ * @param $form_state
+ */
+function panels_form_page_manager_page_form_basic_alter(&$form, &$form_state) {
+ $form['#validate'][] = 'panels_page_manager_handler_add_validate';
+}
+
+/**
+ * Alter the variant add page, so when panels is selected, page manager is the
+ * storage plugin for panels.
+ * @param $form
+ * @param $form_state
+ */
+function panels_form_page_manager_handler_add_alter(&$form, &$form_state) {
+ $form['#validate'][] = 'panels_page_manager_handler_add_validate';
+}
+
+/**
+ * Perform the validation check to see if panel context is selected to use
+ * page manager as the storage plugin.
+ * @param $form
+ * @param $form_state
+ */
+function panels_page_manager_handler_add_validate($form, &$form_state) {
+ if($form_state['values']['handler'] == 'panel_context') {
+ $form_state['page']->storage_type = 'page_manager';
+ }
+}
+
// --------------------------------------------------------------------------
// General utility functions
diff --git a/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php b/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
index abaf6da..0d7198f 100644
--- a/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
+++ b/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
@@ -259,6 +259,19 @@ class panels_renderer_ipe extends panels_renderer_editor {
// Break the lock.
panels_edit_cache_break_lock($this->cache);
}
+ }
+
+ function get_panels_storage_op_for_ajax($method) {
+ switch ($method) {
+ case 'ajax_unlock_ipe':
+ case 'ajax_save_form':
+ return 'update';
+ case 'ajax_change_layout':
+ case 'ajax_set_layout':
+ return 'change layout';
+ }
+
+ return parent::get_panels_storage_op_for_ajax($method);
}
/**
diff --git a/panels_mini/panels_mini.install b/panels_mini/panels_mini.install
index 235e88e..b3239dd 100644
--- a/panels_mini/panels_mini.install
+++ b/panels_mini/panels_mini.install
@@ -122,3 +122,61 @@ function panels_mini_uninstall() {
->execute();
}
}
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function panels_mini_update_dependencies() {
+ // Update 7301 requires panels storage support
+ $dependencies['panels_mini'][7301] = array(
+ 'panels' => 7305,
+ );
+
+ return $dependencies;
+}
+
+/**
+ * Set the storage type and id on existing mini panels.
+ */
+function panels_mini_update_7301() {
+ if (!isset($sandbox['progress'])) {
+ // Initialize batch update information.
+ $sandbox['progress'] = (float)0;
+ $sandbox['current_did'] = -1;
+ $sandbox['max'] = db_query("SELECT COUNT(pd.did)
+ FROM {panels_display} pd
+ JOIN {panels_mini} pm ON pm.did = pd.did
+ WHERE pd.storage_type = ''")->fetchField();
+ }
+
+ // Set a limit of how many rows to process per batch.
+ $limit = 1000;
+
+ // Run the query
+ $result = db_query_range("SELECT pd.did, pm.name
+ FROM {panels_display} pd
+ JOIN {panels_mini} pm ON pm.did = pd.did
+ WHERE pd.storage_type = '' AND pd.did > :current_did", 0, $limit, array(':current_did' => $sandbox['current_did']));
+
+ foreach ($result as $row) {
+ db_update('panels_display')
+ ->fields(array(
+ 'storage_type' => 'panels_mini',
+ 'storage_id' => $row->name,
+ ))
+ ->condition('did', $row->did)
+ ->execute();
+
+ // Update our progress information.
+ $sandbox['progress']++;
+ $sandbox['current_did'] = $row->did;
+ }
+
+ // Set the "finished" status, to tell batch engine whether this function
+ // needs to run again.
+ $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']);
+
+ if ($sandbox['#finished']) {
+ return t('Added the storage type for panels_mini to relevant panels displays');
+ }
+}
diff --git a/panels_mini/panels_mini.module b/panels_mini/panels_mini.module
index 4820f21..e55c673 100644
--- a/panels_mini/panels_mini.module
+++ b/panels_mini/panels_mini.module
@@ -365,6 +365,7 @@ function panels_mini_load_all($reset = FALSE) {
*/
function panels_mini_save(&$mini) {
if (!empty($mini->display)) {
+ $mini->display->storage_id = $mini->name;
$display = panels_save_display($mini->display);
$mini->did = $display->did;
}
@@ -424,6 +425,9 @@ function panels_mini_ctools_plugin_directory($module, $plugin) {
if ($module == 'ctools' && ($plugin == 'content_types' || $plugin == 'export_ui')) {
return 'plugins/' . $plugin;
}
+ if ($module == 'panels' && $plugin == 'panels_storage') {
+ return 'plugins/' . $plugin;
+ }
}
/**
@@ -462,6 +466,9 @@ function panels_mini_panels_cache_get($key) {
$cache->display = $item->display;
$cache->display->context = ctools_context_load_contexts($item);
$cache->display->cache_key = 'panels_mini:' . $key;
+ $cache->display->storage_type = 'panels_mini';
+ // Temporary storage id that's replaced in panels_mini_save().
+ $cache->display->storage_id = 'panels_mini';
$cache->content_types = panels_common_get_allowed_types('panels_mini', $cache->display->context);
$cache->display_title = TRUE;
diff --git a/panels_mini/plugins/panels_storage/panels_mini.inc b/panels_mini/plugins/panels_storage/panels_mini.inc
new file mode 100644
index 0000000..c9ba35d
--- /dev/null
+++ b/panels_mini/plugins/panels_storage/panels_mini.inc
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Provides a panels_storage plugin for mini panels.
+ */
+
+// Plugin definition
+$plugin = array(
+ 'access callback' => 'panels_mini_panels_storage_access',
+);
+
+/**
+ * Access callback for panels storage.
+ */
+function panels_mini_panels_storage_access($storage_type, $storage_id, $op, $account) {
+ if ($op == 'create') {
+ return user_access('create mini panels', $account);
+ }
+
+ return user_access('administer mini panels', $account);
+}
diff --git a/panels_node/panels_node.install b/panels_node/panels_node.install
index f1b24f9..94f7eb4 100644
--- a/panels_node/panels_node.install
+++ b/panels_node/panels_node.install
@@ -57,6 +57,18 @@ function panels_node_uninstall() {
}
/**
+ * Implements hook_update_dependencies().
+ */
+function panels_node_update_dependencies() {
+ // Update 7301 requires panels storage support
+ $dependencies['panels_node'][7301] = array(
+ 'panels' => 7305,
+ );
+
+ return $dependencies;
+}
+
+/**
* Implementation of hook_update to handle adding a pipeline
*/
function panels_node_update_6001() {
@@ -73,7 +85,7 @@ function panels_node_update_6001() {
/**
* Migrate legacy Drupal 6 permissions to Drupal 7.
*/
-function panels_node_update_6002() {
+function panels_node_update_7301() {
$permissions = array(
'create panel-nodes' => 'create panel content',
'edit any panel-nodes' => 'edit any panel content',
@@ -107,3 +119,49 @@ function panels_node_update_6002() {
->execute();
}
}
+
+/*
+ * Set the storage type and id on existing panels nodes.
+ */
+function panels_node_update_7302() {
+ if (!isset($sandbox['progress'])) {
+ // Initialize batch update information.
+ $sandbox['progress'] = (float)0;
+ $sandbox['current_did'] = -1;
+ $sandbox['max'] = db_query("SELECT COUNT(pd.did)
+ FROM {panels_display} pd
+ JOIN {panels_node} pn ON pn.did = pd.did
+ WHERE pd.storage_type = ''")->fetchField();
+ }
+
+ // Set a limit of how many rows to process per batch.
+ $limit = 1000;
+
+ // Run the query
+ $result = db_query_range("SELECT pd.did, pn.nid
+ FROM {panels_display} pd
+ JOIN {panels_node} pn ON pn.did = pd.did
+ WHERE pd.storage_type = '' AND pd.did > :current_did", 0, $limit, array(':current_did' => $sandbox['current_did']));
+
+ foreach ($result as $row) {
+ db_update('panels_display')
+ ->fields(array(
+ 'storage_type' => 'panels_node',
+ 'storage_id' => $row->nid,
+ ))
+ ->condition('did', $row->did)
+ ->execute();
+
+ // Update our progress information.
+ $sandbox['progress']++;
+ $sandbox['current_did'] = $row->did;
+ }
+
+ // Set the "finished" status, to tell batch engine whether this function
+ // needs to run again.
+ $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']);
+
+ if ($sandbox['#finished']) {
+ return t('Added the storage type for panels_node to relevant panels displays');
+ }
+}
diff --git a/panels_node/panels_node.module b/panels_node/panels_node.module
index bcdb670..4b33e7f 100644
--- a/panels_node/panels_node.module
+++ b/panels_node/panels_node.module
@@ -25,6 +25,15 @@ function panels_node_permission() {
}
/**
+ * Implementation of hook_ctools_plugin_directory().
+ */
+function panels_node_ctools_plugin_directory($module, $plugin) {
+ if ($module == 'panels' && $plugin == 'panels_storage') {
+ return 'plugins/' . $plugin;
+ }
+}
+
+/**
* Implementation of hook_menu().
*/
function panels_node_menu() {
@@ -236,6 +245,8 @@ function panels_node_hook_insert(&$node) {
// Create a new display and record that.
$display = panels_new_display();
$display->layout = $node->panels_node['layout'];
+ $display->storage_type = 'panels_node';
+ $display->storage_id = $node->nid;
// Special handling for nodes being imported from an export.module data dump.
if (!empty($node->export_display)) {
diff --git a/panels_node/plugins/panels_storage/panels_node.inc b/panels_node/plugins/panels_storage/panels_node.inc
new file mode 100644
index 0000000..a7a7a3b
--- /dev/null
+++ b/panels_node/plugins/panels_storage/panels_node.inc
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Provides a panels_storage plugin for panels node.
+ */
+
+// Plugin definition
+$plugin = array(
+ 'access callback' => 'panels_node_panels_storage_access',
+);
+
+/**
+ * Access callback for panels storage.
+ */
+function panels_node_panels_storage_access($storage_type, $storage_id, $op, $account) {
+ if ($node = node_load($storage_id)) {
+ if ($op == 'read') {
+ $op = 'view';
+ }
+ return node_access($op, $node, $account);
+ }
+
+ return FALSE;
+}
diff --git a/plugins/display_renderers/panels_renderer_editor.class.php b/plugins/display_renderers/panels_renderer_editor.class.php
index f6f0b16..d8947dc 100644
--- a/plugins/display_renderers/panels_renderer_editor.class.php
+++ b/plugins/display_renderers/panels_renderer_editor.class.php
@@ -515,6 +515,40 @@ class panels_renderer_editor extends panels_renderer_standard {
}
/**
+ * Get the Panels storage oparation for a given renderer AJAX method.
+ *
+ * @param string $method
+ * The method name.
+ *
+ * @return string
+ * The Panels storage op.
+ */
+ function get_panels_storage_op_for_ajax($method) {
+ switch ($method) {
+ case 'ajax_show':
+ case 'ajax_hide':
+ case 'ajax_select_content':
+ case 'ajax_add_pane':
+ case 'ajax_edit_pane':
+ case 'ajax_panel_title':
+ case 'ajax_cache_method':
+ case 'ajax_cache_settings':
+ case 'ajax_style_type':
+ case 'ajax_style_settings':
+ case 'ajax_pane_css':
+ case 'ajax_lock':
+ case 'ajax_access_settings':
+ case 'ajax_access_add_test':
+ case 'ajax_access_configure_test':
+ case 'ajax_layout':
+ case 'ajax_style':
+ return 'update';
+ }
+
+ return parent::get_panels_storage_op($method);
+ }
+
+ /**
* AJAX command to show a pane.
*/
function ajax_show($pid = NULL) {
diff --git a/plugins/display_renderers/panels_renderer_standard.class.php b/plugins/display_renderers/panels_renderer_standard.class.php
index 5f134a9..b97153f 100644
--- a/plugins/display_renderers/panels_renderer_standard.class.php
+++ b/plugins/display_renderers/panels_renderer_standard.class.php
@@ -186,6 +186,19 @@ class panels_renderer_standard {
}
/**
+ * Get the Panels storage oparation for a given renderer AJAX method.
+ *
+ * @param string $method
+ * The method name.
+ *
+ * @return string
+ * The Panels storage op.
+ */
+ function get_panels_storage_op_for_ajax($method) {
+ return 'read';
+ }
+
+ /**
* Prepare the attached display for rendering.
*
* This is the outermost prepare method. It calls several sub-methods as part
diff --git a/plugins/panels_storage/page_manager.inc b/plugins/panels_storage/page_manager.inc
new file mode 100644
index 0000000..d543600
--- /dev/null
+++ b/plugins/panels_storage/page_manager.inc
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Provides a panels_storage plugin for page_manager.
+ */
+
+// Plugin definition
+$plugin = array(
+ 'access callback' => 'page_manager_panels_storage_access',
+);
+
+/**
+ * Access callback for panels storage.
+ */
+function page_manager_panels_storage_access($storage_type, $storage_id, $op, $account) {
+ // Only users with the 'use page manager' or administer page manager perms.
+ return user_access('use page manager', $account) || user_access('administer page manager', $account);
+}
diff --git a/plugins/task_handlers/panel_context.inc b/plugins/task_handlers/panel_context.inc
index 2c65518..b7f4780 100644
--- a/plugins/task_handlers/panel_context.inc
+++ b/plugins/task_handlers/panel_context.inc
@@ -586,6 +586,19 @@ function panels_panel_context_edit_choose($form, &$form_state) {
$form_state['display'] = &panels_panel_context_get_display($form_state['handler']);
+ // Grab the storage_type and storage_id and inject it into the display.
+ if (empty($form_state['display']->storage_type)) {
+ if (!isset($form_state[$form_state['task_id']]->storage_type)) {
+ watchdog('panels', "Unable to find the storage type for specified storage. Read 'Upgrading task handlers' in CHANGELOG.txt", array(), WATCHDOG_ERROR);
+ $form_state['display']->storage_type = 'unknown';
+ }
+ else {
+ $form_state['display']->storage_type = $form_state[$form_state['task_id']]->storage_type;
+ }
+ // When adding variants, we don't know the handler id yet. In that case,
+ // Mark it as new. We'll assign it later.
+ $form_state['display']->storage_id = !empty($form_state['handler_id']) ? $form_state['handler_id'] : 'new';
+ }
// Tell the Panels form not to display buttons.
$form_state['no buttons'] = TRUE;
@@ -743,6 +756,10 @@ function panels_panel_context_edit_content_validate(&$form, &$form_state) {
}
function panels_panel_context_edit_content_submit(&$form, &$form_state) {
+ // Update the storage_id if this is a new variant before saving.
+ if ($form_state['display']->storage_id == 'new') {
+ $form_state['display']->storage_id = $form_state['handler_id'];
+ }
panels_edit_display_form_submit($form, $form_state);
$handler = &$form_state['handler'];