Repository: Kinto/kinto

Issue:
OpenID payload cache uses the wrong cache key
The `cache_key` becomes the same for every access token due to this bug: https://github.com/Kinto/kinto/blob/e1e0d6be0024418fd100210901f9d2ca06344fe1/kinto/plugins/openid/__init__.py#L51
No matter what the `hmac_tokens` variable is the `cache_key` always becomes `'openid:verify:%s'`.




Discussion:
![](https://media.giphy.com/media/nspvD8XYqUxP2/giphy.gif)

Resolving patch:
diff --git a/kinto/plugins/openid/__init__.py b/kinto/plugins/openid/__init__.py
--- a/kinto/plugins/openid/__init__.py
+++ b/kinto/plugins/openid/__init__.py
@@ -48,7 +48,7 @@ def unauthenticated_userid(self, request):
 
         # Check cache if these tokens were already verified.
         hmac_tokens = core_utils.hmac_digest(hmac_secret, access_token)
-        cache_key = 'openid:verify:%s'.format(hmac_tokens)
+        cache_key = 'openid:verify:{}'.format(hmac_tokens)
         payload = request.registry.cache.get(cache_key)
         if payload is None:
             # This can take some time.
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -83,7 +83,7 @@ def read_file(filename):
 
 
 setup(name='kinto',
-      version='9.1.1',
+      version='9.1.2',
       description='Kinto Web Service - Store, Sync, Share, and Self-Host.',
       long_description='{}\n\n{}\n\n{}'.format(README, CHANGELOG, CONTRIBUTORS),
       license='Apache License (2.0)',


Test patch:
diff --git a/tests/plugins/test_openid.py b/tests/plugins/test_openid.py
--- a/tests/plugins/test_openid.py
+++ b/tests/plugins/test_openid.py
@@ -111,13 +111,35 @@ def test_returns_none_if_no_cache_and_invalid_access_token(self):
     def test_payload_is_read_from_cache(self):
         self.request.headers['Authorization'] = 'Bearer xyz'
         self.request.registry.cache.get.return_value = {'sub': 'me'}
-        self.policy.unauthenticated_userid(self.request) == 'me'
+        assert self.policy.unauthenticated_userid(self.request) == 'me'
 
     def test_payload_is_stored_in_cache(self):
         self.request.headers['Authorization'] = 'Bearer xyz'
         assert self.policy.unauthenticated_userid(self.request) == 'userid'
         assert self.request.registry.cache.set.called
 
+    def test_payload_is_read_from_cache_but_differently_by_access_token(self):
+        # State to keep track of cache keys queried.
+        cache_keys_used = []
+
+        def mocked_cache_get(cache_key):
+            # This makes sure the same cache key is not used twice
+            assert cache_key not in cache_keys_used
+            cache_keys_used.append(cache_key)
+            if len(cache_keys_used) == 1:
+                return {'sub': 'me'}
+            elif len(cache_keys_used) == 2:
+                return {'sub': 'you'}
+
+        self.request.registry.cache.get.side_effect = mocked_cache_get
+
+        self.request.headers['Authorization'] = 'Bearer xyz'
+        assert self.policy.unauthenticated_userid(self.request) == 'me'
+
+        # Change the Authorization header the second time
+        self.request.headers['Authorization'] = 'Bearer abc'
+        assert self.policy.unauthenticated_userid(self.request) == 'you'
+
 
 class VerifyTokenTest(unittest.TestCase):