diff --git a/core/modules/rest/src/Plugin/views/display/RestExport.php b/core/modules/rest/src/Plugin/views/display/RestExport.php index e3a587c..bb62cf6 100644 --- a/core/modules/rest/src/Plugin/views/display/RestExport.php +++ b/core/modules/rest/src/Plugin/views/display/RestExport.php @@ -20,6 +20,7 @@ use Drupal\views\Plugin\views\display\PathPluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Routing\RouteCollection; +use Drupal\Core\Authentication\AuthenticationCollectorInterface; /** * The plugin that handles Data response callbacks for REST resources. @@ -98,9 +99,11 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac * The state key value store. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. + * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $authentication_collector + * The collector of authentication providers. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer) { - parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state); + public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer, AuthenticationCollectorInterface $authentication_collector) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state, $authentication_collector); $this->renderer = $renderer; } @@ -115,7 +118,9 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_definition, $container->get('router.route_provider'), $container->get('state'), - $container->get('renderer') + $container->get('renderer'), + $container->get('authentication_collector') + ); } /** @@ -245,6 +250,7 @@ public function optionsSummary(&$categories, &$options) { $options['path']['category'] = 'path'; $options['path']['title'] = $this->t('Path'); + $options['auth']['category'] = 'path'; // Remove css/exposed form settings, as they are not used for the data // display. diff --git a/core/modules/rest/tests/src/Unit/CollectRoutesTest.php b/core/modules/rest/tests/src/Unit/CollectRoutesTest.php index c49ff87..553a994 100644 --- a/core/modules/rest/tests/src/Unit/CollectRoutesTest.php +++ b/core/modules/rest/tests/src/Unit/CollectRoutesTest.php @@ -78,6 +78,12 @@ protected function setUp() { $container->set('plugin.manager.views.style', $style_manager); $container->set('renderer', $this->getMock('Drupal\Core\Render\RendererInterface')); + $authentication_collector = $this->getMock('\Drupal\Core\Authentication\AuthenticationCollectorInterface'); + $container->set('authentication_collector', $authentication_collector); + $authentication_collector->expects($this->any()) + ->method('getSortedProviders') + ->will($this->returnValue(array('basic_auth' => 'data', 'cookie' => 'data'))); + \Drupal::setContainer($container); $this->restExport = RestExport::create($container, array(), "test_routes", array()); @@ -89,6 +95,9 @@ protected function setUp() { // Set the style option. $this->restExport->setOption('style', array('type' => 'serializer')); + // Set the auth option. + $this->restExport->setOption('auth', ['basic_auth']); + $display_manager->expects($this->once()) ->method('getDefinition') ->will($this->returnValue(array('id' => 'test', 'provider' => 'test'))); diff --git a/core/modules/views/config/schema/views.display.schema.yml b/core/modules/views/config/schema/views.display.schema.yml index d31678f..9c83876 100644 --- a/core/modules/views/config/schema/views.display.schema.yml +++ b/core/modules/views/config/schema/views.display.schema.yml @@ -13,6 +13,12 @@ views_display_path: route_name: type: string label: 'Route name' + auth: + type: sequence + label: 'Authentication' + sequence: + type: string + label: 'Authentication Provider' views.display.page: type: views_display_path diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php index 8868c8b..c952aee 100644 --- a/core/modules/views/src/Plugin/views/display/Page.php +++ b/core/modules/views/src/Plugin/views/display/Page.php @@ -8,6 +8,7 @@ namespace Drupal\views\Plugin\views\display; use Drupal\Component\Utility\Xss; +use Drupal\Core\Authentication\AuthenticationCollectorInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\State\StateInterface; @@ -69,11 +70,13 @@ class Page extends PathPluginBase { * The route provider. * @param \Drupal\Core\State\StateInterface $state * The state key value store. + * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $authentication_collector + * The collector of authentication providers. * @param \Drupal\Core\Entity\EntityStorageInterface $menu_storage * The menu storage. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, EntityStorageInterface $menu_storage) { - parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state); + public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, AuthenticationCollectorInterface $authentication_collector, EntityStorageInterface $menu_storage) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state, $authentication_collector); $this->menuStorage = $menu_storage; } @@ -87,6 +90,7 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_definition, $container->get('router.route_provider'), $container->get('state'), + $container->get('authentication_collector'), $container->get('entity.manager')->getStorage('menu') ); } diff --git a/core/modules/views/src/Plugin/views/display/PathPluginBase.php b/core/modules/views/src/Plugin/views/display/PathPluginBase.php index 599e7f0..f9bc129 100644 --- a/core/modules/views/src/Plugin/views/display/PathPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php @@ -23,6 +23,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; +use Drupal\Core\Authentication\AuthenticationCollectorInterface; /** * The base display plugin for path/callbacks. This is used for pages and feeds. @@ -48,6 +49,13 @@ protected $state; /** + * The collector of authentication providers. + * + * @var \Drupal\Core\Authentication\AuthenticationCollectorInterface + */ + protected $authenticationCollector; + + /** * Constructs a PathPluginBase object. * * @param array $configuration @@ -60,12 +68,15 @@ * The route provider. * @param \Drupal\Core\State\StateInterface $state * The state key value store. + * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $authentication_collector + * The collector of authentication providers. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, AuthenticationCollectorInterface $authentication_collector) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->routeProvider = $route_provider; $this->state = $state; + $this->authenticationCollector = $authentication_collector; } /** @@ -77,7 +88,8 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_id, $plugin_definition, $container->get('router.route_provider'), - $container->get('state') + $container->get('state'), + $container->get('authentication_collector') ); } @@ -118,6 +130,7 @@ protected function defineOptions() { $options = parent::defineOptions(); $options['path'] = array('default' => ''); $options['route_name'] = array('default' => ''); + $options['auth'] = array('default' => array()); return $options; } @@ -228,6 +241,13 @@ public function collectRoutes(RouteCollection $collection) { if (!($route_name = $this->getOption('route_name'))) { $route_name = "view.$view_id.$display_id"; } + + // Add authentication to the route if it was set. + $auth = $this->getOption('auth'); + if (!empty($auth)) { + $route->setOption('_auth', $auth); + } + $collection->add($route_name, $route); return array("$view_id.$display_id" => $route_name); } @@ -387,6 +407,21 @@ public function optionsSummary(&$categories, &$options) { 'title' => $this->t('Path'), 'value' => views_ui_truncate($path, 24), ); + + // Authentication. + $auth = $this->getOption('auth'); + if (empty($auth)) { + $auth = $this->t('No authentication is set'); + } + else { + $auth = implode(', ', $auth); + } + + $options['auth'] = array( + 'category' => 'page', + 'title' => $this->t('Authentication'), + 'value' => views_ui_truncate($auth, 24), + ); } /** @@ -410,6 +445,17 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { '#maxlength' => 254, ); break; + case 'auth': + $authentication_providers = array_keys($this->authenticationCollector->getSortedProviders()); + $form['#title'] .= $this->t('The supported authentication methods for this view'); + $form['auth'] = array( + '#type' => 'checkboxes', + '#title' => $this->t('Authentication methods'), + '#description' => $this->t('These are the supported authentication providers for this view. When this view is requested, the client will be forced to authenticate with one of the selected providers. Make sure you set the appropiate requirements at the Access section since the Authentication System will fallback to the anonymous user if it fails to authenticate. For example: require Access: Role | Authenticated User.'), + '#options' => array_combine($authentication_providers, $authentication_providers), + '#default_value' => $this->getOption('auth'), + ); + break; } } @@ -439,6 +485,10 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { if ($form_state->get('section') == 'path') { $this->setOption('path', $form_state->getValue('path')); } + + if ($form_state->get('section') == 'auth') { + $this->setOption('auth', array_filter($form_state->getValue('auth'))); + } } /** diff --git a/core/modules/views/tests/src/Unit/Plugin/display/PathPluginBaseTest.php b/core/modules/views/tests/src/Unit/Plugin/display/PathPluginBaseTest.php index b0ebe13..f84f45d 100644 --- a/core/modules/views/tests/src/Unit/Plugin/display/PathPluginBaseTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/display/PathPluginBaseTest.php @@ -47,6 +47,13 @@ class PathPluginBaseTest extends UnitTestCase { protected $state; /** + * The mocked authentication collector. + * + * @var \Drupal\Core\Authentication\AuthenticationCollector + */ + protected $authentication_collector; + + /** * {@inheritdoc} */ protected function setUp() { @@ -54,8 +61,9 @@ protected function setUp() { $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); $this->state = $this->getMock('\Drupal\Core\State\StateInterface'); + $this->authentication_collector = $this->getMock('\Drupal\Core\Authentication\AuthenticationCollector'); $this->pathPlugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase') - ->setConstructorArgs(array(array(), 'path_base', array(), $this->routeProvider, $this->state)) + ->setConstructorArgs(array(array(), 'path_base', array(), $this->routeProvider, $this->state, $this->authentication_collector)) ->setMethods(NULL) ->getMock(); $this->setupContainer(); @@ -125,7 +133,7 @@ public function testCollectRoutesWithDisplayReturnResponse() { 'path' => 'test_route', ); $this->pathPlugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase') - ->setConstructorArgs(array(array(), 'path_base', array('returns_response' => TRUE), $this->routeProvider, $this->state)) + ->setConstructorArgs(array(array(), 'path_base', array('returns_response' => TRUE), $this->routeProvider, $this->state, $this->authentication_collector)) ->setMethods(NULL) ->getMock(); $this->pathPlugin->initDisplay($view, $display); diff --git a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php index d4bc2b6..81043d2 100644 --- a/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php +++ b/core/modules/views_ui/tests/src/Unit/ViewListBuilderTest.php @@ -83,9 +83,10 @@ public function testBuildRowEntityList() { $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); $state = $this->getMock('\Drupal\Core\State\StateInterface'); $menu_storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface'); + $auth_collector = $this->getMock('\Drupal\Core\Authentication\AuthenticationCollector'); $page_display = $this->getMock('Drupal\views\Plugin\views\display\Page', array('initDisplay', 'getPath'), - array(array(), 'default', $display_manager->getDefinition('page'), $route_provider, $state, $menu_storage) + array(array(), 'default', $display_manager->getDefinition('page'), $route_provider, $state, $auth_collector, $menu_storage) ); $page_display->expects($this->any()) ->method('getPath')