From a0cc5f7cb33ec76d6506781db2bc2345046324a2 Mon Sep 17 00:00:00 2001 From: Markus Beh <markus.beh@ub.uni-freiburg.de> Date: Mon, 13 Jun 2016 14:59:25 -0400 Subject: [PATCH] new permission provider: grant permissions based on user attributes --- config/vufind/permissions.ini | 10 +- module/VuFind/config/module.config.php | 1 + .../Role/PermissionProvider/Factory.php | 14 ++ .../VuFind/Role/PermissionProvider/User.php | 103 ++++++++++++ .../Role/PermissionProvider/UserTest.php | 158 ++++++++++++++++++ 5 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 module/VuFind/src/VuFind/Role/PermissionProvider/User.php create mode 100644 module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionProvider/UserTest.php diff --git a/config/vufind/permissions.ini b/config/vufind/permissions.ini index f9d95a31f82..e480e9d1e45 100644 --- a/config/vufind/permissions.ini +++ b/config/vufind/permissions.ini @@ -45,6 +45,9 @@ ; rule that checks an attribute. ; username - Grant the permission to logged-in users whose usernames match the ; specified value(s). Accepts a string or an array. +; user - Grant the permissions to logged in users whose user attribute match +; the given regular expression pattern. For valid pattern syntax see +; http://php.net/manual/de/reference.pcre.pattern.syntax.php. ; ; Example configuration (grants the "sample.permission" permission to users named ; admin1 or admin2, or anyone coming from the IP addresses 1.2.3.4 or 1.2.3.5): @@ -57,7 +60,12 @@ ; ipRange[] = "1.2.3.4" ; ipRange[] = "1.2.3.7-1.2.5.254" ; permission = sample.permission -; + +; Example configuration (grants the "sample.permission" permission to users +; who are from myCollege or who is a studentmajor (.*studentmajor.*): +; user[] = "college myCollege" +; user[] = "major .*studentmajor.*" + ; List of permissions that you may wish to configure: ; ; access.AdminModule - Controls access to the admin panel (if enabled in config.ini) diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index d666b96d6e9..9fc55eff7fb 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -707,6 +707,7 @@ $config = [ 'ipRegEx' => 'VuFind\Role\PermissionProvider\Factory::getIpRegEx', 'serverParam' => 'VuFind\Role\PermissionProvider\Factory::getServerParam', 'shibboleth' => 'VuFind\Role\PermissionProvider\Factory::getShibboleth', + 'user' => 'VuFind\Role\PermissionProvider\Factory::getUser', 'username' => 'VuFind\Role\PermissionProvider\Factory::getUsername', ], 'invokables' => [ diff --git a/module/VuFind/src/VuFind/Role/PermissionProvider/Factory.php b/module/VuFind/src/VuFind/Role/PermissionProvider/Factory.php index f7aa828055a..478e6ab8440 100644 --- a/module/VuFind/src/VuFind/Role/PermissionProvider/Factory.php +++ b/module/VuFind/src/VuFind/Role/PermissionProvider/Factory.php @@ -108,4 +108,18 @@ class Factory $sm->getServiceLocator()->get('ZfcRbac\Service\AuthorizationService') ); } + + /** + * Factory for User + * + * @param ServiceManager $sm Service manager. + * + * @return User + */ + public static function getUser(ServiceManager $sm) + { + return new User( + $sm->getServiceLocator()->get('ZfcRbac\Service\AuthorizationService') + ); + } } diff --git a/module/VuFind/src/VuFind/Role/PermissionProvider/User.php b/module/VuFind/src/VuFind/Role/PermissionProvider/User.php new file mode 100644 index 00000000000..817a07c3c55 --- /dev/null +++ b/module/VuFind/src/VuFind/Role/PermissionProvider/User.php @@ -0,0 +1,103 @@ +<?php +/** + * User permission provider for VuFind. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2007. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Authorization + * @author Markus Beh <markus.beh@ub.uni-freiburg.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://www.vufind.org Main Page + */ +namespace VuFind\Role\PermissionProvider; +use ZfcRbac\Service\AuthorizationService; + +/** + * LDAP permission provider for VuFind. + * based on permission provider Username.php + * + * @category VuFind2 + * @package Authorization + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://www.vufind.org Main Page + */ +class User implements PermissionProviderInterface, + \Zend\Log\LoggerAwareInterface +{ + use \VuFind\Log\LoggerAwareTrait; + + /** + * Authorization object + * + * @var AuthorizationService + */ + protected $auth; + + /** + * Constructor + * + * @param AuthorizationService $authorization Authorization service + */ + public function __construct(AuthorizationService $authorization) + { + $this->auth = $authorization; + } + + /** + * Return an array of roles which may be granted the permission based on + * the options. + * + * @param mixed $options Options provided from configuration. + * + * @return array + */ + public function getPermissions($options) + { + // If no user is logged in, or the user doesn't match the passed-in + // whitelist, we can't grant the permission to any roles. + if (!($user = $this->auth->getIdentity())) { + return []; + } + + // which user attribute has to match which pattern to get permissions? + $criteria = []; + foreach ((array)$options as $option) { + $parts = explode(' ', $option, 2); + if (count($parts) < 2) { + $this->logError("configuration option '{$option}' invalid"); + return []; + } else { + list($attribute, $pattern) = $parts; + + // check user attribute values against the pattern + if (! preg_match('/^\/.*\/$/', $pattern)) { + $pattern = '/' . $pattern . '/'; + } + + if (preg_match($pattern, $user[$attribute])) { + return ['loggedin']; + } + } + } + + //no matches found, so the user don't get any permissions + return []; + } +} diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionProvider/UserTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionProvider/UserTest.php new file mode 100644 index 00000000000..4d997c636f3 --- /dev/null +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Role/PermissionProvider/UserTest.php @@ -0,0 +1,158 @@ +<?php +/** + * PermissionProvider User 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind + * @package Tests + * @author Markus Beh <markus.beh@ub.uni-freiburg.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\PermissionProvider; + +use ZfcRbac\Service\AuthorizationService; + +/** + * PermissionProvider User Test Class + * + * @category VuFind + * @package Tests + * @author Markus Beh <markus.beh@ub.uni-freiburg.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 UserTest extends \VuFindTest\Unit\TestCase +{ + protected $userValueMap = [ + 'testuser1' => + [ + ['username','mbeh'], + ['email','markus.beh@ub.uni-freiburg.de'], + ['college', 'Albert Ludwigs Universität Freiburg'] + ] + , + 'testuser2' => + [ + ['username','mbeh2'], + ['email','markus.beh@ub.uni-freiburg.de'], + ['college', 'Villanova University'], + ['major', 'alumni'] + ] + ]; + + + /** + * Test single option with matching string + * + * @return void + */ + public function testGetPermissions() + { + $this->check( + 'testuser1', + ['college .*Freiburg'], + ['loggedin'] + ); + + $this->check( + 'testuser2', + ["college .*Freiburg"], + [] + ); + } + + /** + * Test an invalid configuration + * + * @return void + */ + public function testBadConfig() + { + $this->check( + 'testuser1', + ['college'], + [] + ); + } + + /** + * Convenience method for executing similiar tests + * + * @param string $testuser Name of testuser + * @param array $options Options like settings in permissions.ini + * @param array $roles Roles to return if match + * + * @return void + */ + protected function check($testuser, $options, $roles) + { + $this->testuser + = (isset($this->userValueMap[$testuser])) + ? $testuser + : 'testuser1'; + + $auth = $this->getMockAuthorizationService(); + $this->permissionProvider + = new \VuFind\Role\PermissionProvider\User($auth); + + $this->assertEquals( + $roles, + $this->permissionProvider->getPermissions($options) + ); + } + + /** + * Get a mock authorization service object + * + * @return AuthorizationService + */ + protected function getMockAuthorizationService() + { + $authorizationService + = $this->getMockBuilder('ZfcRbac\Service\AuthorizationService') + ->disableOriginalConstructor() + ->getMock(); + $authorizationService + ->method('getIdentity') + ->will($this->returnValue($this->getMockUser())); + + return $authorizationService; + } + + /** + * Get a mock user object + * + * @return UserRow + */ + protected function getMockUser() + { + $user = $this->getMockBuilder('VuFind\Db\Row\User') + ->disableOriginalConstructor() + ->getMock(); + $user->method('__get') + ->will($this->returnValueMap($this->userValueMap[$this->testuser])); + $user->method('offsetGet') + ->will($this->returnValueMap($this->userValueMap[$this->testuser])); + + return $user; + } + + +} -- GitLab