diff --git a/doc/source/authentication-plugins.rst b/doc/source/authentication-plugins.rst index 5afc0bc2e..89384a50e 100644 --- a/doc/source/authentication-plugins.rst +++ b/doc/source/authentication-plugins.rst @@ -235,3 +235,10 @@ can be retrieved. The most simple example of a plugin is the :py:class:`keystoneclient.auth.token_endpoint.Token` plugin. + +When writing a plugin you should ensure that any fetch operation is thread +safe. A common pattern is for a service to hold a single service authentication +plugin globally and re-use that between all threads. This means that when a +token expires there may be multiple threads that all try to fetch a new plugin +at the same time. It is the responsibility of the plugin to ensure that this +case is handled in a way that still results in correct reauthentication. diff --git a/keystoneclient/auth/identity/base.py b/keystoneclient/auth/identity/base.py index 57e172321..02c4fe6a1 100644 --- a/keystoneclient/auth/identity/base.py +++ b/keystoneclient/auth/identity/base.py @@ -12,6 +12,7 @@ import abc import logging +import threading import warnings from oslo_config import cfg @@ -54,6 +55,7 @@ class BaseIdentityPlugin(base.BaseAuthPlugin): self.reauthenticate = reauthenticate self._endpoint_cache = {} + self._lock = threading.Lock() self._username = username self._password = password @@ -236,8 +238,14 @@ class BaseIdentityPlugin(base.BaseAuthPlugin): :returns: Valid AccessInfo :rtype: :py:class:`keystoneclient.access.AccessInfo` """ - if self._needs_reauthenticate(): - self.auth_ref = self.get_auth_ref(session) + # Hey Kids! Thread safety is important particularly in the case where + # a service is creating an admin style plugin that will then proceed + # to make calls from many threads. As a token expires all the threads + # will try and fetch a new token at once, so we want to ensure that + # only one thread tries to actually fetch from keystone at once. + with self._lock: + if self._needs_reauthenticate(): + self.auth_ref = self.get_auth_ref(session) return self.auth_ref