From: Michael Tremer Date: Wed, 5 Oct 2022 14:37:41 +0000 (+0000) Subject: hub: Require builders and users to authenticate using Kerberos X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a250484fa0985e4e49393af37e95f4bfb833e195;p=pbs.git hub: Require builders and users to authenticate using Kerberos Signed-off-by: Michael Tremer --- diff --git a/src/buildservice/builders.py b/src/buildservice/builders.py index 852e827a..203ce1cb 100644 --- a/src/buildservice/builders.py +++ b/src/buildservice/builders.py @@ -53,23 +53,6 @@ class Builders(base.Object): # The Builder object and the passphrase are returned. return builder, passphrase - def auth(self, name, passphrase): - # If either name or passphrase is None, we don't check at all. - if None in (name, passphrase): - return - - # Search for the hostname in the database. - builder = self._get_builder("SELECT * FROM builders \ - WHERE name = %s AND deleted IS FALSE", name) - - # If the builder was not found or the passphrase does not match, - # you have bad luck. - if not builder or not builder.validate_passphrase(passphrase): - return - - # Otherwise we return the Builder object. - return builder - def get_by_id(self, builder_id): return self._get_builder("SELECT * FROM builders WHERE id = %s", builder_id) diff --git a/src/hub/__init__.py b/src/hub/__init__.py index d8291d9d..7e66ee3d 100644 --- a/src/hub/__init__.py +++ b/src/hub/__init__.py @@ -41,6 +41,9 @@ class Application(tornado.web.Application): # Queue (r"/queue", queue.QueueHandler), + # Test + (r"/test", handlers.TestHandler), + # Uploads (r"/uploads", uploads.CreateHandler), ], **settings) diff --git a/src/hub/handlers.py b/src/hub/handlers.py index 82dceb75..0d3a944a 100644 --- a/src/hub/handlers.py +++ b/src/hub/handlers.py @@ -1,6 +1,5 @@ #!/usr/bin/python -import base64 import json import logging import tornado.web @@ -9,9 +8,38 @@ from .. import builds from .. import builders from .. import users +from ..web.auth import KerberosAuthMixin + log = logging.getLogger("pakfire.hub") -class BackendMixin(object): +class AuthMixin(KerberosAuthMixin): + """ + Requires a builder or user to authenticate + """ + def get_current_user(self): + # Fetch the Kerberos ticket + principal = self.get_authenticated_user() + + # Return nothing if we did not receive any credentials + if not principal: + return + + log.debug("Searching for principal %s..." % principal) + + # Strip the realm + principal, delimiter, realm = principal.partition("@") + + # Return any builders + if principal.startswith("host/"): + hostname = principal.removeprefix("host/") + + return self.backend.builders.get_by_name(hostname) + + # Return users + return self.backend.users.get_by_name(principal) + + +class BackendMixin(AuthMixin): @property def backend(self): """ @@ -24,49 +52,7 @@ class BackendMixin(object): return self.backend.db -class HTTPBasicAuthMixin(object): - def get_basic_auth_credentials(self): - """ - This handles HTTP Basic authentication. - """ - auth_header = self.request.headers.get("Authorization", None) - - # If no authentication information was provided, we stop here. - if not auth_header: - return None, None - - # No basic auth? We cannot handle that. - if not auth_header.startswith("Basic "): - raise tornado.web.HTTPError(400, "Can only handle Basic auth.") - - try: - # Convert into bytes() - auth_header = auth_header[6:].encode() - - # Decode base64 - auth_header = base64.b64decode(auth_header).decode() - - name, password = auth_header.split(":", 1) - except: - raise tornado.web.HTTPError(400, "Authorization data was malformed") - - return name, password - - -class BaseHandler(BackendMixin, HTTPBasicAuthMixin, tornado.web.RequestHandler): - def get_current_user(self): - name, password = self.get_basic_auth_credentials() - if name is None: - return - - builder = self.backend.builders.auth(name, password) - if builder: - return builder - - user = self.backend.users.auth(name, password) - if user: - return user - +class BaseHandler(BackendMixin, tornado.web.RequestHandler): @property def builder(self): if isinstance(self.current_user, builders.Builder): @@ -109,6 +95,16 @@ class BaseHandler(BackendMixin, HTTPBasicAuthMixin, tornado.web.RequestHandler): return self.backend.uploads.get_by_uuid(uuid) +# Hello World + +class TestHandler(BaseHandler): + """ + This handler is for checking whether authentication works, etc... + """ + @tornado.web.authenticated + def get(self): + self.write("Hello, %s!\n" % self.current_user) + # Builds class BuildsGetHandler(BaseHandler): diff --git a/src/hub/jobs.py b/src/hub/jobs.py index dd41779d..79e4e862 100644 --- a/src/hub/jobs.py +++ b/src/hub/jobs.py @@ -23,11 +23,11 @@ import json import logging import tornado.websocket -from .handlers import BackendMixin, HTTPBasicAuthMixin +from .handlers import BackendMixin log = logging.getLogger("pakfire.hub.jobs") -class BuilderHandler(BackendMixin, HTTPBasicAuthMixin, tornado.websocket.WebSocketHandler): +class BuilderHandler(BackendMixin, tornado.websocket.WebSocketHandler): """ Builders connect to this handler when they are running a build. diff --git a/src/hub/queue.py b/src/hub/queue.py index dc166bb9..34deb752 100644 --- a/src/hub/queue.py +++ b/src/hub/queue.py @@ -22,7 +22,7 @@ import logging import tornado.websocket -from .handlers import BackendMixin, HTTPBasicAuthMixin +from .handlers import BackendMixin log = logging.getLogger("pakfire.hub.queue") @@ -71,10 +71,10 @@ async def dispatch_jobs(backend): # If there is no job for the builder, we might as well shut it down await builder.stop() -class QueueHandler(BackendMixin, HTTPBasicAuthMixin, tornado.websocket.WebSocketHandler): +class QueueHandler(BackendMixin, tornado.websocket.WebSocketHandler): """ Builders connect to this handler which will add them to a list of connections. - + For all connections, we regularly check if we have any new build jobs, and if so, we will send them the job. """