From b8d64d008cc97165eeca6df42c39c5efd1dad5dc Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Sun, 2 Oct 2016 17:11:41 +0100
Subject: [PATCH] validate usernames before querying backend

---
 authserv/app_common.py | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/authserv/app_common.py b/authserv/app_common.py
index 9d5c8df..32b6c0d 100644
--- a/authserv/app_common.py
+++ b/authserv/app_common.py
@@ -1,3 +1,4 @@
+import re
 from flask import abort, current_app
 from authserv import auth
 from authserv import protocol
@@ -22,8 +23,34 @@ def check_ratelimit(request, username, source_ip):
             abort(503)
 
 
+def _validate_username(username):
+    """Validate a username before fetching it from the backend.
+
+    More of a syntax check than anything. It's just to save cycles in
+    case of (only the most trivial of) brute-force / exploitation
+    attempts.
+
+    Returns the validated username (type str).
+    """
+    if not username:
+        raise Exception('empty username')
+
+    if len(username) > 256:
+        raise Exception('name too long')
+
+    # This will throw a UnicodeEncodeError on non-ASCII usernames.
+    username = str(username)
+
+    # Check that it does not contain spaces or newlines.
+    if re.match(r'\s', username):
+        raise Exception('invalid characters in username')
+
+    return username
+
+
 def do_auth(username, service, shard, password, otp_token, source_ip,
             password_only=False):
+    # Username must be an ASCII string.
     bl = AuthBlackList(current_app.config.get('BLACKLIST_COUNT', 5),
                        current_app.config.get('BLACKLIST_PERIOD', 600),
                        current_app.config.get('BLACKLIST_TIME', 6*3600))
@@ -38,6 +65,12 @@ def do_auth(username, service, shard, password, otp_token, source_ip,
     retval = protocol.ERR_AUTHENTICATION_FAILURE
     errmsg = 'user does not exist'
     out_shard = None
+
+    try:
+        username = _validate_username(username)
+    except:
+        return (retval, errmsg, None)
+
     user = current_app.userdb.get_user(username, service, shard)
     if user:
         retval, errmsg = auth.authenticate(
-- 
GitLab