# HG changeset patch # User Mads Kiilerich # Date 1546569743 -3600 # Node ID 797883404f17c70f4a321205534eacc5c141297d # Parent 9c2fc1390291d9bcab701f2f12bd28913f2058f7 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. diff -r 9c2fc1390291 -r 797883404f17 kallithea/lib/auth.py --- 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') diff -r 9c2fc1390291 -r 797883404f17 kallithea/lib/base.py --- 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