mirror of
https://github.com/pypiserver/pypiserver
synced 2024-11-09 16:45:51 +01:00
implement auth for listings and downloads
This commit is contained in:
parent
d0946ebbcf
commit
ffd366fa3e
@ -5,6 +5,7 @@ version = __version__ = "1.1.6"
|
||||
def app(root=None,
|
||||
redirect_to_fallback=True,
|
||||
fallback_url=None,
|
||||
authenticated=[],
|
||||
password_file=None,
|
||||
overwrite=False,
|
||||
log_req_frmt="%(bottle.request)s",
|
||||
@ -25,7 +26,7 @@ def app(root=None,
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
|
||||
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback, fallback_url=fallback_url,
|
||||
password_file=password_file, overwrite=overwrite,
|
||||
authenticated=authenticated, password_file=password_file, overwrite=overwrite,
|
||||
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt)
|
||||
_app.app.module = _app
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import sys, os, itertools, zipfile, mimetypes, logging
|
||||
import sys, os, itertools, zipfile, mimetypes, logging, contextlib
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
@ -33,9 +33,29 @@ def validate_user(username, password):
|
||||
return config.htpasswdfile.check_password(username, password)
|
||||
|
||||
|
||||
class auth(object):
|
||||
"decorator to apply authentication if specified for the decorated method & action"
|
||||
|
||||
def __init__(self, action):
|
||||
self.action = action
|
||||
|
||||
def __call__(self, method):
|
||||
|
||||
def protector(*args, **kwargs):
|
||||
if self.action in config.authenticated:
|
||||
if not request.auth or request.auth[1] is None:
|
||||
raise HTTPError(401, header={"WWW-Authenticate": 'Basic realm="pypi"'})
|
||||
if not validate_user(*request.auth):
|
||||
raise HTTPError(403)
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return protector
|
||||
|
||||
|
||||
def configure(root=None,
|
||||
redirect_to_fallback=True,
|
||||
fallback_url=None,
|
||||
authenticated=[],
|
||||
password_file=None,
|
||||
overwrite=False,
|
||||
log_req_frmt=None,
|
||||
@ -46,12 +66,15 @@ def configure(root=None,
|
||||
log.info("Starting(%s)", dict(root=root,
|
||||
redirect_to_fallback=redirect_to_fallback,
|
||||
fallback_url=fallback_url,
|
||||
authenticated=authenticated,
|
||||
password_file=password_file,
|
||||
overwrite=overwrite,
|
||||
log_req_frmt=log_req_frmt,
|
||||
log_res_frmt=log_res_frmt,
|
||||
log_err_frmt=log_err_frmt))
|
||||
|
||||
config.authenticated = authenticated
|
||||
|
||||
if root is None:
|
||||
root = os.path.expanduser("~/packages")
|
||||
|
||||
@ -146,13 +169,8 @@ easy_install -i %(URL)ssimple/ PACKAGE
|
||||
|
||||
|
||||
@app.post('/')
|
||||
@auth("update")
|
||||
def update():
|
||||
if not request.auth or request.auth[1] is None:
|
||||
raise HTTPError(401, header={"WWW-Authenticate": 'Basic realm="pypi"'})
|
||||
|
||||
if not validate_user(*request.auth):
|
||||
raise HTTPError(403)
|
||||
|
||||
try:
|
||||
action = request.forms[':action']
|
||||
except KeyError:
|
||||
@ -208,11 +226,13 @@ def update():
|
||||
|
||||
|
||||
@app.route("/simple")
|
||||
@auth("list")
|
||||
def simpleindex_redirect():
|
||||
return redirect(request.fullpath + "/")
|
||||
|
||||
|
||||
@app.route("/simple/")
|
||||
@auth("list")
|
||||
def simpleindex():
|
||||
res = ["<html><head><title>Simple Index</title></head><body>\n"]
|
||||
for x in sorted(get_prefixes(packages())):
|
||||
@ -223,6 +243,7 @@ def simpleindex():
|
||||
|
||||
@app.route("/simple/:prefix")
|
||||
@app.route("/simple/:prefix/")
|
||||
@auth("list")
|
||||
def simple(prefix=""):
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
@ -246,6 +267,7 @@ def simple(prefix=""):
|
||||
|
||||
@app.route('/packages')
|
||||
@app.route('/packages/')
|
||||
@auth("list")
|
||||
def list_packages():
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
@ -262,6 +284,7 @@ def list_packages():
|
||||
|
||||
|
||||
@app.route('/packages/:filename#.*#')
|
||||
@auth("download")
|
||||
def server_static(filename):
|
||||
entries = find_packages(packages())
|
||||
for x in entries:
|
||||
|
@ -189,9 +189,15 @@ pypi-server understands the following options:
|
||||
-i INTERFACE, --interface INTERFACE
|
||||
listen on interface INTERFACE (default: 0.0.0.0, any interface)
|
||||
|
||||
-a [update|download|list], ... --authenticate update|download|list], ...
|
||||
comma-separated list of actions to authenticate (requires giving also
|
||||
the -P option). The "update" action sets up authentication of any
|
||||
repository update given via python setup.py command, such as package
|
||||
upload or removal.
|
||||
|
||||
-P PASSWORD_FILE, --passwords PASSWORD_FILE
|
||||
use apache htpasswd file PASSWORD_FILE in order to enable password
|
||||
protected uploads.
|
||||
use apache htpasswd file PASSWORD_FILE to set usernames & passwords
|
||||
used for authentication (requires giving the -s option as well).
|
||||
|
||||
--disable-fallback
|
||||
disable redirect to real PyPI index for packages not found in the
|
||||
@ -275,6 +281,7 @@ def main(argv=None):
|
||||
server = DEFAULT_SERVER
|
||||
redirect_to_fallback = True
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
authenticated = []
|
||||
password_file = None
|
||||
overwrite = False
|
||||
verbosity = 1
|
||||
@ -289,9 +296,10 @@ def main(argv=None):
|
||||
update_stable_only = True
|
||||
|
||||
try:
|
||||
opts, roots = getopt.getopt(argv[1:], "i:p:r:d:P:Uuvxoh", [
|
||||
opts, roots = getopt.getopt(argv[1:], "i:p:a:r:d:P:Uuvxoh", [
|
||||
"interface=",
|
||||
"passwords=",
|
||||
"authenticate=",
|
||||
"port=",
|
||||
"root=",
|
||||
"server=",
|
||||
@ -313,6 +321,13 @@ def main(argv=None):
|
||||
for k, v in opts:
|
||||
if k in ("-p", "--port"):
|
||||
port = int(v)
|
||||
elif k in ("-a", "--authenticate"):
|
||||
authenticated = [a.strip() for a in v.split(',')]
|
||||
actions = ("list", "download", "update")
|
||||
for a in authenticated:
|
||||
if a not in actions:
|
||||
errmsg = "Incorrect action '%s' given with option '%s'" % (k, a)
|
||||
sys.exit(errmsg)
|
||||
elif k in ("-i", "--interface"):
|
||||
host = v
|
||||
elif k in ("-r", "--root"):
|
||||
@ -375,6 +390,7 @@ def main(argv=None):
|
||||
a = app(
|
||||
root=roots,
|
||||
redirect_to_fallback=redirect_to_fallback,
|
||||
authenticated=authenticated,
|
||||
password_file=password_file,
|
||||
fallback_url=fallback_url,
|
||||
overwrite=overwrite,
|
||||
|
Loading…
Reference in New Issue
Block a user