Added basic privilege system

This commit is contained in:
Marcin Kurczewski 2014-09-04 19:57:06 +02:00
parent 2ecb79a2fa
commit de31770c87
12 changed files with 77 additions and 16 deletions

View file

@ -7,6 +7,13 @@ name = booru-dev
secret = change
minPasswordLength = 5
[security.privileges]
anonymous = register, viewUser
regularUser = listUsers, viewUser
powerUser = listUsers, viewUser
moderator = listUsers, viewUser
administrator = listUsers, viewUser
[users]
minUserNameLength = 1
maxUserNameLength = 32

View file

@ -44,10 +44,8 @@ App.Auth = function(jQuery, util, api, appState, promise) {
function logout() {
return promise.make(function(resolve, reject) {
appState.set('loggedIn', false);
appState.set('loginToken', null);
jQuery.removeCookie('auth');
resolve();
return loginAnonymous().then(resolve).fail(reject);
});
};
@ -75,6 +73,7 @@ App.Auth = function(jQuery, util, api, appState, promise) {
};
function updateAppState(response) {
appState.set('privileges', response.json.privileges || []);
appState.set('loginToken', response.json.token && response.json.token.name);
appState.set('loggedInUser', response.json.user);
appState.set('loggedIn', response.json.user && !!response.json.user.id);

View file

@ -9,6 +9,7 @@ App.Presenters.PagedCollectionPresenter = function(util, promise, api) {
var baseUri;
var backendUri;
var renderCallback;
var failCallback;
var template;
var pageSize;
@ -19,11 +20,10 @@ App.Presenters.PagedCollectionPresenter = function(util, promise, api) {
baseUri = args.baseUri;
backendUri = args.backendUri;
renderCallback = args.renderCallback;
failCallback = args.failCallback;
promise.wait(util.promiseTemplate('pager')).then(function(html) {
template = _.template(html);
//renderCallback({entities: [], totalRecords: 0});
changePage(pageNumber);
});
}
@ -44,7 +44,11 @@ App.Presenters.PagedCollectionPresenter = function(util, promise, api) {
entities: response.json.data,
totalRecords: response.json.totalRecords});
}).fail(function(response) {
if (typeof(failCallback) !== 'undefined') {
failCallback(response);
} else {
console.log(Error(response.json && response.json.error || response));
}
});
}

View file

@ -33,6 +33,7 @@ App.Presenters.TopNavigationPresenter = function(
$el.html(template({
loggedIn: appState.get('loggedIn'),
user: appState.get('loggedInUser'),
privileges: appState.get('privileges'),
}));
$el.find('li.' + selectedElement).addClass('active');
};

View file

@ -7,7 +7,8 @@ App.Presenters.UserListPresenter = function(
promise,
router,
pagedCollectionPresenter,
topNavigationPresenter) {
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var template;
@ -28,6 +29,10 @@ App.Presenters.UserListPresenter = function(
renderCallback: function updateCollection(data) {
userList = data.entities;
render();
},
failCallback: function(response) {
$el.empty();
messagePresenter.showError($el, response.json && response.json.error || response);
}});
});
}

View file

@ -1,6 +1,6 @@
var App = App || {};
App.Router = function(jQuery, util) {
App.Router = function(jQuery, util, appState) {
var root = '#/';

View file

@ -1,8 +1,10 @@
<ul>
<!-- todo: check privileges -->
<% if (_.contains(privileges, 'listUsers')) { %>
<li class="users">
<a href="#/users">Users</a>
</li>
<% } %>
<% if (!loggedIn) { %>
<li class="login">
<a href="#/login">Login</a>

View file

@ -45,6 +45,7 @@ final class AuthController extends AbstractController
[
'token' => new \Szurubooru\ViewProxies\Token($this->authService->getLoginToken()),
'user' => new \Szurubooru\ViewProxies\User($this->authService->getLoggedInUser()),
'privileges' => $this->authService->getCurrentPrivileges(),
];
}
}

View file

@ -3,15 +3,18 @@ namespace Szurubooru\Controllers;
final class UserController extends AbstractController
{
private $inputReader;
private $authService;
private $userService;
private $inputReader;
public function __construct(
\Szurubooru\Services\AuthService $authService,
\Szurubooru\Services\UserService $userService,
\Szurubooru\Helpers\InputReader $inputReader)
{
$this->inputReader = $inputReader;
$this->authService = $authService;
$this->userService = $userService;
$this->inputReader = $inputReader;
}
public function registerRoutes(\Szurubooru\Router $router)
@ -25,7 +28,8 @@ final class UserController extends AbstractController
public function getFiltered()
{
//todo: privilege checking
$this->authService->assertPrivilege(\Szurubooru\Privilege::PRIVILEGE_LIST_USERS);
//todo: move this to form data constructor
$searchFormData = new \Szurubooru\FormData\SearchFormData;
$searchFormData->query = $this->inputReader->query;
@ -41,7 +45,8 @@ final class UserController extends AbstractController
public function getByName($name)
{
//todo: privilege checking
$this->authService->assertPrivilege(\Szurubooru\Privilege::PRIVILEGE_VIEW_USER);
$user = $this->userService->getByName($name);
if (!$user)
throw new \DomainException('User with name "' . $name . '" was not found.');
@ -50,7 +55,8 @@ final class UserController extends AbstractController
public function register()
{
//todo: privilege checking
$this->authService->assertPrivilege(\Szurubooru\Privilege::PRIVILEGE_REGISTER);
$input = new \Szurubooru\FormData\RegistrationFormData;
//todo: move this to form data constructor
$input->name = $this->inputReader->userName;

9
src/Privilege.php Normal file
View file

@ -0,0 +1,9 @@
<?php
namespace Szurubooru;
class Privilege
{
const PRIVILEGE_LIST_USERS = 'listUsers';
const PRIVILEGE_VIEW_USER = 'viewUser';
const PRIVILEGE_REGISTER = 'register';
}

View file

@ -7,6 +7,7 @@ class AuthService
private $loginToken = null;
private $validator;
private $config;
private $passwordService;
private $timeService;
private $userDao;
@ -14,6 +15,7 @@ class AuthService
public function __construct(
\Szurubooru\Validator $validator,
\Szurubooru\Config $config,
\Szurubooru\Services\PasswordService $passwordService,
\Szurubooru\Services\TimeService $timeService,
\Szurubooru\Dao\TokenDao $tokenDao,
@ -22,6 +24,7 @@ class AuthService
$this->loggedInUser = $this->getAnonymousUser();
$this->validator = $validator;
$this->config = $config;
$this->passwordService = $passwordService;
$this->timeService = $timeService;
$this->tokenDao = $tokenDao;
@ -103,6 +106,27 @@ class AuthService
$this->loginToken = null;
}
public function getCurrentPrivileges()
{
switch ($this->getLoggedInUser()->accessRank)
{
case \Szurubooru\Entities\User::ACCESS_RANK_ANONYMOUS: $keyName = 'anonymous'; break;
case \Szurubooru\Entities\User::ACCESS_RANK_REGULAR_USER: $keyName = 'regularUser'; break;
case \Szurubooru\Entities\User::ACCESS_RANK_POWER_USER: $keyName = 'powerUser'; break;
case \Szurubooru\Entities\User::ACCESS_RANK_MODERATOR: $keyName = 'moderator'; break;
case \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR: $keyName = 'administrator'; break;
default:
throw new \DomainException('Invalid access rank!');
}
return array_filter(preg_split('/[;,\s]+/', $this->config->security->privileges[$keyName]));
}
public function assertPrivilege($privilege)
{
if (!in_array($privilege, $this->getCurrentPrivileges()))
throw new \DomainException('Unprivileged operation');
}
private function createAndSaveLoginToken(\Szurubooru\Entities\User $user)
{
$loginToken = new \Szurubooru\Entities\Token();

View file

@ -4,6 +4,7 @@ namespace Szurubooru\Tests\Services;
class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
{
private $validatorMock;
private $configMock;
private $passwordServiceMock;
private $timeServiceMock;
private $tokenDaoMock;
@ -12,6 +13,7 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
public function setUp()
{
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
$this->configMock = $this->mock(\Szurubooru\Config::class);
$this->passwordServiceMock = $this->mock(\Szurubooru\Services\PasswordService::class);
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
$this->tokenDaoMock = $this->mock(\Szurubooru\Dao\TokenDao::class);
@ -94,6 +96,7 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
{
return new \Szurubooru\Services\AuthService(
$this->validatorMock,
$this->configMock,
$this->passwordServiceMock,
$this->timeServiceMock,
$this->tokenDaoMock,