changeset 7702:797883404f17

auth: simplify API key auth - move it out of _determine_auth_user This gives less of the special handling of API key auth in LoginRequired ... but we still need to disable the LoginRequired CSRF protection for API key auth.
author Mads Kiilerich <mads@kiilerich.com>
date Fri, 04 Jan 2019 03:42:23 +0100
parents 9c2fc1390291
children 5c5f0eb45681
files kallithea/lib/auth.py kallithea/lib/base.py
diffstat 2 files changed, 23 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/lib/auth.py	Fri Jan 04 03:42:17 2019 +0100
+++ b/kallithea/lib/auth.py	Fri Jan 04 03:42:23 2019 +0100
@@ -675,19 +675,13 @@
         loc = "%s:%s" % (controller.__class__.__name__, func.__name__)
         log.debug('Checking access for user %s @ %s', user, loc)
 
-        # Check if we used an API key to authenticate.
-        if user.authenticating_api_key is not None:
-            log.info('user %s authenticated with API key ****%s @ %s',
-                     user, user.authenticating_api_key[-4:], loc)
-            return func(*fargs, **fkwargs)
-
         # CSRF protection: Whenever a request has ambient authority (whether
         # through a session cookie or its origin IP address), it must include
         # the correct token, unless the HTTP method is GET or HEAD (and thus
         # guaranteed to be side effect free. In practice, the only situation
         # where we allow side effects without ambient authority is when the
         # authority comes from an API key; and that is handled above.
-        if request.method not in ['GET', 'HEAD']:
+        if user.authenticating_api_key is None and request.method not in ['GET', 'HEAD']:
             token = request.POST.get(secure_form.token_key)
             if not token or token != secure_form.authentication_token():
                 log.error('CSRF check failed')
--- a/kallithea/lib/base.py	Fri Jan 04 03:42:17 2019 +0100
+++ b/kallithea/lib/base.py	Fri Jan 04 03:42:23 2019 +0100
@@ -379,26 +379,13 @@
         self.scm_model = ScmModel()
 
     @staticmethod
-    def _determine_auth_user(api_key, bearer_token, session_authuser, ip_addr):
+    def _determine_auth_user(session_authuser, ip_addr):
         """
         Create an `AuthUser` object given the API key/bearer token
         (if any) and the value of the authuser session cookie.
         Returns None if no valid user is found (like not active or no access for IP).
         """
 
-        # Authenticate by bearer token
-        if bearer_token is not None:
-            api_key = bearer_token
-
-        # Authenticate by API key
-        if api_key is not None:
-            dbuser = User.get_by_api_key(api_key)
-            if dbuser is None:
-                log.info('No db user found for authentication with API key ****%s from %s',
-                         api_key[-4:], ip_addr)
-                return None
-            return AuthUser.make(dbuser=dbuser, authenticating_api_key=api_key, is_external_auth=True, ip_addr=ip_addr)
-
         # Authenticate by session cookie
         # In ancient login sessions, 'authuser' may not be a dict.
         # In that case, the user will have to log in again.
@@ -463,13 +450,9 @@
     def __call__(self, environ, context):
         try:
             ip_addr = _get_ip_addr(environ)
-            # make sure that we update permissions each time we call controller
-
             self._basic_security_checks()
 
-            # set globals for auth user
-
-            bearer_token = None
+            api_key = request.GET.get('api_key')
             try:
                 # Request.authorization may raise ValueError on invalid input
                 type, params = request.authorization
@@ -477,18 +460,31 @@
                 pass
             else:
                 if type.lower() == 'bearer':
-                    bearer_token = params
+                    api_key = params # bearer token is an api key too
+
+            if api_key is None:
+                authuser = self._determine_auth_user(
+                    session.get('authuser'),
+                    ip_addr=ip_addr,
+                )
 
-            authuser = self._determine_auth_user(
-                request.GET.get('api_key'),
-                bearer_token,
-                session.get('authuser'),
-                ip_addr=ip_addr,
-            )
+            else:
+                dbuser = User.get_by_api_key(api_key)
+                if dbuser is None:
+                    log.info('No db user found for authentication with API key ****%s from %s',
+                             api_key[-4:], ip_addr)
+                authuser = AuthUser.make(
+                    dbuser=dbuser,
+                    authenticating_api_key=api_key,
+                    is_external_auth=True,
+                    ip_addr=ip_addr,
+                )
+
             if authuser is None:
                 log.info('No valid user found')
                 raise webob.exc.HTTPForbidden()
 
+            # set globals for auth user
             request.authuser = authuser
             request.ip_addr = ip_addr