Skip to content

Commit fdebb8c

Browse files
committed
Add support for user based default access
1 parent 81b6a57 commit fdebb8c

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

docs/manual/access-control.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,26 @@ For example, this header may be set based on IP range, or based on password auth
151151

152152
Further examples of how to set this header will be provided in the deployments section.
153153

154+
One may also specify default access for different users by adding sub keys to the ``default_access`` setting::
155+
156+
collections:
157+
test:
158+
...
159+
default_access:
160+
default: block
161+
admin: allow
162+
163+
Note that the ``default`` entry will be applied both if the user name is empty and if it actually is ``default``.
164+
If the ``default`` entry is missing, it will be assumed to be ``allow``::
165+
166+
collections:
167+
test:
168+
...
169+
default_access:
170+
guest: block
171+
172+
This works whether the ``default_access`` is specified at the top level or for a specific collection.
173+
154174
**Note: Do not use the user-based rules without configuring proper authentication on an Apache or Nginx frontend to set or remove this header, otherwise the 'X-Pywb-ACL-User' can easily be faked.**
155175

156176
See the :ref:`config-acl-header` section in Usage for examples on how to configure this header.

pywb/warcserver/access_checker.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def __init__(self, access_source, default_access='allow', embargo=None):
107107
self.default_rule['access'] = default_access
108108
self.default_rule['default'] = 'true'
109109

110+
if isinstance(self.default_rule['access'], dict):
111+
if 'default' not in self.default_rule['access']:
112+
self.default_rule['access']['default'] = 'allow'
113+
110114
self.embargo = self.parse_embargo(embargo)
111115

112116
def parse_embargo(self, embargo):
@@ -273,7 +277,17 @@ def find_access_rule(self, url, ts=None, urlkey=None, collection=None, acl_user=
273277
if acl_key < tld:
274278
break
275279

276-
return last_obj if last_obj else self.default_rule
280+
281+
if last_obj:
282+
return last_obj
283+
284+
if isinstance(self.default_rule['access'], dict):
285+
default_rule = dict(self.default_rule)
286+
user = acl_user if acl_user in default_rule['access'] else 'default'
287+
default_rule['access'] = default_rule['access'][user]
288+
return default_rule
289+
290+
return self.default_rule
277291

278292
def __call__(self, res, acl_user):
279293
"""Wraps the cdx iter in the supplied tuple returning a
@@ -334,6 +348,9 @@ def wrap_iter(self, cdx_iter, acl_user):
334348
if not access:
335349
access = self.default_rule['access']
336350

351+
if isinstance(access, dict):
352+
access = self.default_rule['access']['default']
353+
337354
if access == 'allow_ignore_embargo':
338355
access = 'allow'
339356

tests/config_test_access.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ collections:
66
archive_paths: ./sample_archive/warcs/
77
acl_paths: ./sample_archive/access/pywb.aclj
88

9-
default_access: block
9+
default_access:
10+
default: block
1011

1112
pywb-acl-list:
1213
index_paths: ./sample_archive/cdx/
@@ -62,6 +63,12 @@ collections:
6263
acl_paths:
6364
- ./sample_archive/access/pywb.aclj
6465

66+
pywb-acl-user-default:
67+
index_paths: ./sample_archive/cdx/
68+
archive_paths: ./sample_archive/warcs/
69+
acl_paths: ./sample_archive/access/user-default.aclj
6570

71+
default_access:
72+
staff2: block
6673

6774

tests/test_acl.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,12 @@ def test_allowed_different_coll_acl_dir(self):
9696

9797
assert '"http://httpbin.org/anything/resource.json"' in resp.text
9898

99+
def test_user_default(self):
100+
headers = {"X-Pywb-ACL-User": "staff"}
101+
self.testapp.get('/pywb-acl-user-default/mp_/http://www.iana.org/', headers=headers, status=200)
102+
self.testapp.get('/pywb-acl-user-default/mp_/http://www.example.com/', headers=headers, status=451)
103+
headers = {"X-Pywb-ACL-User": "staff2"}
104+
self.testapp.get('/pywb-acl-user-default/mp_/http://www.iana.org/', headers=headers, status=451)
105+
self.testapp.get('/pywb-acl-user-default/mp_/http://www.example.com/', headers=headers, status=200)
99106

100107

0 commit comments

Comments
 (0)