From f8d3dec5da7c6585dfb8ad05dde539a7c8706aab Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Fri, 1 Sep 2017 08:32:43 -0400
Subject: [PATCH] Added configurable denied permission behavior. - See
 permissionBehavior.ini for new options - Adds new helper classes for managing
 permissions - Adds new controller plugin for permission checks - Adds new
 view helper for permission checks

---
 config/vufind/permissionBehavior.ini          |  72 ++++++
 module/VuFind/config/module.config.php        |   3 +
 .../src/VuFind/Controller/AbstractBase.php    |  25 ++-
 .../src/VuFind/Controller/Plugin/Factory.php  |  30 ++-
 .../VuFind/Controller/Plugin/Permission.php   | 120 ++++++++++
 .../VuFind/Role/PermissionDeniedManager.php   | 203 +++++++++++++++++
 .../src/VuFind/Role/PermissionManager.php     | 110 +++++++++
 module/VuFind/src/VuFind/Service/Factory.php  |  32 +++
 .../src/VuFind/View/Helper/Root/Factory.php   |  16 ++
 .../VuFind/View/Helper/Root/Permission.php    | 128 +++++++++++
 .../Role/PermissionDeniedManagerTest.php      | 153 +++++++++++++
 .../VuFindTest/Role/PermissionManagerTest.php | 132 +++++++++++
 .../View/Helper/Root/PermissionTest.php       | 208 ++++++++++++++++++
 themes/root/theme.config.php                  |   1 +
 14 files changed, 1213 insertions(+), 20 deletions(-)
 create mode 100644 config/vufind/permissionBehavior.ini
 create mode 100644 module/VuFind/src/VuFind/Controller/Plugin/Permission.php
 create mode 100644 module/VuFind/src/VuFind/Role/PermissionDeniedManager.php
 create mode 100644 module/VuFind/src/VuFind/Role/PermissionManager.php
 create mode 100644 module/VuFind/src/VuFind/View/Helper/Root/Permission.php
 create mode 100644 module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionDeniedManagerTest.php
 create mode 100644 module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionManagerTest.php
 create mode 100644 module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/PermissionTest.php

diff --git a/config/vufind/permissionBehavior.ini b/config/vufind/permissionBehavior.ini
new file mode 100644
index 00000000000..d9250bd4c3b
--- /dev/null
+++ b/config/vufind/permissionBehavior.ini
@@ -0,0 +1,72 @@
+; This file controls how denied permissions are treated within VuFind.
+;
+; The permissions need to be set in permissions.ini.
+; In this file you can configure what should happen if a permission is denied.
+; Please use the permission names from permissions.ini as section names here.
+;
+; Example:
+;
+; This role from permissions.ini:
+;
+; [default.EITModule]
+; role = loggedin
+; permission = access.EITModule
+;
+; should be configured here in section:
+;
+; [access.EITModule]
+;
+; See permissions.ini for more permissions that you may also wish to configure here.
+;
+; Within each section, there are two options which can be configured:
+;
+; deniedTemplateBehavior: The behavior to apply when a permission is denied
+; dynamically within a template; i.e. the user has access to a page but is blocked
+; from a particular feature of that page. If undefined, the default behavior is
+; to hide the affected functionality and display no special message.
+;
+; deniedControllerBehavior: The behavior to apply when a permission is denied at the
+; controller level; i.e. the user is totally blocked from accessing something. If
+; undefined, the default behavior defined by the controller (usually promptLogin)
+; will be applied.
+;
+; Each of these options may be set to one of the following options; most options
+; also receive a colon-delimited list of parameters.
+;
+; exception - Throw the specified exception class (param 1) with the specified
+;     exception message (param 2).
+;     This option is ONLY supported by deniedControllerBehavior.
+;     example: deniedControllerBehavior = exception:MyExceptionClass:Access Denied.
+;
+; promptLogin - Redirect the user to the login page. You can optionally set the
+;     first parameter to a message to display on the login page (omit for default).
+;     This option is ONLY supported by deniedControllerBehavior.
+;     example: deniedControllerBehavior = promptLogin
+;
+; showMessage - Display the message (the first parameter) to the user; this text
+;     will be run through the translator. When used as the deniedControllerBehavior,
+;     the message will be displayed in the form of a flash message on the
+;     "permission denied" screen. When used as the deniedTemplateBehavior, the text
+;     will be displayed in place of the blocked markup.
+;     example: deniedControllerBehavior = showMessage:Blocked!
+;
+; showTemplate - Render a specific template, specified as the first parameter.
+;     This option is ONLY supported by deniedTemplateBehavior.
+;     example: deniedTemplateBehavior = showTemplate:error/denied
+
+; Section for global parameters
+[global]
+; The default behavior will get used if a permission is denied, but the controller
+; in question defines no default behavior and no permission denied behavior has been
+; configured in this file for the relevant permission.
+defaultDeniedControllerBehavior = "promptLogin"
+
+; The default behavior will get used if a permission is denied, but no permission
+; denied behavior has been configured in this file for the relevant permission.
+; (False means "use the default behavior defined by the template").
+defaultDeniedTemplateBehavior = false
+
+; Example configuration for non-standard favorites permission behavior:
+;[feature.Favorites]
+;deniedTemplateBehavior = "showMessage:Login for Favorites"
+;deniedControllerBehavior = "exception::You are not logged in!"
diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 314f7c9631a..77222f57558 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -159,6 +159,7 @@ $config = [
             'holds' => 'VuFind\Controller\Plugin\Factory::getHolds',
             'newitems' => 'VuFind\Controller\Plugin\Factory::getNewItems',
             'ILLRequests' => 'VuFind\Controller\Plugin\Factory::getILLRequests',
+            'permission' => 'VuFind\Controller\Plugin\Factory::getPermission',
             'recaptcha' => 'VuFind\Controller\Plugin\Factory::getRecaptcha',
             'reserves' => 'VuFind\Controller\Plugin\Factory::getReserves',
             'result-scroller' => 'VuFind\Controller\Plugin\Factory::getResultScroller',
@@ -218,6 +219,8 @@ $config = [
             'VuFind\RecordTabPluginManager' => 'VuFind\Service\Factory::getRecordTabPluginManager',
             'VuFind\RelatedPluginManager' => 'VuFind\Service\Factory::getRelatedPluginManager',
             'VuFind\ResolverDriverPluginManager' => 'VuFind\Service\Factory::getResolverDriverPluginManager',
+            'VuFind\Role\PermissionManager' => 'VuFind\Service\Factory::getPermissionManager',
+            'VuFind\Role\PermissionDeniedManager' => 'VuFind\Service\Factory::getPermissionDeniedManager',
             'VuFind\Search' => 'VuFind\Service\Factory::getSearchService',
             'VuFind\Search\BackendManager' => 'VuFind\Service\Factory::getSearchBackendManager',
             'VuFind\Search\Memory' => 'VuFind\Service\Factory::getSearchMemory',
diff --git a/module/VuFind/src/VuFind/Controller/AbstractBase.php b/module/VuFind/src/VuFind/Controller/AbstractBase.php
index 000821ae7cf..1236a31c84c 100644
--- a/module/VuFind/src/VuFind/Controller/AbstractBase.php
+++ b/module/VuFind/src/VuFind/Controller/AbstractBase.php
@@ -60,11 +60,14 @@ class AbstractBase extends AbstractActionController
     protected $accessPermission = false;
 
     /**
-     * Behavior when access is denied. Valid values are 'promptLogin' and 'exception'
+     * Behavior when access is denied (used unless overridden through
+     * permissionBehavior.ini). Valid values are 'promptLogin' and 'exception'.
+     * Leave at null to use the defaultDeniedControllerBehavior set in
+     * permissionBehavior.ini (normally 'promptLogin' unless changed).
      *
      * @var string
      */
-    protected $accessDeniedBehavior = 'promptLogin';
+    protected $accessDeniedBehavior = null;
 
     /**
      * Constructor
@@ -85,17 +88,15 @@ class AbstractBase extends AbstractActionController
      */
     public function validateAccessPermission(MvcEvent $e)
     {
-        // Make sure the current user has permission to access the module:
-        if ($this->accessPermission
-            && !$this->getAuthorizationService()->isGranted($this->accessPermission)
-        ) {
-            if ($this->accessDeniedBehavior == 'promptLogin') {
-                if (!$this->getUser()) {
-                    $e->setResponse($this->forceLogin(null, [], false));
-                    return;
-                }
+        // If there is an access permission set for this controller, pass it
+        // through the permission helper, and if the helper returns a custom
+        // response, use that instead of the normal behavior.
+        if ($this->accessPermission) {
+            $response = $this->permission()
+                ->check($this->accessPermission, $this->accessDeniedBehavior);
+            if (is_object($response)) {
+                $e->setResponse($response);
             }
-            throw new ForbiddenException('Access denied.');
         }
     }
 
diff --git a/module/VuFind/src/VuFind/Controller/Plugin/Factory.php b/module/VuFind/src/VuFind/Controller/Plugin/Factory.php
index 63c7261e64f..c84dec47594 100644
--- a/module/VuFind/src/VuFind/Controller/Plugin/Factory.php
+++ b/module/VuFind/src/VuFind/Controller/Plugin/Factory.php
@@ -103,12 +103,27 @@ class Factory
         );
     }
 
+    /**
+     * Construct the ILLRequests plugin.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return ILLRequests
+     */
+    public static function getILLRequests(ServiceManager $sm)
+    {
+        return new ILLRequests(
+            $sm->getServiceLocator()->get('VuFind\HMAC'),
+            $sm->getServiceLocator()->get('VuFind\SessionManager')
+        );
+    }
+
     /**
      * Construct the NewItems plugin.
      *
      * @param ServiceManager $sm Service manager.
      *
-     * @return Reserves
+     * @return NewItems
      */
     public static function getNewItems(ServiceManager $sm)
     {
@@ -119,18 +134,17 @@ class Factory
     }
 
     /**
-     * Construct the ILLRequests plugin.
+     * Construct the Permission plugin.
      *
      * @param ServiceManager $sm Service manager.
      *
-     * @return ILLRequests
+     * @return Permission
      */
-    public static function getILLRequests(ServiceManager $sm)
+    public static function getPermission(ServiceManager $sm)
     {
-        return new ILLRequests(
-            $sm->getServiceLocator()->get('VuFind\HMAC'),
-            $sm->getServiceLocator()->get('VuFind\SessionManager')
-        );
+        $pdm = $sm->getServiceLocator()->get('VuFind\Role\PermissionDeniedManager');
+        $pm = $sm->getServiceLocator()->get('VuFind\Role\PermissionManager');
+        return new Permission($pm, $pdm);
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Controller/Plugin/Permission.php b/module/VuFind/src/VuFind/Controller/Plugin/Permission.php
new file mode 100644
index 00000000000..ba91c34ac28
--- /dev/null
+++ b/module/VuFind/src/VuFind/Controller/Plugin/Permission.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * VuFind Action Helper - Permission Checker
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Controller_Plugins
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org Main Page
+ */
+namespace VuFind\Controller\Plugin;
+use VuFind\I18n\Translator\TranslatorAwareInterface;
+use VuFind\Role\PermissionDeniedManager;
+use VuFind\Role\PermissionManager;
+use Zend\Log\LoggerAwareInterface;
+use Zend\Mvc\Controller\Plugin\AbstractPlugin;
+
+/**
+ * VuFind Action Helper - Permission Checker
+ *
+ * @category VuFind
+ * @package  Controller_Plugins
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org Main Page
+ */
+class Permission extends AbstractPlugin implements LoggerAwareInterface,
+    TranslatorAwareInterface
+{
+    use \VuFind\I18n\Translator\TranslatorAwareTrait;
+    use \VuFind\Log\LoggerAwareTrait;
+
+    /**
+     * Permission manager
+     *
+     * @var PermissionManager
+     */
+    protected $permissionManager;
+
+    /**
+     * Permission denied manager
+     *
+     * @var PermissionDeniedManager
+     */
+    protected $permissionDeniedManager;
+
+    /**
+     * Constructor
+     *
+     * @param PermissionManager       $pm  Permission Manager
+     * @param PermissionDeniedManager $pdm Permission Denied Manager
+     */
+    public function __construct(PermissionManager $pm, PermissionDeniedManager $pdm)
+    {
+        $this->permissionManager = $pm;
+        $this->permissionDeniedManager = $pdm;
+    }
+
+    /**
+     * Check if a permission is denied; if so, throw an exception or return an
+     * error response as configured in permissionBehavior.ini.
+     *
+     * @param string $permission      Permission to check
+     * @param string $defaultBehavior Default behavior to use if none configured
+     * (null to use default configured in the manager, false to take no action).
+     *
+     * @return mixed
+     */
+    public function check($permission, $defaultBehavior = null)
+    {
+        // Make sure the current user has permission to access the module:
+        if ($this->permissionManager->isAuthorized($permission) !== true) {
+            $dl = $this->permissionDeniedManager->getDeniedControllerBehavior(
+                $permission, $defaultBehavior
+            );
+            $exceptionDescription = isset($dl['exceptionMessage'])
+                ? $dl['exceptionMessage'] : 'Access denied.';
+            switch (strtolower($dl['action'])) {
+            case 'promptlogin':
+                $msg = empty($dl['value']) ? null : $dl['value'];
+                return $this->getController()->forceLogin($msg, [], false);
+            case 'showmessage':
+                return $this->getController()->redirect()->toRoute(
+                    'error-permissiondenied', [],
+                    ['query' => ['msg' => $dl['value']]]
+                );
+            case 'exception':
+                $exceptionClass
+                    = (isset($dl['value']) && class_exists($dl['value']))
+                    ? $dl['value'] : 'VuFind\Exception\Forbidden';
+                $exception = new $exceptionClass($exceptionDescription);
+                if ($exception instanceof \Exception) {
+                    throw $exception;
+                }
+                $this->logError("Permission configuration problem.");
+                throw new \Exception("$exceptionClass is not an exception!");
+            default:
+                throw new ForbiddenException($exceptionDescription);
+            }
+        }
+        return null;
+    }
+}
diff --git a/module/VuFind/src/VuFind/Role/PermissionDeniedManager.php b/module/VuFind/src/VuFind/Role/PermissionDeniedManager.php
new file mode 100644
index 00000000000..a08e305bec1
--- /dev/null
+++ b/module/VuFind/src/VuFind/Role/PermissionDeniedManager.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Permission Manager
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Authorization
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+namespace VuFind\Role;
+
+/**
+ * Permission Manager
+ *
+ * @category VuFind
+ * @package  Authorization
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+class PermissionDeniedManager
+{
+    /**
+     * List config
+     *
+     * @var array
+     */
+    protected $config;
+
+    /**
+     * Default behavior for denied permissions at the controller level.
+     *
+     * @var string|bool
+     */
+    protected $defaultDeniedControllerBehavior = 'promptLogin';
+
+    /**
+     * Default behavior for denied permissions at the template level.
+     * (False means "do nothing").
+     *
+     * @var string|bool
+     */
+    protected $defaultDeniedTemplateBehavior = false;
+
+    /**
+     * Constructor
+     *
+     * @param array $config configuration
+     */
+    public function __construct($config)
+    {
+        $this->config = $config;
+        // if the config contains a defaultDeniedControllerBehavior setting, apply it
+        if (isset($config['global']['defaultDeniedControllerBehavior'])) {
+            $this->defaultDeniedControllerBehavior
+                = $config['global']['defaultDeniedControllerBehavior'];
+        }
+        // if the config contains a defaultDeniedTemplateBehavior setting, apply it
+        if (isset($config['global']['defaultDeniedTemplateBehavior'])) {
+            $this->defaultDeniedTemplateBehavior
+                = $config['global']['defaultDeniedTemplateBehavior'];
+        }
+    }
+
+    /**
+     * Set the default behavior for a denied controller permission
+     *
+     * @param string|bool $value Default behavior for a denied controller permission
+     *
+     * @return void
+     */
+    public function setDefaultDeniedControllerBehavior($value)
+    {
+        $this->defaultDeniedControllerBehavior = $value;
+    }
+
+    /**
+     * Set the default behavior for a denied template permission
+     *
+     * @param string|bool $value Default behavior for a denied template permission
+     *
+     * @return void
+     */
+    public function setDefaultDeniedTemplateBehavior($value)
+    {
+        $this->defaultDeniedTemplateBehavior = $value;
+    }
+
+    /**
+     * Get behavior to apply when a controller denies a permission.
+     *
+     * @param string $permission      Permission that has been denied
+     * @param string $defaultBehavior Default behavior to use if none configured
+     * (null to use default configured in this class, false to take no action).
+     *
+     * @return array|bool Associative array of behavior for the given
+     * permission (containing the keys 'action', 'value', 'params' and
+     * 'exceptionMessage' for exceptions) or false if no action needed.
+     */
+    public function getDeniedControllerBehavior($permission, $defaultBehavior = null)
+    {
+        if ($defaultBehavior === null) {
+            $defaultBehavior = $this->defaultDeniedControllerBehavior;
+        }
+        return $this->getDeniedBehavior(
+            $permission, 'deniedControllerBehavior', $defaultBehavior
+        );
+    }
+
+    /**
+     * Get behavior to apply when a template denies a permission.
+     *
+     * @param string $permission      Permission that has been denied
+     * @param string $defaultBehavior Default action to use if none configured
+     * (null to use default configured in this class, false to take no action).
+     *
+     * @return array|bool
+     */
+    public function getDeniedTemplateBehavior($permission, $defaultBehavior = null)
+    {
+        if ($defaultBehavior === null) {
+            $defaultBehavior = $this->defaultDeniedTemplateBehavior;
+        }
+        return $this->getDeniedBehavior(
+            $permission, 'deniedTemplateBehavior', $defaultBehavior
+        );
+    }
+
+    /**
+     * Get permission denied logic
+     *
+     * @param string $permission      Permission that has been denied
+     * @param string $mode            Mode of the operation. Should be either
+     * deniedControllerBehavior or deniedTemplateBehavior
+     * @param string $defaultBehavior Default action to use if none configured
+     *
+     * @return array|bool
+     */
+    protected function getDeniedBehavior($permission, $mode, $defaultBehavior)
+    {
+        $config = isset($this->config[$permission][$mode])
+            ? $this->config[$permission][$mode] : $defaultBehavior;
+
+        return empty($config) ? false : $this->processConfigString($config);
+    }
+
+    /**
+     * Translate a configuration string into an array.
+     *
+     * @param string $config Configuration string to process
+     *
+     * @return array
+     */
+    protected function processConfigString($config)
+    {
+        // Split config string:
+        $parts = explode(':', $config);
+
+        // Load standard values:
+        $output = [
+            'action' => array_shift($parts),
+            'value' => array_shift($parts),
+        ];
+
+        // Special case -- extra parameters for exceptions:
+        if (strtolower($output['action']) === 'exception') {
+            $output['exceptionMessage'] = array_shift($parts);
+        }
+
+        // Now process any remaining keypairs:
+        $params = [];
+        while ($param = array_shift($parts)) {
+            $paramParts = explode('=', $param, 2);
+            if (count($paramParts) == 2) {
+                $params[$paramParts[0]] = $paramParts[1];
+            } else {
+                $params[] = $paramParts[0];
+            }
+        }
+        $output['params'] = $params;
+        return $output;
+    }
+}
diff --git a/module/VuFind/src/VuFind/Role/PermissionManager.php b/module/VuFind/src/VuFind/Role/PermissionManager.php
new file mode 100644
index 00000000000..4ec82c7ba8b
--- /dev/null
+++ b/module/VuFind/src/VuFind/Role/PermissionManager.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Permission Manager
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Authorization
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+namespace VuFind\Role;
+use ZfcRbac\Service\AuthorizationServiceAwareTrait;
+
+/**
+ * Permission Manager
+ *
+ * @category VuFind
+ * @package  Authorization
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+class PermissionManager
+{
+    use AuthorizationServiceAwareTrait;
+
+    /**
+     * List config
+     *
+     * @var array
+     */
+    protected $config;
+
+    /**
+     * Constructor
+     *
+     * @param array $config configuration
+     */
+    public function __construct(array $config)
+    {
+        $this->config = $config;
+    }
+
+    /**
+     * Determine if the user is authorized in a certain context or not
+     *
+     * @param string $context Context for the permission behavior
+     *
+     * @return bool
+     */
+    public function isAuthorized($context)
+    {
+        $authService = $this->getAuthorizationService();
+
+        // if no authorization service is available return false
+        if (!$authService) {
+            return false;
+        }
+
+        if ($authService->isGranted($context)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Check if a permission rule exists for a given context
+     *
+     * @param string $context Context for the permission behavior
+     *
+     * @return bool
+     */
+    public function permissionRuleExists($context)
+    {
+        foreach ($this->config as $key => $value) {
+            if (!isset($value['permission'])) {
+                continue;
+            }
+            if ($value['permission'] == $context) {
+                return true;
+            }
+            if (is_array($value['permission'])
+                && in_array($context, $value['permission'])
+            ) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/module/VuFind/src/VuFind/Service/Factory.php b/module/VuFind/src/VuFind/Service/Factory.php
index 1a0ef93fbcb..cbe060ff0c7 100644
--- a/module/VuFind/src/VuFind/Service/Factory.php
+++ b/module/VuFind/src/VuFind/Service/Factory.php
@@ -590,6 +590,38 @@ class Factory
         );
     }
 
+    /**
+     * Construct the PermissionDeniedManager.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return \VuFind\Role\PermissionDeniedManager
+     */
+    public static function getPermissionDeniedManager(ServiceManager $sm)
+    {
+        return new \VuFind\Role\PermissionDeniedManager(
+            $sm->get('VuFind\Config')->get('permissionBehavior')
+        );
+    }
+
+    /**
+     * Construct the PermissionManager.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return \VuFind\Role\PermissionManager
+     */
+    public static function getPermissionManager(ServiceManager $sm)
+    {
+            $permManager = new \VuFind\Role\PermissionManager(
+                $sm->get('VuFind\Config')->get('permissions')->toArray()
+            );
+            $permManager->setAuthorizationService(
+                $sm->get('ZfcRbac\Service\AuthorizationService')
+            );
+            return $permManager;
+    }
+
     /**
      * Construct the RecordDriver Plugin Manager.
      *
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Factory.php b/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
index 682a83d2e70..021e1b7b1f7 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
@@ -234,6 +234,22 @@ class Factory
         return new GoogleAnalytics($key, $universal);
     }
 
+    /**
+     * Construct the Permission helper.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return Permission
+     */
+    public static function getPermission(ServiceManager $sm)
+    {
+        $ld = new Permission(
+            $sm->getServiceLocator()->get('VuFind\Role\PermissionManager'),
+            $sm->getServiceLocator()->get('VuFind\Role\PermissionDeniedManager')
+        );
+        return $ld;
+    }
+
     /**
      * Construct the Piwik helper.
      *
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Permission.php b/module/VuFind/src/VuFind/View/Helper/Root/Permission.php
new file mode 100644
index 00000000000..816a128f01b
--- /dev/null
+++ b/module/VuFind/src/VuFind/View/Helper/Root/Permission.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * Permission helper
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  View_Helpers
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+namespace VuFind\View\Helper\Root;
+use VuFind\Role\PermissionDeniedManager;
+use VuFind\Role\PermissionManager;
+use Zend\View\Helper\AbstractHelper;
+
+/**
+ * Permission helper
+ *
+ * @category VuFind
+ * @package  View_Helpers
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/ Wiki
+ */
+class Permission extends AbstractHelper
+{
+    /**
+     * PermissionDenied manager for behavior on denied permissions
+     *
+     * @var PermissionDeniedManager
+     */
+    protected $permissionDeniedManager;
+
+    /**
+     * Permission manager to decide if a permission has been granted or not
+     *
+     * @var PermissionManager
+     */
+    protected $permissionManager;
+
+    /**
+     * Constructor
+     *
+     * @param PermissionsManager       $permissionManager       Manager to decide
+     *                                                          if a permission has
+     *                                                          been granted or not
+     * @param PermissionsDeniedManager $permissionDeniedManager Manager for
+     *                                                          behavior on
+     *                                                          denied permissions
+     */
+    public function __construct(
+        PermissionManager $permissionManager,
+        PermissionDeniedManager $permissionDeniedManager
+    ) {
+        $this->permissionManager = $permissionManager;
+        $this->permissionDeniedManager = $permissionDeniedManager;
+    }
+
+    /**
+     * Determine if a local block inside the template should be displayed
+     *
+     * @param string $context Name of the permission rule
+     *
+     * @return bool
+     */
+    public function allowDisplay($context)
+    {
+        // If there is no context, assume permission is granted.
+        if (empty($context)) {
+            return true;
+        }
+
+        // If permission has been granted, we do not need to continue
+        // Just return true to indicate that the default can get applied
+        if ($this->permissionManager->isAuthorized($context) === true) {
+            return true;
+        }
+        // If we are getting to this point, we know that the permission has been
+        // denied. Nevertheless show the local block if there is no
+        // deniedTemplateBehavior set for this context.
+        $displayLogic = $this->permissionDeniedManager
+            ->getDeniedTemplateBehavior($context);
+        return !isset($displayLogic['action']);
+    }
+
+    /**
+     * Get content to display in place of blocked content
+     *
+     * @param string $context Name of the permission rule
+     *
+     * @return string
+     */
+    public function getAlternateContent($context)
+    {
+        $displayLogic = $this->permissionDeniedManager
+            ->getDeniedTemplateBehavior($context);
+
+        switch (isset($displayLogic['action']) ? $displayLogic['action'] : '') {
+        case 'showMessage':
+            return $this->view->transEsc($displayLogic['value']);
+        case 'showTemplate':
+            return $this->view->context($this->view)->renderInContext(
+                $displayLogic['value'], $displayLogic['params']
+            );
+        default:
+            return null;
+        }
+    }
+}
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionDeniedManagerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionDeniedManagerTest.php
new file mode 100644
index 00000000000..ee0156e0047
--- /dev/null
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionDeniedManagerTest.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * PermissionManager Test Class
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Oliver Goldschmidt <@o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+namespace VuFindTest\Role;
+use VuFind\Role\PermissionDeniedManager;
+
+/**
+ * PermissionManager Test Class
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Oliver Goldschmidt <@o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+class PermissionDeniedManagerTest extends \VuFindTest\Unit\TestCase
+{
+    /**
+     * Sample configuration with varios config options.
+     *
+     * @var array
+     */
+    protected $permissionDeniedConfig = [
+        'permissionDeniedTemplate' => [
+            'deniedTemplateBehavior' => "showTemplate:record/displayLogicTest:param1=noValue",
+            'deniedControllerBehavior' => "showTemplate:record/ActionTest:param1=noValue"
+        ],
+        'permissionDeniedTemplateNoParams' => [
+            'deniedTemplateBehavior' => "showTemplate:record/displayLogicTest",
+            'deniedControllerBehavior' => "showTemplate:record/ActionTest"
+        ],
+        'permissionDeniedMessage' => [
+            'deniedTemplateBehavior' => "showMessage:dl_translatable_test",
+            'deniedControllerBehavior' => "showTemplate:action_translatable_test"
+        ],
+        'permissionDeniedLogin' => [
+            'deniedControllerBehavior' => "promptLogin"
+        ],
+        'permissionDeniedException' => [
+            'deniedControllerBehavior' => "exception:ForbiddenException:exception_message"
+        ],
+        'permissionDeniedNonExistentException' => [
+            'deniedControllerBehavior' => "exception:NonExistentException:exception_message"
+        ],
+        'permissionDeniedNothing' => [
+        ],
+    ];
+
+    /**
+     * Test a correctly configured template
+     *
+     * @return void
+     */
+    public function testTemplateConfig()
+    {
+        $expected = [
+            'action' => 'showTemplate',
+            'value' => 'record/ActionTest',
+            'params' => [
+                'param1' => 'noValue',
+            ],
+        ];
+        $expectedNoParams = [
+            'action' => 'showTemplate',
+            'value' => 'record/ActionTest',
+            'params' => [],
+        ];
+        $pm = new PermissionDeniedManager($this->permissionDeniedConfig);
+
+        $this->assertEquals($expected, $pm->getDeniedControllerBehavior('permissionDeniedTemplate'));
+        $this->assertEquals($expectedNoParams, $pm->getDeniedControllerBehavior('permissionDeniedTemplateNoParams'));
+    }
+
+    /**
+     * Test a correctly configured exception
+     *
+     * @return void
+     */
+    public function testExceptionConfig()
+    {
+        $expected = [
+            'action' => 'exception',
+            'value' => 'ForbiddenException',
+            'exceptionMessage' => 'exception_message',
+            'params' => [],
+        ];
+        $pm = new PermissionDeniedManager($this->permissionDeniedConfig);
+
+        $this->assertEquals($expected, $pm->getDeniedControllerBehavior('permissionDeniedException'));
+    }
+
+    /**
+     * Test an empty permission section
+     * getDeniedControllerBehavior should return false as the PermissionDeniedManager
+     * has nothing to do
+     *
+     * @return void
+     */
+    public function testEmptyConfig()
+    {
+        $expected = [
+            'action' => 'promptLogin',
+            'value' => false,
+            'params' => [],
+        ];
+        $pm = new PermissionDeniedManager($this->permissionDeniedConfig);
+
+        $this->assertEquals($expected, $pm->getDeniedControllerBehavior('permissionDeniedNothing'));
+    }
+
+    /**
+     * Test a non existent permission section
+     * getDeniedControllerBehavior should return false as the PermissionDeniedManager
+     * has nothing to do
+     *
+     * @return void
+     */
+    public function testNonExistentConfig()
+    {
+        $expected = [
+            'action' => 'promptLogin',
+            'value' => false,
+            'params' => [],
+        ];
+        $pm = new PermissionDeniedManager($this->permissionDeniedConfig);
+
+        $this->assertEquals($expected, $pm->getDeniedControllerBehavior('garbage'));
+    }
+}
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionManagerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionManagerTest.php
new file mode 100644
index 00000000000..7c08377cdf6
--- /dev/null
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionManagerTest.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * PermissionManager Test Class
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Oliver Goldschmidt <@o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+namespace VuFindTest\Role;
+use VuFind\Role\PermissionManager;
+
+/**
+ * PermissionManager Test Class
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Oliver Goldschmidt <@o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+class PermissionManagerTest extends \VuFindTest\Unit\TestCase
+{
+    /**
+     * Sample configuration with varios config options.
+     *
+     * @var array
+     */
+    protected $permissionConfig = [
+        'permission.all' => [
+            'permission' => "everyone"
+        ],
+        'permission.nobody' => [
+            'permission' => "nobody"
+        ],
+        'permission.empty' => [
+        ],
+        'permission.array' => [
+            'permission' => ['everyoneArray', 'everyoneArray2']
+        ]
+    ];
+
+    /**
+     * Test a non existent permission section
+     *
+     * @return void
+     */
+    public function testNonExistentPermission()
+    {
+        $pm = new PermissionManager($this->permissionConfig);
+
+        $this->assertEquals(false, $pm->permissionRuleExists('garbage'));
+    }
+
+    /**
+     * Test an existing permission section
+     *
+     * @return void
+     */
+    public function testExistentPermission()
+    {
+        $pm = new PermissionManager($this->permissionConfig);
+
+        $this->assertEquals(true, $pm->permissionRuleExists('everyone'));
+    }
+
+    /**
+     * Test an existing permission section in an array
+     *
+     * @return void
+     */
+    public function testExistentPermissionInArray()
+    {
+        $pm = new PermissionManager($this->permissionConfig);
+
+        $this->assertEquals(true, $pm->permissionRuleExists('everyoneArray'));
+    }
+
+    /**
+     * Test a granted permission
+     *
+     * @return void
+     */
+    public function testGrantedPermission()
+    {
+        $pm = new PermissionManager($this->permissionConfig);
+        $mockAuth = $this->getMockBuilder('ZfcRbac\Service\AuthorizationService')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockAuth->expects($this->any())->method('isGranted')
+            ->will($this->returnValue(true));
+        $pm->setAuthorizationService($mockAuth);
+
+        $this->assertEquals(true, $pm->isAuthorized('permission.everyone'));
+    }
+
+    /**
+     * Test a denied permission
+     *
+     * @return void
+     */
+    public function testDeniedPermission()
+    {
+        $pm = new PermissionManager($this->permissionConfig);
+        $mockAuth = $this->getMockBuilder('ZfcRbac\Service\AuthorizationService')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockAuth->expects($this->any())->method('isGranted')
+            ->will($this->returnValue(false));
+        $pm->setAuthorizationService($mockAuth);
+
+        $this->assertEquals(false, $pm->isAuthorized('permission.nobody'));
+    }
+}
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/PermissionTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/PermissionTest.php
new file mode 100644
index 00000000000..76154cf2f8e
--- /dev/null
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/PermissionTest.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * Permission view helper Test Class
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+namespace VuFindTest\View\Helper\Root;
+use VuFind\View\Helper\Root\Permission;
+
+/**
+ * Permission view helper Test Class
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Oliver Goldschmidt <o.goldschmidt@tuhh.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+class PermissionTest  extends \VuFindTest\Unit\ViewHelperTestCase
+{
+    /**
+     * Sample configuration with varios config options.
+     *
+     * @var array
+     */
+    protected $permissionDeniedConfig = [
+        'permissionDeniedTemplate' => [
+            'deniedTemplateBehavior' => "showTemplate:record/displayLogicTest:param1=noValue",
+            'deniedControllerBehavior' => "showTemplate:record/ActionTest:param1=noValue"
+        ],
+        'permissionDeniedTemplateNoParams' => [
+            'deniedTemplateBehavior' => "showTemplate:record/displayLogicTest",
+            'deniedControllerBehavior' => "showTemplate:record/ActionTest"
+        ],
+        'permissionDeniedMessage' => [
+            'deniedTemplateBehavior' => "showMessage:dl_translatable_test",
+            'deniedControllerBehavior' => "showTemplate:action_translatable_test"
+        ],
+        'permissionDeniedLogin' => [
+            'deniedControllerBehavior' => "promptLogin"
+        ],
+        'permissionDeniedException' => [
+            'deniedControllerBehavior' => "exception:ForbiddenException:exception_message"
+        ],
+        'permissionDeniedNonExistentException' => [
+            'deniedControllerBehavior' => "exception:NonExistentException:exception_message"
+        ],
+        'permissionDeniedNothing' => [
+        ],
+    ];
+
+    /**
+     * Test the message display
+     *
+     * @return void
+     */
+    public function testMessageDisplay()
+    {
+        $mockPmdMessage = $this->getMockPmd([
+                'deniedTemplateBehavior' => [
+                    'action' => 'showMessage',
+                    'value' => 'dl_translatable_test',
+                    'params' => [],
+                ],
+            ]);
+
+        $helper = new Permission($this->getMockPm(false), $mockPmdMessage);
+        $helper->setView($this->getMockView());
+
+        $displayBlock = $helper->getAlternateContent('permissionDeniedMessage');
+        $this->assertEquals('dl_translatable_test', $displayBlock);
+    }
+
+    /**
+     * Test the template display
+     *
+     * @return void
+     */
+    public function testTemplateDisplay()
+    {
+        // Template does not exist, expect an exception, though
+        $this->setExpectedException('Zend\View\Exception\RuntimeException');
+
+        $mockPmd = $this->getMockPmd([
+                'deniedTemplateBehavior' => [
+                    'action' => 'showTemplate',
+                    'value' => 'record/displayLogicTest',
+                    'params' => [],
+                ],
+            ]);
+
+        $helper = new Permission($this->getMockPm(false), $mockPmd);
+        $helper->setView($this->getMockView());
+
+        $displayBlock = $helper->getAlternateContent('permissionDeniedTemplate');
+    }
+
+    /**
+     * Test the template display with an existing template
+     *
+     * @return void
+     */
+    public function testExistingTemplateDisplay()
+    {
+        $mockPmd = $this->getMockPmd([
+                'deniedTemplateBehavior' => [
+                    'action' => 'showTemplate',
+                    'value' => 'ajax/status-available.phtml',
+                    'params' => [],
+                ],
+            ]);
+
+        $helper = new Permission($this->getMockPm(false), $mockPmd);
+        $helper->setView($this->getMockView());
+
+        $this->assertEquals(
+            '<span class="label label-success">Available</span>',
+            trim($helper->getAlternateContent('permissionDeniedTemplate'))
+        );
+    }
+
+    /**
+     * Get mock driver that returns a deniedTemplateBehavior.
+     *
+     * @param array $config Config containing DeniedTemplateBehavior to return
+     *
+     * @return \VuFind\Role\PermissionDeniedManager
+     */
+    protected function getMockPmd($config = false) {
+        $mockPmd = $this->getMockBuilder('\VuFind\Role\PermissionDeniedManager')
+            ->setConstructorArgs([$this->permissionDeniedConfig])
+            ->getMock();
+        $mockPmd->expects($this->any())->method('getDeniedTemplateBehavior')
+            ->will($this->returnValue($config['deniedTemplateBehavior']));
+        return $mockPmd;
+    }
+
+    /**
+     * Get mock permission manager
+     *
+     * @param array $isAuthorized isAuthorized value to return
+     *
+     * @return \VuFind\Role\PermissionManager
+     */
+    protected function getMockPm($isAuthorized = false) {
+        $mockPm = $this->getMockBuilder('\VuFind\Role\PermissionManager')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockPm->expects($this->any())->method('isAuthorized')
+            ->will($this->returnValue($isAuthorized));
+        $mockPm->expects($this->any())->method('permissionRuleExists')
+            ->will($this->returnValue(true));
+
+        return $mockPm;
+    }
+
+    /**
+     * Get mock context helper.
+     *
+     * @return \VuFind\View\Helper\Root\Context
+     */
+    protected function getMockContext()
+    {
+        return $this->getMockBuilder('VuFind\View\Helper\Root\Context')
+            ->disableOriginalConstructor()->getMock();
+    }
+
+    /**
+     * Return a view object populated for these test cases.
+     *
+     * @return \Zend\View\Renderer\PhpRenderer
+     */
+    protected function getMockView()
+    {
+        $escapehtml = new \Zend\View\Helper\EscapeHtml();
+        $translate = new \VuFind\View\Helper\Root\Translate();
+        $transEsc = new \VuFind\View\Helper\Root\TransEsc();
+        $context = new \VuFind\View\Helper\Root\Context();
+        $realView = $this->getPhpRenderer(
+            compact('translate', 'transEsc', 'context', 'escapehtml')
+        );
+        $transEsc->setView($realView);
+        return $realView;
+    }
+}
diff --git a/themes/root/theme.config.php b/themes/root/theme.config.php
index a6d343b3517..79082aaddbf 100644
--- a/themes/root/theme.config.php
+++ b/themes/root/theme.config.php
@@ -22,6 +22,7 @@ return array(
             'ils' => 'VuFind\View\Helper\Root\Factory::getIls',
             'jstranslations' => 'VuFind\View\Helper\Root\Factory::getJsTranslations',
             'keepalive' => 'VuFind\View\Helper\Root\Factory::getKeepAlive',
+            'permission' => 'VuFind\View\Helper\Root\Factory::getPermission',
             'proxyurl' => 'VuFind\View\Helper\Root\Factory::getProxyUrl',
             'openurl' => 'VuFind\View\Helper\Root\Factory::getOpenUrl',
             'piwik' => 'VuFind\View\Helper\Root\Factory::getPiwik',
-- 
GitLab