api: allow http basic auth access to /api/forms/ (#53882)

This commit is contained in:
Frédéric Péters 2021-05-10 19:21:29 +02:00
parent e05865b1cd
commit d029e24e4c
2 changed files with 56 additions and 18 deletions

View File

@ -788,8 +788,8 @@ def test_api_anonymized_formdata(pub, local_user, admin_user):
assert 'name' in resp.json['evolution'][1]['who']
@pytest.mark.parametrize('http_basic_auth', [False, True])
def test_api_access_restrict_to_anonymised_data(pub, local_user, http_basic_auth):
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
def test_api_access_restrict_to_anonymised_data(pub, local_user, auth):
pub.role_class.wipe()
role = pub.role_class(name='test')
role.store()
@ -826,7 +826,7 @@ def test_api_access_restrict_to_anonymised_data(pub, local_user, http_basic_auth
app = get_app(pub)
if http_basic_auth:
if auth == 'http-basic':
# there's not "defaults to admin" permissions in case of basic authentication.
access.roles = [role]
access.store()
@ -866,7 +866,7 @@ def test_api_access_restrict_to_anonymised_data(pub, local_user, http_basic_auth
resp = get_url('/api/forms/test/%s/' % formdata.id)
assert 'user' not in resp.json
if http_basic_auth:
if auth == 'http-basic':
# for basic HTTP authentication, check there's no access if roles are not given.
access.roles = []
access.store()
@ -1101,7 +1101,9 @@ def test_api_global_geojson(pub, local_user):
assert len(resp.json['features']) == 20
def test_api_global_listing(pub, local_user):
@pytest.mark.parametrize('user', ['query-email', 'api-access'])
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
def test_api_global_listing(pub, local_user, user, auth):
if not pub.is_using_postgresql():
resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
pytest.skip('this requires SQL')
@ -1111,8 +1113,35 @@ def test_api_global_listing(pub, local_user):
role = pub.role_class(name='test')
role.store()
app = get_app(pub)
if user == 'api-access':
access = ApiAccess()
access.name = 'test'
access.access_identifier = 'test'
access.access_key = '12345'
access.store()
if auth == 'http-basic':
def get_url(url, **kwargs):
app.set_authorization(('Basic', ('test', '12345')))
return app.get(url, **kwargs)
else:
def get_url(url, **kwargs):
return app.get(sign_uri(url, orig=access.access_identifier, key=access.access_key), **kwargs)
else:
if auth == 'http-basic':
pytest.skip('http basic authentication requires ApiAccess')
def get_url(url, **kwargs):
return app.get(sign_uri(url, user=local_user), **kwargs)
# check there's no crash if there are no formdefs
resp = get_app(pub).get(sign_uri('/api/forms/', user=local_user))
resp = get_url('/api/forms/')
assert len(resp.json['data']) == 0
FormDef.wipe()
@ -1141,38 +1170,42 @@ def test_api_global_listing(pub, local_user):
formdata.store()
# check empty content if user doesn't have the appropriate role
resp = get_app(pub).get(sign_uri('/api/forms/', user=local_user))
resp = get_url('/api/forms/')
assert len(resp.json['data']) == 0
# add proper role to user
local_user.roles = [role.id]
local_user.store()
if user == 'api-access':
access.roles = [role]
access.store()
else:
local_user.roles = [role.id]
local_user.store()
# check it gets the data
resp = get_app(pub).get(sign_uri('/api/forms/', user=local_user))
resp = get_url('/api/forms/')
assert len(resp.json['data']) == 10
# check with a filter
resp = get_app(pub).get(sign_uri('/api/forms/?status=done', user=local_user))
resp = get_url('/api/forms/?status=done')
assert len(resp.json['data']) == 20
# check limit/offset
resp = get_app(pub).get(sign_uri('/api/forms/?status=done&limit=5', user=local_user))
resp = get_url('/api/forms/?status=done&limit=5')
assert len(resp.json['data']) == 5
resp = get_app(pub).get(sign_uri('/api/forms/?status=done&offset=5&limit=5', user=local_user))
resp = get_url('/api/forms/?status=done&offset=5&limit=5')
assert len(resp.json['data']) == 5
resp = get_app(pub).get(sign_uri('/api/forms/?status=done&offset=18&limit=5', user=local_user))
resp = get_url('/api/forms/?status=done&offset=18&limit=5')
assert len(resp.json['data']) == 2
# check error handling
get_app(pub).get(sign_uri('/api/forms/?status=done&limit=plop', user=local_user), status=400)
get_app(pub).get(sign_uri('/api/forms/?status=done&offset=plop', user=local_user), status=400)
get_url('/api/forms/?status=done&limit=plop', status=400)
get_url('/api/forms/?status=done&offset=plop', status=400)
# check when there are missing statuses
for formdata in data_class.select():
formdata.status = 'wf-missing'
formdata.store()
resp = get_app(pub).get(sign_uri('/api/forms/?status=all', user=local_user))
resp = get_url('/api/forms/?status=all')
assert resp.json['data'][0]['status'] is None
assert 'unknown' in resp.json['data'][0]['title']
@ -1250,7 +1283,7 @@ def test_api_global_listing_categories_filter(pub, local_user):
def test_api_global_listing_ignored_roles(pub, local_user):
test_api_global_listing(pub, local_user)
test_api_global_listing(pub, local_user, user='query-email', auth='signature')
role = pub.role_class(name='test2')
role.store()

View File

@ -368,6 +368,11 @@ class ApiFormsDirectory(Directory):
def check_access(self):
if not is_url_signed():
api_user = get_user_from_api_query_string()
if api_user and api_user.is_api_user:
# API users are ok
return
# grant access to admins, to ease debug
if not (get_request().user and get_request().user.is_admin):
raise AccessForbiddenError('user not authenticated')