summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYves-Gwenael Bourhis <yves-gwenael.bourhis@cloudwatt.com>2014-06-20 13:43:24 +0200
committerYves-Gwenael Bourhis <yves-gwenael.bourhis@cloudwatt.com>2014-09-12 16:49:45 +0200
commit31860107c305cc649a74335a3436cbc610be8ef9 (patch)
tree4ada06ba71463eea9afecf99fcdedd9adb923c3b
parent5c8b0c78f28a9fdc8eea91bc0d89879523dd1959 (diff)
downloaddjango_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.py4
-rw-r--r--openstack_auth/user.py43
-rw-r--r--openstack_auth/utils.py31
-rw-r--r--openstack_auth/views.py34
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):