Commit 98421099 authored by Jakob P's avatar Jakob P
Browse files

Improve access checks for panels routes

parent 3c7f39f7
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -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.
+25 −0
Original line number Diff line number Diff line
@@ -478,6 +478,31 @@ function panels_get_renderer_pipelines($sort = TRUE) {
  return $pipelines;
}

/**
 * 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.
 *
+69 −1
Original line number Diff line number Diff line
@@ -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();
    }
  }
}
+87 −0
Original line number Diff line number Diff line
@@ -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

+13 −0
Original line number Diff line number Diff line
@@ -261,6 +261,19 @@ class panels_renderer_ipe extends panels_renderer_editor {
    }
  } 

  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);
  }

  /**
   * AJAX callback to unlock the IPE.
   *
Loading