]> git.ipfire.org Git - ipfire.org.git/commitdiff
nopaste: Require authentication on the cURL interface
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 23 Feb 2024 19:19:23 +0000 (19:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 23 Feb 2024 19:19:23 +0000 (19:19 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/web/base.py
src/web/nopaste.py

index 956dca2f3ccc7c309c34800076e2edf060b1c93e..efc47d7fe751b5dfce6806b0357b7af64ed9e96f 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 
 import asyncio
+import base64
 import datetime
 import dateutil.parser
 import functools
@@ -169,6 +170,57 @@ class BaseHandler(tornado.web.RequestHandler):
        def referrer(self):
                return self.request.headers.get("Referer", None)
 
+       def _request_basic_authentication(self):
+               """
+                       Called to ask the client to perform HTTP Basic authentication
+               """
+               # Ask for authentication
+               self.set_status(401)
+
+               # Say that we support Basic
+               self.set_header("WWW-Authenticate", "Basic realm=Restricted")
+
+               self.finish()
+
+       def perform_basic_authentication(self):
+               """
+                       This handles HTTP Basic authentication.
+               """
+               # Fetch credentials
+               cred = self.request.headers.get("Authorization", None)
+               if not cred:
+                       return self._request_basic_authentication()
+
+               # No basic auth? We cannot handle that
+               if not cred.startswith("Basic "):
+                       return self._request_basic_authentication()
+
+               # Decode the credentials
+               try:
+                       # Convert into bytes()
+                       cred = cred[6:].encode()
+
+                       # Decode base64
+                       cred = base64.b64decode(cred).decode()
+
+                       username, password = cred.split(":", 1)
+
+               # Fail if any of those steps failed
+               except:
+                       raise e
+                       raise tornado.web.HTTPError(400, "Authorization data was malformed")
+
+               # Find the user in the database
+               return self.backend.accounts.auth(username, password)
+
+               # Log something
+               if account:
+                       log.info("%s authenticated successfully using HTTP Basic authentication" % account.uid)
+               else:
+                       log.warning("Could not authenticate %s" % username)
+
+               return account
+
        def get_argument_int(self, *args, **kwargs):
                arg = self.get_argument(*args, **kwargs)
 
index f0508d837bb1813bea0e8523d1043c1fff9e303c..6424f26e6c2c09393414d55e914c463d621a5323 100644 (file)
@@ -28,6 +28,13 @@ class CreateHandler(base.AnalyticsMixin, base.BaseHandler):
 
        # cURL Interface
 
+       def get_current_user(self):
+               if self.request.method == "PUT":
+                       return self.perform_basic_authentication()
+
+               # Perform the usual authentication
+               return super().get_current_user()
+
        def check_xsrf_cookie(self):
                # Skip the check on PUT
                if self.request.method == "PUT":
@@ -36,13 +43,12 @@ class CreateHandler(base.AnalyticsMixin, base.BaseHandler):
                # Perform the check as usual
                super().check_xsrf_cookie()
 
-       # XXX implement HTTP Basic authentication
-
+       @tornado.web.authenticated
        @base.ratelimit(minutes=15, requests=5)
        def put(self):
                with self.db.transaction():
                        paste = self.backend.nopaste.create(
-                               self.request.body, address=self.get_remote_ip())
+                               self.request.body, account=account, address=self.get_remote_ip())
 
                # Send a message to the client
                self.write("https://%s/view/%s\n" % (self.request.host, paste.uuid))