0001-api-add-possibility-of-http-basic-auth-access-to-the.patch
tests/test_api.py | ||
---|---|---|
1445 | 1445 |
formdef.store() |
1446 | 1446 |
resp = get_app(pub).get(sign_uri('/api/forms/test/geojson', user=local_user), status=404) |
1447 | 1447 | |
1448 |
def test_api_ics_formdata(pub, local_user): |
|
1448 |
@pytest.fixture |
|
1449 |
def ics_data(local_user): |
|
1449 | 1450 |
Role.wipe() |
1450 | 1451 |
role = Role(name='test') |
1451 | 1452 |
role.store() |
... | ... | |
1462 | 1463 |
data_class = formdef.data_class() |
1463 | 1464 |
data_class.wipe() |
1464 | 1465 | |
1465 |
# check access is denied if the user has not the appropriate role |
|
1466 |
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar', user=local_user), status=403) |
|
1467 |
# even if there's an anonymse parameter |
|
1468 |
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar?anonymise', user=local_user), status=403) |
|
1469 | ||
1470 | 1466 |
date = datetime.datetime(2014, 1, 20, 12, 00) |
1471 | 1467 |
for i in range(30): |
1472 | 1468 |
formdata = data_class() |
... | ... | |
1479 | 1475 |
formdata.jump_status('finished') |
1480 | 1476 |
formdata.store() |
1481 | 1477 | |
1478 |
def test_api_ics_formdata(pub, local_user, ics_data): |
|
1479 |
role = Role.select()[0] |
|
1480 | ||
1481 |
# check access is denied if the user has not the appropriate role |
|
1482 |
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar', user=local_user), status=403) |
|
1483 |
# even if there's an anonymse parameter |
|
1484 |
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/foobar?anonymise', user=local_user), status=403) |
|
1485 | ||
1482 | 1486 |
# add proper role to user |
1483 | 1487 |
local_user.roles = [role.id] |
1484 | 1488 |
local_user.store() |
... | ... | |
1495 | 1499 |
# check 404 on erroneous field var |
1496 | 1500 |
resp = get_app(pub).get(sign_uri('/api/forms/test/ics/xxx', user=local_user), status=404) |
1497 | 1501 | |
1502 |
def test_api_ics_formdata_http_auth(pub, local_user, ics_data): |
|
1503 |
role = Role.select()[0] |
|
1504 | ||
1505 |
# no access |
|
1506 |
app = get_app(pub) |
|
1507 |
app.authorization = ('Basic', ('user', 'password')) |
|
1508 |
resp = app.get('/api/forms/test/ics/foobar?email=%s' % local_user.email, status=403) |
|
1509 | ||
1510 |
# add authentication info |
|
1511 |
pub.load_site_options() |
|
1512 |
pub.site_options.add_section('api-http-auth-ics') |
|
1513 |
pub.site_options.set('api-http-auth-ics', 'user', 'password') |
|
1514 |
pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w')) |
|
1515 | ||
1516 |
# check access is denied if the user has not the appropriate role |
|
1517 |
resp = app.get('/api/forms/test/ics/foobar?email=%s' % local_user.email, status=403) |
|
1518 | ||
1519 |
# add proper role to user |
|
1520 |
local_user.roles = [role.id] |
|
1521 |
local_user.store() |
|
1522 | ||
1523 |
# check it gets the data |
|
1524 |
resp = app.get('/api/forms/test/ics/foobar?email=%s' % local_user.email, status=200) |
|
1525 |
assert resp.headers['content-type'] == 'text/calendar; charset=utf-8' |
|
1526 |
assert resp.body.count('BEGIN:VEVENT') == 10 |
|
1527 | ||
1528 |
# check it fails with a different password |
|
1529 |
app.authorization = ('Basic', ('user', 'password2')) |
|
1530 |
resp = app.get('/api/forms/test/ics/foobar?email=%s' % local_user.email, status=403) |
|
1531 | ||
1498 | 1532 |
def test_roles(pub, local_user): |
1499 | 1533 |
Role.wipe() |
1500 | 1534 |
role = Role(name='Hello World') |
wcs/api.py | ||
---|---|---|
117 | 117 |
self.formdef = FormDef.get_by_urlname(component) |
118 | 118 |
except KeyError: |
119 | 119 |
raise TraversalError() |
120 |
# check access for all paths, to block access to formdata that would |
|
121 |
# otherwise be accessible if the user is the submitter. |
|
122 |
self.check_access() |
|
123 | 120 | |
124 |
def check_access(self): |
|
121 |
def check_access(self, api_name=None):
|
|
125 | 122 |
if 'anonymise' in get_request().form: |
126 | 123 |
if not is_url_signed() or (get_request().user and get_request().user.is_admin): |
127 | 124 |
raise AccessForbiddenError('user not authenticated') |
128 | 125 |
else: |
129 |
api_user = get_user_from_api_query_string() |
|
126 |
api_user = get_user_from_api_query_string(api_name=api_name)
|
|
130 | 127 |
if not api_user: |
131 | 128 |
if get_request().user and get_request().user.is_admin: |
132 | 129 |
return # grant access to admins, to ease debug |
... | ... | |
138 | 135 |
if component == 'ics': |
139 | 136 |
return self.ics() |
140 | 137 | |
138 |
# check access for all paths, to block access to formdata that would |
|
139 |
# otherwise be accessible if the user is the submitter. |
|
140 |
self.check_access() |
|
141 | 141 |
try: |
142 | 142 |
formdata = self.formdef.data_class().get(component) |
143 | 143 |
except KeyError: |
... | ... | |
147 | 147 | |
148 | 148 |
class ApiFormsDirectory(Directory): |
149 | 149 |
def _q_lookup(self, component): |
150 |
if not is_url_signed(): |
|
151 |
# grant access to admins, to ease debug |
|
152 |
if not (get_request().user and get_request().user.is_admin): |
|
153 |
raise AccessForbiddenError('user not authenticated') |
|
154 | 150 |
return ApiFormPage(component) |
155 | 151 | |
156 | 152 |
wcs/api_utils.py | ||
---|---|---|
98 | 98 |
return True |
99 | 99 | |
100 | 100 | |
101 |
def get_user_from_api_query_string(): |
|
102 |
if not is_url_signed(): |
|
101 |
def get_user_from_api_query_string(api_name=None): |
|
102 |
auth_header = get_request().get_header('Authorization', '') |
|
103 |
if auth_header: |
|
104 |
if not auth_header.startswith('Basic '): |
|
105 |
# we do not handle other authentication schemes |
|
106 |
raise AccessForbiddenError('unhandled authorization header') |
|
107 |
auth_header = auth_header.split(' ', 1)[1] |
|
108 |
username, password = base64.decodestring(auth_header).split(':', 1) |
|
109 |
configured_password = get_publisher().get_site_option( |
|
110 |
username, section='api-http-auth-%s' % api_name) |
|
111 |
if configured_password != password: |
|
112 |
raise AccessForbiddenError('invalid authorization') |
|
113 |
elif not is_url_signed(): |
|
103 | 114 |
return None |
104 |
# Signature is good. Now looking for the user, by email/NameID. |
|
115 |
# Signature or auth header are ok. |
|
116 |
# Look for the user, by email/NameID. |
|
105 | 117 |
user = None |
106 | 118 |
if get_request().form.get('email'): |
107 | 119 |
email = get_request().form.get('email') |
wcs/backoffice/management.py | ||
---|---|---|
1604 | 1604 |
if 'anonymise' in get_request().form: |
1605 | 1605 |
# api/ will let this pass but we don't want that. |
1606 | 1606 |
raise errors.AccessForbiddenError() |
1607 |
self.check_access() |
|
1607 |
self.check_access('ics') |
|
1608 |
user = get_user_from_api_query_string('ics') or get_request().user |
|
1608 | 1609 | |
1609 | 1610 |
formdef = self.formdef |
1610 | 1611 |
selected_filter = self.get_filter_from_query() |
... | ... | |
1625 | 1626 |
else: |
1626 | 1627 |
raise errors.TraversalError() |
1627 | 1628 | |
1628 |
user = get_user_from_api_query_string() or get_request().user |
|
1629 | ||
1630 | 1629 |
formdatas, total_count = FormDefUI(formdef).get_listing_items( |
1631 | 1630 |
selected_filter, user=user, query=query, criterias=criterias) |
1632 | 1631 | |
1633 |
- |