#!/usr/bin/python
+import asyncio
import base64
+import functools
import http.client
import json
import kerberos
# Set status to 401
self.set_status(401)
+ @functools.cache
def get_authenticated_user(self):
auth_header = self.request.headers.get("Authorization", None)
return
# Perform GSS API Negotiation
- if auth_header.startswith("Negotiate"):
+ if auth_header.startswith("Negotiate "):
return self._auth_negotiate(auth_header)
# Perform Basic Authentication
except:
raise tornado.web.HTTPError(400, "Authorization data was malformed")
+ # Authenticate against Kerberos
+ return self._auth_with_credentials(username, password)
+
+ def _auth_with_credentials(self, username, password):
# Check the credentials against the Kerberos database
try:
kerberos.checkPassword(username, password,
"format_date" : self.format_date,
"format_size" : misc.format_size,
"version" : __version__,
+ "xsrf_token" : self.xsrf_token,
"year" : time.strftime("%Y"),
})
def get_argument_bool(self, name):
arg = self.get_argument(name, default=None)
- return arg == "on"
+ if arg:
+ return arg.lower() in ("on", "true", "yes", "1")
+
+ return False
def get_argument_int(self, *args, **kwargs):
arg = self.get_argument(*args, **kwargs)
if slug:
return self.backend.distros.get_by_slug(slug)
+ # Uploads
+
+ def _get_upload(self, uuid):
+ upload = self.backend.uploads.get_by_uuid(uuid)
+
+ # Check permissions
+ if upload and not upload.has_perm(self.current_user):
+ raise tornado.web.HTTPError(403, "%s has no permissions for upload %s" % (self.current_user, upload))
+
+ return upload
+
def get_argument_upload(self, *args, **kwargs):
"""
Returns an upload
uuid = self.get_argument(*args, **kwargs)
if uuid:
- return self.backend.uploads.get_by_uuid(uuid)
+ return self._get_upload(uuid)
def get_argument_uploads(self, *args, **kwargs):
"""
uuids = self.get_arguments(*args, **kwargs)
# Return all uploads
- return [self.backend.uploads.get_by_uuid(uuid) for uuid in uuids]
+ return [self._get_upload(uuid) for uuid in uuids]
def get_argument_user(self, *args, **kwargs):
name = self.get_argument(*args, **kwargs)
log.debug("%s" % json.dumps(message, indent=4))
return message
+
+
+class ratelimit(object):
+ """
+ A decorator class which limits how often a function can be called
+ """
+ def __init__(self, *, minutes, requests):
+ self.minutes = minutes
+ self.requests = requests
+
+ def __call__(self, method):
+ @functools.wraps(method)
+ async def wrapper(handler, *args, **kwargs):
+ # Pass the request to the rate limiter and get a request object
+ req = handler.backend.ratelimiter.handle_request(handler.request,
+ handler, minutes=self.minutes, limit=self.requests)
+
+ # If the rate limit has been reached, we won't allow
+ # processing the request and therefore send HTTP error code 429.
+ if await req.is_ratelimited():
+ raise tornado.web.HTTPError(429, "Rate limit exceeded")
+
+ # Call the wrapped method
+ result = method(handler, *args, **kwargs)
+
+ # Await it if it is a coroutine
+ if asyncio.iscoroutine(result):
+ return await result
+
+ # Return the result
+ return result
+
+ return wrapper