Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for user based default access #812

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/manual/access-control.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,26 @@ For example, this header may be set based on IP range, or based on password auth

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

One may also specify default access for different users by adding sub keys to the ``default_access`` setting::

collections:
test:
...
default_access:
default: block
admin: allow

Note that the ``default`` entry will be applied both if the user name is empty and if it actually is ``default``.
If the ``default`` entry is missing, it will be assumed to be ``allow``::

collections:
test:
...
default_access:
guest: block

This works whether the ``default_access`` is specified at the top level or for a specific collection.

**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.**

See the :ref:`config-acl-header` section in Usage for examples on how to configure this header.
Expand Down
19 changes: 18 additions & 1 deletion pywb/warcserver/access_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def __init__(self, access_source, default_access='allow', embargo=None):
self.default_rule['access'] = default_access
self.default_rule['default'] = 'true'

if isinstance(self.default_rule['access'], dict):
if 'default' not in self.default_rule['access']:
self.default_rule['access']['default'] = 'allow'

self.embargo = self.parse_embargo(embargo)

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

return last_obj if last_obj else self.default_rule

if last_obj:
return last_obj

if isinstance(self.default_rule['access'], dict):
default_rule = dict(self.default_rule)
user = acl_user if acl_user in default_rule['access'] else 'default'
default_rule['access'] = default_rule['access'][user]
return default_rule

return self.default_rule

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

if isinstance(access, dict):
access = self.default_rule['access']['default']

if access == 'allow_ignore_embargo':
access = 'allow'

Expand Down
2 changes: 2 additions & 0 deletions sample_archive/access/user-default.aclj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
com,example)/ - {"access": "block", "user": "staff"}
com,example)/ - {"access": "allow", "user": "staff2"}
9 changes: 8 additions & 1 deletion tests/config_test_access.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ collections:
archive_paths: ./sample_archive/warcs/
acl_paths: ./sample_archive/access/pywb.aclj

default_access: block
default_access:
default: block

pywb-acl-list:
index_paths: ./sample_archive/cdx/
Expand Down Expand Up @@ -62,6 +63,12 @@ collections:
acl_paths:
- ./sample_archive/access/pywb.aclj

pywb-acl-user-default:
index_paths: ./sample_archive/cdx/
archive_paths: ./sample_archive/warcs/
acl_paths: ./sample_archive/access/user-default.aclj

default_access:
staff2: block


8 changes: 8 additions & 0 deletions tests/test_acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,13 @@ def test_allowed_different_coll_acl_dir(self):

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

def test_user_default(self):
headers = {"X-Pywb-ACL-User": "staff"}
self.testapp.get('/pywb-acl-user-default/mp_/http://www.iana.org/', headers=headers, status=200)
self.testapp.get('/pywb-acl-user-default/mp_/http://www.example.com/', headers=headers, status=451)

headers = {"X-Pywb-ACL-User": "staff2"}
self.testapp.get('/pywb-acl-user-default/mp_/http://www.iana.org/', headers=headers, status=451)
self.testapp.get('/pywb-acl-user-default/mp_/http://www.example.com/', headers=headers, status=200)


1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ python =

[testenv]
setenv = PYWB_NO_VERIFY_SSL = 1
passenv = *
deps =
-rtest_requirements.txt
-rrequirements.txt
Expand Down