ByteInternet / drf-oidc-auth

OpenID Connect authentication for Django REST Framework
MIT License
113 stars 46 forks source link

Re-adding the same key breaks proper expiration #37

Closed obi-081 closed 4 years ago

obi-081 commented 4 years ago

Hi ! I have this error on our server. I suspect that two requests arrive at the same time are creating a race congition. We use Gunicorn 20.0.4 Django==2.2.11 djangorestframework==3.11.0 drf-oidc-auth==0.9

Can you help ?

Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/oidc_auth/util.py", line 35, in wrapped cached_value = self.get_from_cache(args) File "/usr/local/lib/python3.6/site-packages/oidc_auth/util.py", line 27, in get_from_cache return self.cached_values[key] KeyError: (b'ey...fQ.ey...n0.Dl...wQ',)

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner response = get_response(request) File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, callback_kwargs) File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view return view_func(*args, *kwargs) File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view return self.dispatch(request, args, kwargs) File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 505, in dispatch response = self.handle_exception(exc) File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 465, in handle_exception self.raise_uncaught_exception(exc) File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception raise exc File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 493, in dispatch self.initial(request, *args, **kwargs) File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 410, in initial self.perform_authentication(request) File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 324, in perform_authentication request.user File "/usr/local/lib/python3.6/site-packages/rest_framework/request.py", line 220, in user self._authenticate() File "/usr/local/lib/python3.6/site-packages/rest_framework/request.py", line 373, in _authenticate user_auth_tuple = authenticator.authenticate(self) File "/usr/local/lib/python3.6/site-packages/oidc_auth/authentication.py", line 44, in authenticate userinfo = self.get_userinfo(bearer_token) File "/usr/local/lib/python3.6/site-packages/oidc_auth/util.py", line 38, in wrapped self.add_to_cache(args, cached_value, now) File "/usr/local/lib/python3.6/site-packages/oidc_auth/util.py", line 20, in add_to_cache assert key not in self.cached_values, "Re-adding the same key breaks proper expiration" AssertionError: Re-adding the same key breaks proper expiration

mikebridge commented 4 years ago

I just installed drf-oidc-auth for the first time and I'm getting a similar error,

Python 3.8 drf-oidc-auth 0.9 djangorestframework 3.11.0 django 3.0.5

Internal Server Error: /api/test/
Traceback (most recent call last):
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/oidc_auth/util.py", line 35, in wrapped
    cached_value = self.get_from_cache(args)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/oidc_auth/util.py", line 27, in get_from_cache
    return self.cached_values[key]
KeyError: (b'eyJ0eXAiO******',)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/viewsets.py", line 114, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 493, in dispatch
    self.initial(request, *args, **kwargs)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 410, in initial
    self.perform_authentication(request)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/views.py", line 324, in perform_authentication
    request.user
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/request.py", line 220, in user
    self._authenticate()
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/rest_framework/request.py", line 373, in _authenticate
    user_auth_tuple = authenticator.authenticate(self)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/oidc_auth/authentication.py", line 44, in authenticate
    userinfo = self.get_userinfo(bearer_token)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/oidc_auth/util.py", line 37, in wrapped
    cached_value = fn(this, *args)
  File "/home/bridge/.local/share/virtualenvs/api-b1B34dg8/lib/python3.8/site-packages/oidc_auth/authentication.py", line 71, in get_userinfo
    response = requests.get(self.oidc_config['userinfo_endpoint'],
KeyError: 'userinfo_endpoint'
kerrermanisNL commented 4 years ago

Hi guys thanks for reporting this. I'll have a look this Friday afternoon :)

sebaacuna commented 4 years ago

I got around this by monkeypatching with:

from oidc_auth.util import cache
import logging

logger = logging.getLogger(__name__)

# Monkey patch OIDC issue
# https://github.com/ByteInternet/drf-oidc-auth/issues/37
def add_to_cache(self, key, value, now):
    if key not in self.cached_values:
        logger.debug("Re-adding the same key breaks proper expiration")
        return

    self.cached_values[key] = value
    # Since TTL is constant, expiration happens in order of addition to queue,
    # so queue is always ordered by expiration time.
    self.expiration_queue.append((now + self.ttl, key))

cache.add_to_cache = add_to_cache

@kerrermanisNL Would that change (assert -> if / return) be an acceptable change in the behavior?

obi-081 commented 4 years ago

I see that this one is patched in version 0.10, I think we can close the Ticket. ;)

kerrermanisNL commented 4 years ago

Haha, sorry. Yeah I did take a look at it, but couldn't figure out what was wrong. Probably because I was looking at the newer code base :sweat_smile: At least, let's hope that was it :smile: