diff options
author | Yves-Gwenael Bourhis <yves-gwenael.bourhis@cloudwatt.com> | 2014-06-20 13:43:24 +0200 |
---|---|---|
committer | Yves-Gwenael Bourhis <yves-gwenael.bourhis@cloudwatt.com> | 2014-09-12 16:49:45 +0200 |
commit | 31860107c305cc649a74335a3436cbc610be8ef9 (patch) | |
tree | 4ada06ba71463eea9afecf99fcdedd9adb923c3b | |
parent | 5c8b0c78f28a9fdc8eea91bc0d89879523dd1959 (diff) | |
download | django_openstack_auth-31860107c305cc649a74335a3436cbc610be8ef9.tar.gz |
Adding django kwargs to login and logout views
The django.contrib.auth.views login and logout views take usefull parameters
which where dropped by the openstack_auth.views methods.
Added a TOKEN_TIMEOUT_MARGIN which allows to check token expiration minus a
time margin in seconds. This is usefull if you know a process will take a
certain time, you want to have your token still valid all this time (e.g. the
time it can take to render a view).
This patch is required for https://review.openstack.org/88220
Change-Id: I7508c40d6f1eaa2bf1eef5cc762052b15d6d9273
Closes-Bug: 1308918
-rw-r--r-- | openstack_auth/backend.py | 4 | ||||
-rw-r--r-- | openstack_auth/user.py | 43 | ||||
-rw-r--r-- | openstack_auth/utils.py | 31 | ||||
-rw-r--r-- | openstack_auth/views.py | 34 |
4 files changed, 86 insertions, 26 deletions
diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py index 88121d5..f941ad3 100644 --- a/openstack_auth/backend.py +++ b/openstack_auth/backend.py @@ -36,8 +36,8 @@ class KeystoneBackend(object): ``django.contrib.auth``. """ - def check_auth_expiry(self, auth_ref): - if not utils.check_token_expiration(auth_ref): + def check_auth_expiry(self, auth_ref, margin=None): + if not utils.is_token_valid(auth_ref, margin): msg = _("The authentication token issued by the Identity service " "has expired.") LOG.warning("The authentication token issued by the Identity " diff --git a/openstack_auth/user.py b/openstack_auth/user.py index 0fb368b..84844ef 100644 --- a/openstack_auth/user.py +++ b/openstack_auth/user.py @@ -194,27 +194,56 @@ class User(models.AnonymousUser): def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.username) - def is_token_expired(self): + def is_token_expired(self, margin=None): """Determine if the token is expired. Returns ``True`` if the token is expired, ``False`` if not, and ``None`` if there is no token set. + + .. param:: margin + + A security time margin in seconds before real expiration. + Will return ``True`` if the token expires in less than ``margin`` + seconds of time. + A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the + django settings. + """ if self.token is None: return None - return not utils.check_token_expiration(self.token) + return not utils.is_token_valid(self.token, margin) + + def is_authenticated(self, margin=None): + """Checks for a valid authentication. + + .. param:: margin - def is_authenticated(self): - """Checks for a valid token that has not yet expired.""" + A security time margin in seconds before end of authentication. + Will return ``False`` if authentication ends in less than ``margin`` + seconds of time. + A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the + django settings. + + """ return (self.token is not None and - utils.check_token_expiration(self.token)) + utils.is_token_valid(self.token, margin)) - def is_anonymous(self): + def is_anonymous(self, margin=None): """Return if the user is not authenticated. Returns ``True`` if not authenticated,``False`` otherwise. + + .. param:: margin + + A security time margin in seconds before end of an eventual + authentication. + Will return ``True`` even if authenticated but that authentication + ends in less than ``margin`` seconds of time. + A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the + django settings. + """ - return not self.is_authenticated() + return not self.is_authenticated(margin) @property def is_active(self): diff --git a/openstack_auth/utils.py b/openstack_auth/utils.py index a8c2ff5..f41985c 100644 --- a/openstack_auth/utils.py +++ b/openstack_auth/utils.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import datetime import functools from six.moves.urllib import parse as urlparse @@ -28,6 +29,7 @@ from keystoneclient.v3 import client as client_v3 _PROJECT_CACHE = {} +_TOKEN_TIMEOUT_MARGIN = getattr(settings, 'TOKEN_TIMEOUT_MARGIN', 0) """ We need the request object to get the user, so we'll slightly modify the @@ -65,21 +67,36 @@ def patch_middleware_get_user(): """ End Monkey-Patching. """ -def check_token_expiration(token): +def is_token_valid(token, margin=None): """Timezone-aware checking of the auth token's expiration timestamp. Returns ``True`` if the token has not yet expired, otherwise ``False``. + + .. param:: token + + The openstack_auth.user.Token instance to check + + .. param:: margin + + A time margin in seconds to subtract from the real token's validity. + An example usage is that the token can be valid once the middleware + passed, and invalid (timed-out) during a view rendering and this + generates authorization errors during the view rendering. + A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the + django settings. """ expiration = token.expires - if settings.USE_TZ and timezone.is_naive(expiration): - # Presumes that the Keystone is using UTC. - expiration = timezone.make_aware(expiration, timezone.utc) # In case we get an unparseable expiration timestamp, return False # so you can't have a "forever" token just by breaking the expires param. - if expiration: - return expiration > timezone.now() - else: + if expiration is None: return False + if margin is None: + margin = getattr(settings, 'TOKEN_TIMEOUT_MARGIN', 0) + expiration = expiration - datetime.timedelta(seconds=margin) + if settings.USE_TZ and timezone.is_naive(expiration): + # Presumes that the Keystone is using UTC. + expiration = timezone.make_aware(expiration, timezone.utc) + return expiration > timezone.now() # From django.contrib.auth.views diff --git a/openstack_auth/views.py b/openstack_auth/views.py index 361d22f..00aff6a 100644 --- a/openstack_auth/views.py +++ b/openstack_auth/views.py @@ -48,7 +48,7 @@ LOG = logging.getLogger(__name__) @sensitive_post_parameters() @csrf_protect @never_cache -def login(request): +def login(request, template_name=None, extra_context=None, **kwargs): """Logs a user in using the :class:`~openstack_auth.forms.Login` form.""" # If the user is already authenticated, redirect them to the # dashboard straight away, unless the 'next' parameter is set as it @@ -78,18 +78,21 @@ def login(request): else: form = functional.curry(forms.Login, initial=initial) - extra_context = {'redirect_field_name': auth.REDIRECT_FIELD_NAME} + if extra_context is None: + extra_context = {'redirect_field_name': auth.REDIRECT_FIELD_NAME} - if request.is_ajax(): - template_name = 'auth/_login.html' - extra_context['hide'] = True - else: - template_name = 'auth/login.html' + if not template_name: + if request.is_ajax(): + template_name = 'auth/_login.html' + extra_context['hide'] = True + else: + template_name = 'auth/login.html' res = django_auth_views.login(request, template_name=template_name, authentication_form=form, - extra_context=extra_context) + extra_context=extra_context, + **kwargs) # Set the session data here because django's session key rotation # will erase it if we set it earlier. if request.user.is_authenticated(): @@ -102,7 +105,17 @@ def login(request): return res -def logout(request): +def logout(request, login_url=None, **kwargs): + """Logs out the user if he is logged in. Then redirects to the log-in page. + + .. param:: login_url + + Once logged out, defines the URL where to redirect after login + + .. param:: kwargs + see django.contrib.auth.views.logout_then_login extra parameters. + + """ msg = 'Logging out user "%(username)s".' % \ {'username': request.user.username} LOG.info(msg) @@ -111,7 +124,8 @@ def logout(request): if token and endpoint: delete_token(endpoint=endpoint, token_id=token.id) """ Securely logs a user out. """ - return django_auth_views.logout_then_login(request) + return django_auth_views.logout_then_login(request, login_url=login_url, + **kwargs) def delete_token(endpoint, token_id): |