Add matrix auth
This commit is contained in:
parent
51bf5ac961
commit
3d37c00999
|
@ -197,17 +197,33 @@ def main(argv=None):
|
|||
err = sys.exc_info()[1]
|
||||
sys.exit("Invalid port(%r) due to: %s" % (v, err))
|
||||
elif k in ("-a", "--authenticate"):
|
||||
c.authenticated = [a.lower()
|
||||
for a in re.split("[, ]+", v.strip(" ,"))
|
||||
if a]
|
||||
if c.authenticated == ['.']:
|
||||
c.authenticated = []
|
||||
if '{' in v:
|
||||
import ast
|
||||
v = ast.literal_eval(v)
|
||||
if isinstance(v, dict):
|
||||
c.authenticated = {}
|
||||
for user in v:
|
||||
c.authenticated[user] = [a.lower() for a in v[user] if a]
|
||||
if c.authenticated[user] == ['.']:
|
||||
c.authenticated[user] = []
|
||||
else:
|
||||
actions = ("list", "download", "update")
|
||||
for a in c.authenticated[user]:
|
||||
if a not in actions:
|
||||
errmsg = "Action '%s' for option `%s` not one of %s!"
|
||||
sys.exit(errmsg % (a, k, actions))
|
||||
else:
|
||||
actions = ("list", "download", "update")
|
||||
for a in c.authenticated:
|
||||
if a not in actions:
|
||||
errmsg = "Action '%s' for option `%s` not one of %s!"
|
||||
sys.exit(errmsg % (a, k, actions))
|
||||
c.authenticated = [a.lower()
|
||||
for a in re.split("[, ]+", v.strip(" ,"))
|
||||
if a]
|
||||
if c.authenticated == ['.']:
|
||||
c.authenticated = []
|
||||
else:
|
||||
actions = ("list", "download", "update")
|
||||
for a in c.authenticated:
|
||||
if a not in actions:
|
||||
errmsg = "Action '%s' for option `%s` not one of %s!"
|
||||
sys.exit(errmsg % (a, k, actions))
|
||||
elif k in ("-i", "--interface"):
|
||||
c.host = v
|
||||
elif k in ("-r", "--root"):
|
||||
|
|
|
@ -42,17 +42,25 @@ class auth(object):
|
|||
def __call__(self, method):
|
||||
|
||||
def protector(*args, **kwargs):
|
||||
if self.action in config.authenticated:
|
||||
if not request.auth or request.auth[1] is None:
|
||||
auth = request.auth
|
||||
if config.authenticated:
|
||||
if not auth or auth[1] is None:
|
||||
raise HTTPError(
|
||||
401, headers={"WWW-Authenticate": 'Basic realm="pypi"'}
|
||||
)
|
||||
if not config.auther(*request.auth):
|
||||
401, headers={"WWW-Authenticate": 'Basic realm="pypi"'})
|
||||
if not config.auther(*auth):
|
||||
raise HTTPError(403)
|
||||
if self.authorized(auth):
|
||||
return method(*args, **kwargs)
|
||||
else:
|
||||
raise HTTPError(403)
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return protector
|
||||
|
||||
def authorized(self, auth):
|
||||
if isinstance(config.authenticated, dict):
|
||||
return auth[0] in config.authenticated and self.action in config.authenticated[auth[0]]
|
||||
return self.action in config.authenticated
|
||||
|
||||
|
||||
@app.hook('before_request')
|
||||
def log_request():
|
||||
|
|
|
@ -362,7 +362,7 @@ def test_no_cache_control_set(root, _app, testapp):
|
|||
def test_cache_control_set(root):
|
||||
from pypiserver import app
|
||||
AGE = 86400
|
||||
app_with_cache = webtest.TestApp(app(root=root.strpath, cache_control=AGE))
|
||||
app_with_cache = webtest.TestApp(app(root=root.strpath, cache_control=AGE, authenticated=[]))
|
||||
root.join("foo_bar-1.0.tar.gz").write("")
|
||||
resp = app_with_cache.get("/packages/foo_bar-1.0.tar.gz")
|
||||
assert "Cache-Control" in resp.headers
|
||||
|
@ -381,8 +381,8 @@ def test_upload_badAction(root, testapp):
|
|||
assert "Unsupported ':action' field: BAD" in hp.unescape(resp.text)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("package"), [f[0]
|
||||
for f in test_core.files
|
||||
@pytest.mark.parametrize(("package"), [f[0]
|
||||
for f in test_core.files
|
||||
if f[1] and '/' not in f[0]])
|
||||
def test_upload(package, root, testapp):
|
||||
resp = testapp.post("/", params={':action': 'file_upload'},
|
||||
|
@ -393,13 +393,13 @@ def test_upload(package, root, testapp):
|
|||
assert uploaded_pkgs[0].lower() == package.lower()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("package"), [f[0]
|
||||
for f in test_core.files
|
||||
@pytest.mark.parametrize(("package"), [f[0]
|
||||
for f in test_core.files
|
||||
if f[1] and '/' not in f[0]])
|
||||
def test_upload_with_signature(package, root, testapp):
|
||||
resp = testapp.post("/", params={':action': 'file_upload'},
|
||||
upload_files=[
|
||||
('content', package, b''),
|
||||
('content', package, b''),
|
||||
('gpg_signature', '%s.asc' % package, b'')])
|
||||
assert resp.status_int == 200
|
||||
uploaded_pkgs = [f.basename.lower() for f in root.listdir()]
|
||||
|
@ -433,7 +433,7 @@ def test_remove_pkg_missingNaveVersion(name, version, root, testapp):
|
|||
params = {':action': 'remove_pkg', 'name': name, 'version': version}
|
||||
params = dict((k, v) for k,v in params.items() if v is not None)
|
||||
resp = testapp.post("/", expect_errors=1, params=params)
|
||||
|
||||
|
||||
assert resp.status == '400 Bad Request'
|
||||
assert msg %(name, version) in hp.unescape(resp.text)
|
||||
|
||||
|
|
|
@ -169,3 +169,21 @@ def test_dot_password_without_auth_list(main, monkeypatch):
|
|||
|
||||
main(["-P", ".", "-a", "."])
|
||||
assert main.app.module.config.authenticated == []
|
||||
|
||||
def test_password_with_auth_list(main, monkeypatch):
|
||||
monkeypatch.setitem(sys.modules, 'passlib', mock.MagicMock())
|
||||
monkeypatch.setitem(sys.modules, 'passlib.apache', mock.MagicMock())
|
||||
main(["-P", "pswd-file", "-a", "update, download"])
|
||||
assert main.app.module.config.authenticated == ['update', 'download']
|
||||
|
||||
def test_password_with_auth_list_with_no_spaces(main, monkeypatch):
|
||||
monkeypatch.setitem(sys.modules, 'passlib', mock.MagicMock())
|
||||
monkeypatch.setitem(sys.modules, 'passlib.apache', mock.MagicMock())
|
||||
main(["-P", "pswd-file", "-a", "update,download"])
|
||||
assert main.app.module.config.authenticated == ['update', 'download']
|
||||
|
||||
def test_matrix_auth_list(main, monkeypatch):
|
||||
monkeypatch.setitem(sys.modules, 'passlib', mock.MagicMock())
|
||||
monkeypatch.setitem(sys.modules, 'passlib.apache', mock.MagicMock())
|
||||
main(["-P", "pswd-file", "-a", "{'a': ['update', 'list'], 'b': ['download']}"])
|
||||
assert main.app.module.config.authenticated == {'a': ['update', 'list'], 'b': ['download']}
|
||||
|
|
|
@ -43,7 +43,7 @@ Srv = namedtuple('Srv', ('proc', 'port', 'package'))
|
|||
|
||||
def _run_server(packdir, port, authed, other_cli=''):
|
||||
pswd_opt_choices = {
|
||||
True: "-Ptests/htpasswd.a.a -a update,download",
|
||||
True: "-Ptests/htpasswd.a.a -a update,download,list",
|
||||
False: "-P. -a."
|
||||
}
|
||||
pswd_opts = pswd_opt_choices[authed]
|
||||
|
|
Loading…
Reference in New Issue