Merge permissionservice

Permissionservice
This commit is contained in:
Julius Härtl
2016-10-31 00:49:07 +01:00
committed by GitHub
16 changed files with 554 additions and 173 deletions

View File

@@ -12,14 +12,6 @@ coverage:
patch: yes
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "header, diff, changes, sunburst, uncovered"
behavior: default

View File

@@ -36,4 +36,4 @@ after_failure:
- cat ../../data/nextcloud.log
after_success:
- cd build && bash <(curl -s https://codecov.io/bash) -t 49bdd1ee-6ef5-47b9-b80f-825b51515ce9
- cd build && bash <(curl -s https://codecov.io/bash) -t 49bdd1ee-6ef5-47b9-b80f-825b51515ce9 -x fix

View File

@@ -40,19 +40,15 @@ class Application extends App {
$container = $this->getContainer();
$server = $container->getServer();
// This is currently unused
$container->registerService('SharingMiddleware', function ($container) use ($server) {
return new SharingMiddleware(
$container,
$server->getRequest(),
$server->getUserSession(),
$container->query('ControllerMethodReflector'),
$container->query('OCP\IGroupManager'),
$container->query('OCA\Deck\Db\AclMapper'),
$container->query('OCA\Deck\Service\BoardService')
$container->query('OCA\Deck\Service\PermissionService')
);
});
/** @noinspection PhpMethodOrClassCallIsNotCaseSensitiveInspection */
$container->registerMiddleware('SharingMiddleware');
}

View File

@@ -26,6 +26,7 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Db\Acl;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\PermissionService;
use OCP\IRequest;
use OCP\AppFramework\Controller;
@@ -38,6 +39,7 @@ class BoardController extends Controller {
private $boardService;
private $userManager;
private $groupManager;
private $permissionService;
private $userInfo;
public function __construct($appName,
@@ -45,12 +47,14 @@ class BoardController extends Controller {
IUserManager $userManager,
IGroupManager $groupManager,
BoardService $boardService,
PermissionService $permissionService,
$userId) {
parent::__construct($appName, $request);
$this->userId = $userId;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->boardService = $boardService;
$this->permissionService = $permissionService;
$this->userInfo = $this->getBoardPrerequisites();
}
@@ -123,6 +127,7 @@ class BoardController extends Controller {
* @internal param $userId
*/
public function getUserPermissions($boardId) {
$this->permissionService->getPermissions($boardId);
$board = $this->boardService->find($boardId);
if ($this->userId === $board->getOwner()) {
return [

View File

@@ -50,6 +50,9 @@ class Acl extends Entity implements JsonSerializable {
$this->addType('permissionManage', 'boolean');
$this->addType('owner', 'boolean');
$this->addRelation('owner');
$this->setPermissionWrite(false);
$this->setPermissionInvite(false);
$this->setPermissionManage(false);
}
public function getPermission($permission) {

View File

@@ -5,20 +5,20 @@
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* 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 Affero General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace OCA\Deck\Db;
@@ -28,16 +28,16 @@ use OCP\IDb;
class BoardMapper extends DeckMapper implements IPermissionMapper {
private $labelMapper;
private $labelMapper;
private $aclMapper;
private $stackMapper;
public function __construct(IDb $db, LabelMapper $labelMapper, AclMapper $aclMapper, StackMapper $stackMapper) {
parent::__construct($db, 'deck_boards', '\OCA\Deck\Db\Board');
$this->labelMapper = $labelMapper;
$this->aclMapper = $aclMapper;
public function __construct(IDb $db, LabelMapper $labelMapper, AclMapper $aclMapper, StackMapper $stackMapper) {
parent::__construct($db, 'deck_boards', '\OCA\Deck\Db\Board');
$this->labelMapper = $labelMapper;
$this->aclMapper = $aclMapper;
$this->stackMapper = $stackMapper;
}
}
/**
@@ -46,41 +46,46 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
* @param bool $withAcl
* @return \OCP\AppFramework\Db\Entity if not found
*/
public function find($id, $withLabels=false, $withAcl=false) {
$sql = 'SELECT id, title, owner, color, archived FROM `*PREFIX*deck_boards` ' .
'WHERE `id` = ?';
$board = $this->findEntity($sql, [$id]);
public function find($id, $withLabels = false, $withAcl = false) {
$sql = 'SELECT id, title, owner, color, archived FROM `*PREFIX*deck_boards` ' .
'WHERE `id` = ?';
$board = $this->findEntity($sql, [$id]);
// Add labels
$labels = $this->labelMapper->findAll($id);
$board->setLabels($labels);
// Add labels
if ($withLabels) {
$labels = $this->labelMapper->findAll($id);
$board->setLabels($labels);
}
// Add acl
$acl = $this->aclMapper->findAll($id);
$board->setAcl($acl);
return $board;
}
// Add acl
if ($withAcl) {
$acl = $this->aclMapper->findAll($id);
$board->setAcl($acl);
}
/**
* Find all boards for a given user
* @param $userId
* @param null $limit
* @param null $offset
* @return array
*/
public function findAllByUser($userId, $limit=null, $offset=null) {
$sql = 'SELECT id, title, owner, color, archived, 0 as shared FROM oc_deck_boards WHERE owner = ? UNION ' .
'SELECT boards.id, title, owner, color, archived, 1 as shared FROM oc_deck_boards as boards ' .
'JOIN oc_deck_board_acl as acl ON boards.id=acl.board_id WHERE acl.participant=? AND acl.type=\'user\' AND boards.owner != ?';
$entries = $this->findEntities($sql, [$userId, $userId, $userId], $limit, $offset);
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
return $board;
}
/**
* Find all boards for a given user
*
* @param $userId
* @param null $limit
* @param null $offset
* @return array
*/
public function findAllByUser($userId, $limit = null, $offset = null) {
$sql = 'SELECT id, title, owner, color, archived, 0 as shared FROM oc_deck_boards WHERE owner = ? UNION ' .
'SELECT boards.id, title, owner, color, archived, 1 as shared FROM oc_deck_boards as boards ' .
'JOIN oc_deck_board_acl as acl ON boards.id=acl.board_id WHERE acl.participant=? AND acl.type=\'user\' AND boards.owner != ?';
$entries = $this->findEntities($sql, [$userId, $userId, $userId], $limit, $offset);
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
/**
* Find all boards for a given user
@@ -91,31 +96,31 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
* @param null $offset
* @return array
*/
public function findAllByGroups($userId, $groups, $limit=null, $offset=null) {
if(count($groups)<=0) {
return [];
}
$sql = 'SELECT boards.id, title, owner, color, archived, 2 as shared FROM oc_deck_boards as boards ' .
'INNER JOIN oc_deck_board_acl as acl ON boards.id=acl.board_id WHERE owner != ? AND type=\'group\' AND (';
for($i=0;$i<count($groups);$i++) {
public function findAllByGroups($userId, $groups, $limit = null, $offset = null) {
if (count($groups) <= 0) {
return [];
}
$sql = 'SELECT boards.id, title, owner, color, archived, 2 as shared FROM oc_deck_boards as boards ' .
'INNER JOIN oc_deck_board_acl as acl ON boards.id=acl.board_id WHERE owner != ? AND type=\'group\' AND (';
for ($i = 0; $i < count($groups); $i++) {
$sql .= 'acl.participant = ? ';
if(count($groups)>1 && $i<count($groups)-1) {
if (count($groups) > 1 && $i < count($groups) - 1) {
$sql .= ' OR ';
}
}
$sql .= ');';
$entries = $this->findEntities($sql, array_merge([$userId], $groups), $limit, $offset);
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
$sql .= ');';
$entries = $this->findEntities($sql, array_merge([$userId], $groups), $limit, $offset);
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
public function delete(/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
public function delete(/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
\OCP\AppFramework\Db\Entity $entity) {
// delete acl
// delete acl
$acl = $this->aclMapper->findAll($entity->getId());
foreach ($acl as $item) {
$this->aclMapper->delete($item);
@@ -132,17 +137,17 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
$this->labelMapper->delete($label);
}
return parent::delete($entity);
}
return parent::delete($entity);
}
public function isOwner($userId, $boardId) {
$board = $this->find($boardId);
return ($board->getOwner() === $userId);
}
public function isOwner($userId, $boardId) {
$board = $this->find($boardId);
return ($board->getOwner() === $userId);
}
public function findBoardId($id) {
return $id;
}
public function findBoardId($id) {
return $id;
}
}

View File

@@ -33,7 +33,8 @@ use OCA\Deck\Db\AclMapper;
use OCA\Deck\NoPermissionException;
use OCA\Deck\NotFoundException;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\PermissionService;
use OCA\Deck\StatusException;
use \OCP\AppFramework\Middleware;
use OCP\IContainer;
use OCP\IGroupManager;
@@ -50,9 +51,7 @@ class SharingMiddleware extends Middleware {
private $request;
private $userSession;
private $reflector;
private $groupManager;
private $aclMapper;
private $boardService;
private $permissionService;
public function __construct(
@@ -60,17 +59,12 @@ class SharingMiddleware extends Middleware {
IRequest $request,
IUserSession $userSession,
ControllerMethodReflector $reflector,
IGroupManager $groupManager,
AclMapper $aclMapper,
BoardService $boardService
) {
PermissionService $permissionService) {
$this->container = $container;
$this->request = $request;
$this->userSession = $userSession;
$this->reflector = $reflector;
$this->aclMapper = $aclMapper;
$this->groupManager = $groupManager;
$this->boardService = $boardService;
$this->permissionService = $permissionService;
}
/**
@@ -91,7 +85,6 @@ class SharingMiddleware extends Middleware {
* @throws NoPermissionException
*/
public function beforeController($controller, $methodName) {
$userId = null;
if ($this->userSession->getUser()) {
$userId = $this->userSession->getUser()->getUID();
@@ -99,7 +92,25 @@ class SharingMiddleware extends Middleware {
$method = $this->request->getMethod();
$params = $this->request->getParams();
$this->checkPermissions($userId, $controller, $method, $params, $methodName);
}
/**
* Return JSON error response if the user has no sufficient permission
*
* @param \OCP\AppFramework\Controller $controller
* @param string $methodName
* @param \Exception $exception
* @return JSONResponse
* @throws \Exception
*/
public function afterException($controller, $methodName, \Exception $exception) {
if ($exception instanceof StatusException) {
return new JSONResponse([
"status" => $exception->getStatus(),
"message" => $exception->getMessage()
], $exception->getStatus());
}
throw $exception;
}
/**
@@ -117,8 +128,7 @@ class SharingMiddleware extends Middleware {
private function checkPermissions($userId, $controller, $method, $params, $methodName) {
// no permission checks needed for plain html page or RequireNoPermission
if (
$controller instanceof PageController ||
if ($controller instanceof PageController ||
$this->reflector->hasAnnotation('RequireNoPermission')
) {
return true;
@@ -167,23 +177,28 @@ class SharingMiddleware extends Middleware {
throw new \Exception("No mappers specified for permission checks");
}
$boardId = $mapper->findBoardId($id);
if(!$boardId) {
throw new NotFoundException("Entity not found");
}
if ($this->reflector->hasAnnotation('RequireReadPermission')) {
if (!$this->checkMapperPermission(Acl::PERMISSION_READ, $userId, $mapper, $id)) {
if (!$this->permissionService->getPermission($boardId, Acl::PERMISSION_READ)) {
throw new NoPermissionException("User " . $userId . " has no permission to read.", $controller, $methodName);
}
}
if ($this->reflector->hasAnnotation('RequireEditPermission')) {
if (!$this->checkMapperPermission(Acl::PERMISSION_EDIT, $userId, $mapper, $id)) {
if (!$this->permissionService->getPermission($boardId, Acl::PERMISSION_EDIT)) {
throw new NoPermissionException("User " . $userId . " has no permission to edit.", $controller, $methodName);
}
}
if ($this->reflector->hasAnnotation('RequireSharePermission')) {
if (!$this->checkMapperPermission(Acl::PERMISSION_SHARE, $userId, $mapper, $id)) {
if (!$this->permissionService->getPermission($boardId, Acl::PERMISSION_SHARE)) {
throw new NoPermissionException("User " . $userId . " has no permission to share.", $controller, $methodName);
}
}
if ($this->reflector->hasAnnotation('RequireManagePermission')) {
if (!$this->checkMapperPermission(Acl::PERMISSION_MANAGE, $userId, $mapper, $id)) {
if (!$this->permissionService->getPermission($boardId, Acl::PERMISSION_MANAGE)) {
throw new NoPermissionException("User " . $userId . " has no permission to manage.", $controller, $methodName);
}
}
@@ -192,53 +207,4 @@ class SharingMiddleware extends Middleware {
}
/**
* Check if $userId is authorized for $permission on board related to $mapper with $id
*
* @param $permission
* @param $userId
* @param $mapper
* @param $id
* @return bool
* @throws NotFoundException
*/
public function checkMapperPermission($permission, $userId, $mapper, $id) {
// check if current user is owner
if ($mapper->isOwner($userId, $id)) {
return true;
}
// find related board
$boardId = $mapper->findBoardId($id);
if(!$boardId) {
throw new NotFoundException("Entity not found");
}
return $this->boardService->getPermission($boardId, $userId, $permission);
}
/**
* Return JSON error response if the user has no sufficient permission
*
* @param \OCP\AppFramework\Controller $controller
* @param string $methodName
* @param \Exception $exception
* @return JSONResponse
* @throws \Exception
*/
public function afterException($controller, $methodName, \Exception $exception) {
if (is_a($exception, '\OCA\Deck\NoPermissionException')) {
return new JSONResponse([
"status" => 401,
"message" => $exception->getMessage()
], 401);
}
if (is_a($exception, '\OCA\Deck\NotFoundException')) {
return new JSONResponse([
"status" => 404,
"message" => $exception->getMessage()
], 404);
}
throw $exception;
}
}

View File

@@ -24,7 +24,7 @@
namespace OCA\Deck;
class NoPermissionException extends \Exception {
class NoPermissionException extends StatusException {
public function __construct($message, $controller=null, $method=null) {
parent::__construct($message);
@@ -32,4 +32,8 @@ class NoPermissionException extends \Exception {
$this->message = get_class($controller) . "#" . $method . ": " . $message;
}
}
public function getStatus() {
return 403;
}
}

View File

@@ -24,9 +24,13 @@
namespace OCA\Deck;
class NotFoundException extends \Exception {
class NotFoundException extends StatusException {
public function __construct($message="") {
parent::__construct($message);
}
public function getStatus() {
return 404;
}
}

View File

@@ -68,7 +68,7 @@ class BoardService {
}
public function find($boardId) {
$board = $this->boardMapper->find($boardId);
$board = $this->boardMapper->find($boardId, true, true);
return $board;
}

View File

@@ -97,7 +97,7 @@ class CardService {
$this->cardMapper->update($card);
}
// FIXME: return reordered cards without an additional db query
//$cards = $this->cardMapper->findAll($stackId);
$cards = $this->cardMapper->findAll($stackId);
return $cards;
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Service;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\AclMapper;
use \OCA\Deck\Db\BoardMapper;
use OCP\IGroupManager;
use OCP\ILogger;
class PermissionService {
private $boardMapper;
private $aclMapper;
private $logger;
private $userId;
public function __construct(
ILogger $logger,
AclMapper $aclMapper,
BoardMapper $boardMapper,
IGroupManager $groupManager,
$userId
) {
$this->aclMapper = $aclMapper;
$this->boardMapper = $boardMapper;
$this->logger = $logger;
$this->groupManager = $groupManager;
$this->userId = $userId;
}
/**
* Get current user permissions for a board
*
* @param $boardId
* @return bool|array
*/
public function getPermissions($boardId) {
$owner = $this->userIsBoardOwner($boardId);
$acls = $this->aclMapper->findAll($boardId);
return [
Acl::PERMISSION_READ => $owner || $this->userCan($acls, Acl::PERMISSION_READ),
Acl::PERMISSION_EDIT => $owner || $this->userCan($acls, Acl::PERMISSION_READ),
Acl::PERMISSION_MANAGE => $owner || $this->userCan($acls, Acl::PERMISSION_MANAGE),
Acl::PERMISSION_SHARE => $owner || $this->userCan($acls, Acl::PERMISSION_SHARE),
];
}
/**
* Check if the current user has specified permissions on a board
*
* @param $boardId
* @param $permission
* @return bool
*/
public function getPermission($boardId, $permission) {
if ($this->userIsBoardOwner($boardId)) {
return true;
}
$acls = $this->aclMapper->findAll($boardId);
return $this->userCan($acls, $permission);
}
/**
* @param $boardId
* @return bool
*/
public function userIsBoardOwner($boardId) {
$board = $this->boardMapper->find($boardId);
if ($board && $this->userId === $board->getOwner()) {
return true;
} else {
return false;
}
}
/**
* Check if permission matches the acl rules for current user and groups
*
* @param Acl[] $acls
* @param $permission
* @return bool
*/
public function userCan($acls, $permission) {
// check for users
foreach ($acls as $acl) {
if ($acl->getType() === "user" && $acl->getParticipant() === $this->userId) {
return $acl->getPermission($permission);
}
}
// check for groups
$hasGroupPermission = false;
foreach ($acls as $acl) {
if (!$hasGroupPermission && $acl->getType() === "group" && $this->groupManager->isInGroup($this->userId, $acl->getParticipant())) {
$hasGroupPermission = $acl->getPermission($permission);
}
}
return $hasGroupPermission;
}
}

36
lib/StatusException.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
/**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck;
abstract class StatusException extends \Exception {
public function __construct($message) {
parent::__construct($message);
}
public function getStatus() {
return 500;
}
}

View File

@@ -26,14 +26,18 @@ namespace OCA\Deck\Middleware;
use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\AppFramework\Utility\SimpleContainer;
use OCA\Deck\Db\DeckMapper;
use OCA\Deck\Db\IPermissionMapper;
use OCA\Deck\NoPermissionException;
use OCA\Deck\NotFoundException;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\PermissionService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IContainer;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCA\Deck\Db\AclMapper;
@@ -44,45 +48,88 @@ class SharingMiddlewareTest extends \PHPUnit_Framework_TestCase {
private $request;
private $userSession;
private $reflector;
private $groupManager;
private $aclMapper;
private $boardService;
private $permissionService;
public function setUp() {
$this->container = new SimpleContainer();
$this->container = $this->getMockBuilder(IContainer::class)
->disableOriginalConstructor()->getMock();
$this->request = $this->getMockBuilder(IRequest::class)
->disableOriginalConstructor()->getMock();
$this->userSession = $this->getMockBuilder(IUserSession::class)
->disableOriginalConstructor()->getMock();
$this->reflector = $this->getMockBuilder(ControllerMethodReflector::class)
->disableOriginalConstructor()->getMock();
$this->groupManager = $this->getMockBuilder(IGroupManager::class)
->disableOriginalConstructor()->getMock();
$this->aclMapper = $this->getMockBuilder(AclMapper::class)
->disableOriginalConstructor()->getMock();
$this->boardService = $this->getMockBuilder(BoardService::class)
$this->reflector = new ControllerMethodReflector();
//$this->getMockBuilder(ControllerMethodReflector::class)
// ->disableOriginalConstructor()->getMock();
$this->permissionService = $this->getMockBuilder(PermissionService::class)
->disableOriginalConstructor()->getMock();
$this->sharingMiddleware = new SharingMiddleware(
$this->container,
$this->request,
$this->userSession,
$this->reflector,
$this->groupManager,
$this->aclMapper,
$this->boardService
$this->permissionService
);
}
public function testBeforeController() {
$controller = $this->getMockBuilder(Controller::class)
public function dataBeforeController() {
return [
['GET', '\OCA\Deck\Controller\PageController', 'index', null, true],
['GET', '\OCA\Deck\Controller\BoardController', 'index', null, true],
['GET', '\OCA\Deck\Controller\BoardController', 'read', true, true],
['GET', '\OCA\Deck\Controller\BoardController', 'read', false, true, NoPermissionException::class],
['GET', '\OCA\Deck\Controller\CardController', 'read', false, true, NoPermissionException::class],
['POST', '\OCA\Deck\Controller\CardController', 'reorder', false, true, NoPermissionException::class],
];
}
/**
* @dataProvider dataBeforeController
* @param $controllerClass
* @param $methodName
*/
public function testBeforeController($method, $controllerClass, $methodName, $getPermission, $success, $exception=null) {
$controller = $this->getMockBuilder($controllerClass)
->disableOriginalConstructor()->getMock();
$methodName = '';
$mapper = $this->getMockBuilder(IPermissionMapper::class)
->disableOriginalConstructor()->getMock();
$mapper->expects($this->any())->method('findBoardId')->willReturn(123);
$mapper->expects($this->any())->method('isOwner')->willReturn(false);
$user = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()->getMock();
$user->expects($this->once())->method('getUID')->willReturn('user1');
$this->reflector->reflect($controller, $methodName);
$this->container->expects($this->any())
->method('query')->willReturn($mapper);
$this->userSession->expects($this->exactly(2))->method('getUser')->willReturn($user);
$this->request->expects($this->once())->method('getMethod')->willReturn($method);
if($getPermission) {
$this->permissionService->expects($this->any())->method('getPermission')->willReturn($getPermission);
}
if($success) {
$this->sharingMiddleware->beforeController($controller, $methodName);
} else {
try {
$this->sharingMiddleware->beforeController($controller, $methodName);
} catch (\Exception $e) {
$this->assertInstanceOf($exception, $e);
}
}
}
public function setUpPermissions() {
$this->permissionService->expects($this->once())
->method('getPermission')
->with(123, Acl::PERMISSION_READ)
->willReturn(true);
}
public function dataAfterException() {
return [
[new NoPermissionException('No permission'), 401, 'No permission'],
[new NoPermissionException('No permission'), 403, 'No permission'],
[new NotFoundException('Not found'), 404, 'Not found']
];
}
@@ -96,7 +143,14 @@ class SharingMiddlewareTest extends \PHPUnit_Framework_TestCase {
"message" => $message
], $status);
$this->assertEquals($expected, $result);
}
public function testAfterExceptionFail() {
try {
$result = $this->sharingMiddleware->afterException('Foo', 'bar', new \Exception('failed hard'));
} catch (\Exception $e) {
$this->assertEquals('failed hard', $e->getMessage());
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Service;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCP\IGroupManager;
use OCP\ILogger;
use PHPUnit_Framework_TestCase;
class PermissionServiceTest extends \PHPUnit_Framework_TestCase {
private $service;
private $logger;
private $aclMapper;
private $boardMapper;
private $groupManager;
private $userId = 'admin';
public function setUp() {
$this->logger = $this->request = $this->getMockBuilder(ILogger::class)
->disableOriginalConstructor()
->getMock();
$this->aclMapper = $this->getMockBuilder(AclMapper::class)
->disableOriginalConstructor()->getMock();
$this->boardMapper = $this->getMockBuilder(BoardMapper::class)
->disableOriginalConstructor()->getMock();
$this->groupManager = $this->getMockBuilder(IGroupManager::class)
->disableOriginalConstructor()->getMock();
$this->service = new PermissionService(
$this->logger,
$this->aclMapper,
$this->boardMapper,
$this->groupManager,
'admin'
);
}
public function testGetPermissionsOwner() {
$board = new Board();
$board->setOwner('admin');
$this->boardMapper->expects($this->once())->method('find')->with(123)->willReturn($board);
$this->aclMapper->expects($this->once())
->method('findAll')
->willReturn(null);
$expected = [
Acl::PERMISSION_READ => true,
Acl::PERMISSION_EDIT => true,
Acl::PERMISSION_MANAGE => true,
Acl::PERMISSION_SHARE => true,
];
$this->assertEquals($expected, $this->service->getPermissions(123));
}
public function testGetPermissionsAcl() {
$board = new Board();
$board->setOwner('admin');
$this->boardMapper->expects($this->once())->method('find')->with(123)->willReturn($board);
$aclUser = new Acl();
$aclUser->setType('user');
$aclUser->setParticipant('admin');
$aclUser->setPermissionWrite(true);
$aclUser->setPermissionInvite(true);
$aclUser->setPermissionManage(true);
$this->aclMapper->expects($this->once())
->method('findAll')
->willReturn([$aclUser]);
$expected = [
Acl::PERMISSION_READ => true,
Acl::PERMISSION_EDIT => true,
Acl::PERMISSION_MANAGE => true,
Acl::PERMISSION_SHARE => true,
];
$this->assertEquals($expected, $this->service->getPermissions(123));
}
public function testGetPermissionsAclNo() {
$board = new Board();
$board->setOwner('user1');
$this->boardMapper->expects($this->once())->method('find')->with(123)->willReturn($board);
$this->aclMapper->expects($this->once())
->method('findAll')
->willReturn([]);
$expected = [
Acl::PERMISSION_READ => false,
Acl::PERMISSION_EDIT => false,
Acl::PERMISSION_MANAGE => false,
Acl::PERMISSION_SHARE => false,
];
$this->assertEquals($expected, $this->service->getPermissions(123));
}
public function testGetPermission() {
$board = new Board();
$board->setOwner('admin');
$this->boardMapper->expects($this->exactly(4))->method('find')->with(123)->willReturn($board);
$this->assertEquals(true, $this->service->getPermission(123, Acl::PERMISSION_READ));
$this->assertEquals(true, $this->service->getPermission(123, Acl::PERMISSION_EDIT));
$this->assertEquals(true, $this->service->getPermission(123, Acl::PERMISSION_MANAGE));
$this->assertEquals(true, $this->service->getPermission(123, Acl::PERMISSION_SHARE));
}
public function testGetPermissionFail() {
$board = new Board();
$board->setOwner('user1');
$this->boardMapper->expects($this->exactly(4))->method('find')->with(234)->willReturn($board);
$this->aclMapper->expects($this->exactly(4))->method('findAll')->willReturn([]);
$this->assertEquals(false, $this->service->getPermission(234, Acl::PERMISSION_READ));
$this->assertEquals(false, $this->service->getPermission(234, Acl::PERMISSION_EDIT));
$this->assertEquals(false, $this->service->getPermission(234, Acl::PERMISSION_MANAGE));
$this->assertEquals(false, $this->service->getPermission(234, Acl::PERMISSION_SHARE));
}
public function testUserIsBoardOwner() {
$board = new Board();
$board->setOwner('admin');
$this->boardMapper->expects($this->at(0))->method('find')->with(123)->willReturn($board);
$this->assertEquals(true, $this->service->userIsBoardOwner(123));
$board = new Board();
$board->setOwner('user1');
$this->boardMapper->expects($this->at(0))->method('find')->with(234)->willReturn($board);
$this->assertEquals(false, $this->service->userIsBoardOwner(234));
}
public function testUserIsBoardOwnerNull() {
$this->boardMapper->expects($this->once())->method('find')->willReturn(null);
$this->assertEquals(false, $this->service->userIsBoardOwner(123));
}
public function dataTestUserCan() {
return [
// participant permissions type
['admin', false, false, false, 'user', true, false, false, false],
['admin', true, false, false, 'user', true, true, false, false],
['admin', true, true, false, 'user', true, true, true, false],
['admin', true, true, false, 'user', true, true, true, false],
['admin', true, true, true, 'user', true, true, true, true],
['user1', false, false, false, 'user', false, false, false, false]
];
}
/** @dataProvider dataTestUserCan */
public function testUserCan($participant, $edit, $share, $manage, $type, $canRead, $canEdit, $canShare, $canManage) {
$aclUser = new Acl();
$aclUser->setType($type);
$aclUser->setParticipant($participant);
$aclUser->setPermissionWrite($edit);
$aclUser->setPermissionInvite($share);
$aclUser->setPermissionManage($manage);
$acls = [
$aclUser
];
$this->assertEquals($canRead, $this->service->userCan($acls, Acl::PERMISSION_READ));
$this->assertEquals($canEdit, $this->service->userCan($acls, Acl::PERMISSION_EDIT));
$this->assertEquals($canShare, $this->service->userCan($acls, Acl::PERMISSION_SHARE));
$this->assertEquals($canManage, $this->service->userCan($acls, Acl::PERMISSION_MANAGE));
}
public function testUserCanFail() {
$this->assertFalse($this->service->userCan([], Acl::PERMISSION_EDIT));
}
}

View File

@@ -32,6 +32,7 @@ class BoardControllerTest extends \PHPUnit_Framework_TestCase {
private $userManager;
private $groupManager;
private $boardService;
private $permissionService;
private $userId = 'user';
public function setUp() {
@@ -55,6 +56,10 @@ class BoardControllerTest extends \PHPUnit_Framework_TestCase {
'\OCA\Deck\Service\BoardService')
->disableOriginalConstructor()
->getMock();
$this->permissionService = $this->getMockBuilder(
'\OCA\Deck\Service\PermissionService')
->disableOriginalConstructor()
->getMock();
$this->groupManager->method('getUserGroupIds')
->willReturn(['admin', 'group1', 'group2']);
@@ -68,6 +73,7 @@ class BoardControllerTest extends \PHPUnit_Framework_TestCase {
$this->userManager,
$this->groupManager,
$this->boardService,
$this->permissionService,
$this->userId
);
}