From bbeb73044790b8983c7735ab671580b29676674b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 10 Jan 2017 10:52:40 +0100 Subject: [PATCH] general: allow marking form as required a given authentication context (#13177) --- tests/test_admin_pages.py | 34 ++++++++++++++++++++++++++++++++++ tests/test_api.py | 5 +++++ tests/test_form_pages.py | 37 +++++++++++++++++++++++++++++++++++-- tests/test_formdef_import.py | 8 ++++++++ wcs/admin/forms.py | 20 +++++++++++++++++++- wcs/api.py | 2 ++ wcs/backoffice/submission.py | 3 +++ wcs/formdef.py | 19 +++++++++++++++++++ wcs/forms/root.py | 28 +++++++++++++++++++++++++++- wcs/qommon/publisher.py | 28 ++++++++++++++++++++++++++++ wcs/qommon/sessions.py | 7 +++++++ 11 files changed, 187 insertions(+), 4 deletions(-) diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py index 69c66ffc..1af69861 100644 --- a/tests/test_admin_pages.py +++ b/tests/test_admin_pages.py @@ -477,6 +477,40 @@ def test_form_workflow_remapping(pub): assert data_class.get(formdata1.id).status == 'wf-finished' assert data_class.get(formdata2.id).status == 'draft' +def test_form_submitter_roles(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href=re.compile('^roles$')) + resp.form['roles$element0'] = 'logged-users' + assert not 'required_authentication_contexts' in resp.body + resp = resp.form.submit() + assert FormDef.get(formdef.id).roles == ['logged-users'] + + # add auth contexts support + if not pub.site_options.has_section('options'): + pub.site_options.add_section('options') + pub.site_options.set('options', 'auth-contexts', 'fedict') + with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: + pub.site_options.write(fd) + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href=re.compile('^roles$')) + assert 'required_authentication_contexts' in resp.body + resp.form['required_authentication_contexts$element0'].checked = True + resp = resp.form.submit() + resp = resp.follow() + assert FormDef.get(formdef.id).required_authentication_contexts == ['fedict'] + def test_form_workflow_role(pub): create_superuser(pub) role = create_role() diff --git a/tests/test_api.py b/tests/test_api.py index d90b5b0b..0718fa70 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -335,6 +335,11 @@ def test_limited_formdef_list(pub, local_user): assert resp.json[0]['authentication_required'] assert resp.json == resp2.json == resp3.json == resp4.json + formdef.required_authentication_contexts = ['fedict'] + formdef.store() + resp = get_app(pub).get('/api/formdefs/') + assert resp.json[0]['required_authentication_contexts'] == ['fedict'] + def test_formdef_list_redirection(pub): FormDef.wipe() formdef = FormDef() diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py index 226cde89..95765838 100644 --- a/tests/test_form_pages.py +++ b/tests/test_form_pages.py @@ -325,10 +325,10 @@ def test_form_access(pub): login(get_app(pub), username='foo', password='foo').get('/test/', status=200) # check special "logged users" role - formdef.roles = [logged_users_role()] + formdef.roles = [logged_users_role().id] formdef.store() user = create_user(pub) - login(get_app(pub), username='foo', password='foo').get('/test/', status=403) + login(get_app(pub), username='foo', password='foo').get('/test/', status=200) resp = get_app(pub).get('/test/', status=302) # redirect to login # check "receiver" can also access the formdef @@ -341,6 +341,39 @@ def test_form_access(pub): user.store() login(get_app(pub), username='foo', password='foo').get('/test/', status=200) +def test_form_access_auth_context(pub): + user = create_user(pub) + + if not pub.site_options.has_section('options'): + pub.site_options.add_section('options') + pub.site_options.set('options', 'auth-contexts', 'fedict') + with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: + pub.site_options.write(fd) + + formdef = create_formdef() + get_app(pub).get('/test/', status=200) + + formdef.required_authentication_contexts = ['fedict'] + formdef.roles = [logged_users_role().id] + formdef.store() + + # an unlogged user will get a redirect to login + resp = get_app(pub).get('/test/', status=302) + assert '/login' in resp.location + + # a user logged in with a simple username/password tuple will get a page + # to relogin with a stronger auth + app = login(get_app(pub), username='foo', password='foo') + resp = app.get('/test/') + assert 'You need a stronger authentication level to fill this form.' in resp.body + + for session in pub.session_manager.values(): + session.saml_authn_context = 'urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI' + session.store() + resp = app.get('/test/') + assert 'You need a stronger authentication level to fill this form.' not in resp.body + assert resp.form + def test_form_submit(pub): formdef = create_formdef() formdef.data_class().wipe() diff --git a/tests/test_formdef_import.py b/tests/test_formdef_import.py index e66cfb5d..0e5cb0d0 100644 --- a/tests/test_formdef_import.py +++ b/tests/test_formdef_import.py @@ -408,3 +408,11 @@ def test_backoffice_submission_roles(): formdef.backoffice_submission_roles = [role.id] fd2 = assert_xml_import_export_works(formdef, include_id=True) assert fd2.backoffice_submission_roles == formdef.backoffice_submission_roles + +def test_required_authentication_contexts(): + formdef = FormDef() + formdef.name = 'foo' + formdef.fields = [] + formdef.required_authentication_contexts = ['fedict'] + fd2 = assert_xml_import_export_works(formdef, include_id=True) + assert fd2.required_authentication_contexts == formdef.required_authentication_contexts diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py index 0e925ff9..d28251d7 100644 --- a/wcs/admin/forms.py +++ b/wcs/admin/forms.py @@ -430,7 +430,7 @@ class FormDefPage(Directory): wf_role_label, role_label) r += add_option_line('roles', _('User Roles'), - self._get_roles_label('roles')) + self._get_roles_label_and_auth_context('roles')) r += add_option_line('backoffice-submission-roles', _('Backoffice Submission Role'), self._get_roles_label('backoffice_submission_roles')) @@ -525,6 +525,15 @@ class FormDefPage(Directory): value = C_('roles|None') return value + def _get_roles_label_and_auth_context(self, attribute): + value = self._get_roles_label(attribute) + if self.formdef.required_authentication_contexts: + auth_contexts = get_publisher().get_supported_authentication_contexts() + value += ' (%s)' % ', '.join([auth_contexts.get(x) + for x in self.formdef.required_authentication_contexts + if auth_contexts.get(x)]) + return value + def get_sidebar(self): r = TemplateIO(html=True) r += htmltext('