backoffice: refactor check of backoffice access rights (#6726)

This commit is contained in:
Frédéric Péters 2015-05-06 22:10:21 +02:00
parent 7ef5152323
commit f95e3361e8
7 changed files with 80 additions and 54 deletions

View File

@ -33,12 +33,14 @@ def pub(request):
return pub
def create_superuser(pub):
global user1
def create_user(pub, is_admin=True):
if pub.user_class.select(lambda x: x.name == 'admin'):
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
user1.is_admin = is_admin
user1.store()
return
user1 = pub.user_class(name='admin')
user1.is_admin = True
user1.is_admin = is_admin
user1.store()
account1 = PasswordAccount(id='admin')
@ -53,6 +55,7 @@ def create_superuser(pub):
user1.roles = [role.id]
user1.store()
def create_environment(set_receiver=True):
FormDef.wipe()
formdef = FormDef()
@ -100,19 +103,43 @@ def teardown_module(module):
clean_temporary_pub()
def test_backoffice_unlogged(pub):
create_superuser(pub)
create_user(pub)
resp = get_app(pub).get('/backoffice/', status=302)
resp = resp.follow()
assert resp.location == 'http://example.net/login/'
def test_backoffice_home(pub):
create_superuser(pub)
create_user(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert 'Management' in resp.body
assert 'Forms Workshop' in resp.body
assert 'Workflows Workshop' in resp.body
def test_backoffice_role_user(pub):
create_user(pub, is_admin=False)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert 'Management' in resp.body
assert not 'Forms Workshop' in resp.body
assert not 'Workflows Workshop' in resp.body
pub.cfg['admin-permissions'] = {'forms': [x.id for x in Role.select()]}
pub.write_cfg()
resp = app.get('/backoffice/')
assert 'Management' in resp.body
assert 'Forms Workshop' in resp.body
assert not 'Workflows Workshop' in resp.body
pub.cfg['admin-permissions'] = {'workflows': [x.id for x in Role.select()]}
pub.write_cfg()
resp = app.get('/backoffice/')
assert 'Management' in resp.body
assert not 'Forms Workshop' in resp.body
assert 'Workflows Workshop' in resp.body
def test_backoffice_forms(pub):
create_superuser(pub)
create_user(pub)
create_environment(set_receiver=False)
# 1st time with user not handling those forms
@ -131,7 +158,7 @@ def test_backoffice_forms(pub):
assert '17 open on 50' in resp.body
def test_backoffice_listing(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -159,7 +186,7 @@ def test_backoffice_listing(pub):
assert resp.body.count('data-link') == 33
def test_backoffice_columns(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -171,7 +198,7 @@ def test_backoffice_columns(pub):
assert resp.body.count('FOO BAR') == 0 # no field 1 column
def test_backoffice_filter(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -197,7 +224,7 @@ def test_backoffice_filter(pub):
assert resp.body.count('<td>baz</td>') == 8
def test_backoffice_csv(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -212,7 +239,7 @@ def test_backoffice_csv(pub):
assert len(resp.body.splitlines()) == 51
def test_backoffice_ods(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -222,7 +249,7 @@ def test_backoffice_ods(pub):
assert resp.body[:2] == 'PK' # ods has a zip container
def test_backoffice_statistics(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -240,7 +267,7 @@ def test_backoffice_statistics(pub):
assert 'Total number of records: 0' in resp.body
def test_backoffice_statistics_status_filter(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -270,7 +297,7 @@ def test_backoffice_statistics_status_filter(pub):
assert 'Total number of records: 50' in resp.body
def test_backoffice_statistics_status_select(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
@ -291,7 +318,7 @@ def test_backoffice_statistics_status_select(pub):
assert 'Total number of records: 13' in resp.body
def test_backoffice_handling(pub):
create_superuser(pub)
create_user(pub)
create_environment()
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id
@ -306,7 +333,7 @@ def test_backoffice_handling(pub):
assert 'HELLO WORLD' in resp.body
def test_global_statisticspub(pub):
create_superuser(pub)
create_user(pub)
create_environment()
app = login(get_app(pub))
resp = app.get('/backoffice/')

View File

@ -32,7 +32,6 @@ from qommon.afterjobs import AfterJob
from qommon import errors
from qommon import ods
from qommon.form import *
from qommon.admin.menu import is_accessible
from qommon.storage import Equal, NotEqual, LessOrEqual, GreaterOrEqual, Or
from wcs.forms.common import FormStatusPage
@ -239,6 +238,38 @@ class RootDirectory(BackofficeRootDirectory):
('/', N_('WCS Form Server'))
]
def _q_traverse(self, path):
get_response().add_javascript(['jquery.js'])
return super(RootDirectory, self)._q_traverse(path)
@classmethod
def is_accessible(cls, subdirectory):
# check a backoffice directory is accessible to the current user
if not get_request().user:
if get_publisher().user_class.count() == 0:
# setting up the site, access is granted to settings and users
# sections
return subdirectory in ('settings', 'users')
if getattr(get_response(), 'filter', {}) and get_response().filter.get('admin_for_all'):
# if admin for all is set, access is granted to everything
return True
return False
user_roles = set(get_request().user.roles or [])
authorised_roles = set(get_cfg('admin-permissions', {}).get(subdirectory) or [])
if authorised_roles:
# access is governed by roles set in the settings panel
return user_roles.intersection(authorised_roles)
# for some subdirectories, the user needs to be part of a role allowed
# to go in the backoffice
if subdirectory in ('management',):
return get_request().user.can_go_in_backoffice()
# for the other directories, an extra level is required, the user needs
# to be marked as admin
return get_request().user.can_go_in_admin()
def _q_access(self):
get_response().breadcrumb.append( ('backoffice/', _('Back Office')) )
req = get_request()
@ -519,7 +550,7 @@ class RootDirectory(BackofficeRootDirectory):
def _q_lookup(self, component):
if component in [str(x[0]).strip('/') for x in self.menu_items]:
if not is_accessible(component):
if not self.is_accessible(component):
raise errors.AccessForbiddenError()
return getattr(self, component)
return FormPage(component)
@ -541,7 +572,7 @@ class RootDirectory(BackofficeRootDirectory):
continue
if display_function and not display_function(slug):
continue
if not is_accessible(slug):
if not self.is_accessible(slug):
continue
if callable(v):
label = v()

View File

@ -153,13 +153,12 @@ class Category(XmlStorableObject):
return '%s/%s/' % (base_url, self.url_name)
def get_description_html_text(self, editable=True):
from qommon.admin.menu import is_accessible
if not self.description:
return None
text = self.description
if text[0] != '<':
text = '<p>%s</p>' % text
if editable and is_accessible('categories'):
if editable and get_publisher().get_backoffice_root().is_accessible('categories'):
root_url = get_publisher().get_root_url()
get_response().add_javascript(['jquery.js', 'jquery-ui.js',
'ckeditor/ckeditor.js', 'qommon.wysiwyg.js',

View File

@ -17,7 +17,6 @@
from quixote import get_publisher, get_response, get_request, get_session
from quixote.html import TemplateIO, htmltext
from qommon.misc import is_user_admin
from qommon import get_cfg
import re
@ -179,18 +178,3 @@ def error_page(section, error):
r += htmltext('<a href="%s">%s</a>') % (get_request().get_url(), _('Back'))
r += htmltext('</div>')
return r.getvalue()
def is_accessible(key):
if not get_request().user:
if get_publisher().user_class.count() == 0:
return key in ('settings', 'users')
if getattr(get_response(), 'filter', {}) and get_response().filter.get('admin_for_all'):
return True
return False
user_roles = set(get_request().user.roles or [])
authorised_roles = set(get_cfg('admin-permissions', {}).get(key) or [])
if not authorised_roles:
return is_user_admin()
return user_roles.intersection(authorised_roles)

View File

@ -24,7 +24,6 @@ from quixote.directory import Directory
from qommon.form import *
from qommon import misc, get_cfg, ezt
from qommon.backoffice.menu import html_top
from qommon.admin.menu import is_accessible
class TextsDirectory(Directory):
@ -56,7 +55,8 @@ class TextsDirectory(Directory):
text_template.generate(fd, subst_vars)
text = fd.getvalue()
if is_accessible('settings'):
if get_publisher().get_backoffice_root() and \
get_publisher().get_backoffice_root().is_accessible('settings'):
root_url = get_publisher().get_root_url()
get_response().add_javascript(['jquery.js', 'jquery-ui.js',
'ckeditor/ckeditor.js', 'qommon.wysiwyg.js',

View File

@ -17,7 +17,6 @@
from quixote import get_response, get_request, get_publisher, get_session
from qommon import get_cfg
from qommon.misc import is_user_admin
from quixote.html import htmltext, TemplateIO
def generate_header_menu(selected = None):

View File

@ -271,20 +271,6 @@ def http_get_page(url, headers={}, timeout=None):
def http_post_request(url, body=None, headers={}, timeout=None):
return _http_request(url, 'POST', body, headers, timeout=timeout)
def is_user_admin():
session = get_session()
if not session:
return False
user = session.get_user_object()
if not user:
return False
if callable(user.is_admin):
if user.is_admin():
return True
elif user.is_admin:
return True
return False
def get_variadic_url(url, variables, encode_query=True):
# substitution in an URL : try to be safe