misc: limit cancel URL to relatable URLs (#43276)

This commit is contained in:
Frédéric Péters 2020-05-25 18:12:54 +02:00
parent 05c1573e38
commit c3795921c3
3 changed files with 61 additions and 0 deletions

View File

@ -428,6 +428,47 @@ def test_form_access_auth_context(pub):
assert resp.form
def test_form_cancelurl(pub):
formdef = create_formdef()
formdef.data_class().wipe()
# path
resp = get_app(pub).get('/test/?cancelurl=/plop/')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.net/plop/'
# full URL
resp = get_app(pub).get('/test/?cancelurl=http://example.net/plop/')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.net/plop/'
# remote site
get_app(pub).get('/test/?cancelurl=http://example.org/plop/', status=400)
pub.site_options.add_section('api-secrets')
pub.site_options.set('api-secrets', 'example.org', 'xyz')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
resp = get_app(pub).get('/test/?cancelurl=http://example.org/plop/')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.org/plop/'
pub.site_options.remove_section('api-secrets')
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
get_app(pub).get('/test/?cancelurl=http://example.org/plop/', status=400)
pub.site_options.set('options', 'relatable-hosts', 'example.com')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
get_app(pub).get('/test/?cancelurl=http://example.org/plop/', status=400)
pub.site_options.set('options', 'relatable-hosts', 'example.com, example.org')
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
resp = get_app(pub).get('/test/?cancelurl=http://example.org/plop/')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.org/plop/'
def test_form_submit(pub):
formdef = create_formdef()
formdef.data_class().wipe()

View File

@ -328,6 +328,8 @@ class FormPage(Directory, FormTemplateMixin):
if page == self.pages[0] and 'cancelurl' in get_request().form:
cancelurl = get_request().form['cancelurl']
if not get_publisher().is_relatable_url(cancelurl):
raise errors.RequestError('invalid cancel URL')
form_data['__cancelurl'] = cancelurl
session.add_magictoken(magictoken, form_data)

View File

@ -386,6 +386,7 @@ class QommonPublisher(Publisher, object):
defaults = {
'options': {
'unused-files-behaviour': 'remove',
'relatable-hosts': '',
},
}
if self.site_options is None:
@ -956,6 +957,23 @@ class QommonPublisher(Publisher, object):
d['manager_homepage_title'] = d.get('portal_agent_title')
return d
def is_relatable_url(self, url):
parsed_url = urllib.urlparse(url)
if not parsed_url.netloc:
return True
if parsed_url.netloc == urllib.urlparse(self.get_frontoffice_url()).netloc:
return True
if parsed_url.netloc == urllib.urlparse(self.get_backoffice_url()).netloc:
return True
if parsed_url.netloc in [x.strip() for x in self.get_site_option('relatable-hosts').split(',')]:
return True
try:
if parsed_url.netloc in self.site_options.options('api-secrets'):
return True
except ConfigParser.NoSectionError:
pass
return False
extra_sources = []
@classmethod
def register_extra_source(cls, source):