middleware.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #!/usr/bin/env python
  2. # Licensed to Cloudera, Inc. under one
  3. # or more contributor license agreements. See the NOTICE file
  4. # distributed with this work for additional information
  5. # regarding copyright ownership. Cloudera, Inc. licenses this file
  6. # to you under the Apache License, Version 2.0 (the
  7. # "License"); you may not use this file except in compliance
  8. # with the License. You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing, software
  13. # distributed under the License is distributed on an "AS IS" BASIS,
  14. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. # See the License for the specific language governing permissions and
  16. # limitations under the License.
  17. import logging
  18. from datetime import datetime
  19. from django.contrib import messages
  20. from django.contrib.auth.models import User
  21. from django.contrib.sessions.models import Session
  22. from django.db import DatabaseError
  23. from django.db.models import Q
  24. from django.utils.translation import ugettext as _
  25. from desktop.auth.views import dt_logout
  26. from desktop.conf import AUTH, LDAP, SESSION
  27. from models import UserProfile, get_profile
  28. from views import import_ldap_users
  29. import ldap_access
  30. LOG = logging.getLogger(__name__)
  31. class LdapSynchronizationMiddleware(object):
  32. """
  33. Synchronize against LDAP authority.
  34. """
  35. USER_CACHE_NAME = 'ldap_use_group_sync_cache'
  36. def process_request(self, request):
  37. user = request.user
  38. server = None
  39. # Used by tests only
  40. if request.method == "GET":
  41. server = request.GET.get('server')
  42. if not user or not user.is_authenticated():
  43. return
  44. if not User.objects.filter(username=user.username, userprofile__creation_method=str(UserProfile.CreationMethod.EXTERNAL)).exists():
  45. LOG.warn("User %s is not an Ldap user" % user.username)
  46. return
  47. # Cache should be cleared when user logs out.
  48. if self.USER_CACHE_NAME not in request.session:
  49. if LDAP.LDAP_SERVERS.get():
  50. connection = ldap_access.get_connection_from_server(next(LDAP.LDAP_SERVERS.__iter__()))
  51. else:
  52. connection = ldap_access.get_connection_from_server()
  53. import_ldap_users(connection, user.username, sync_groups=True, import_by_dn=False, server=server)
  54. request.session[self.USER_CACHE_NAME] = True
  55. request.session.modified = True
  56. class LastActivityMiddleware(object):
  57. """
  58. Middleware to track the last activity of a user and automatically log out the user after a specified period of inactivity
  59. """
  60. def process_request(self, request):
  61. user = request.user
  62. if not user or not user.is_authenticated():
  63. return
  64. profile = get_profile(user)
  65. expires_after = AUTH.IDLE_SESSION_TIMEOUT.get()
  66. now = datetime.now()
  67. logout = False
  68. if profile.last_activity and expires_after > 0 and self._total_seconds(now - profile.last_activity) > expires_after:
  69. logout = True
  70. # Save last activity for user except when polling
  71. if not (request.path.strip('/') == 'jobbrowser/jobs' and request.POST.get('format') == 'json') and not (request.path == '/desktop/debug/is_idle'):
  72. try:
  73. profile.last_activity = datetime.now()
  74. profile.save()
  75. except DatabaseError:
  76. LOG.exception('Error saving profile information')
  77. if logout:
  78. dt_logout(request, next_page='/')
  79. def _total_seconds(self, dt):
  80. # Keep backward compatibility with Python 2.6 which doesn't support total_seconds()
  81. if hasattr(dt, 'total_seconds'):
  82. return dt.total_seconds()
  83. else:
  84. return (dt.microseconds + (dt.seconds + dt.days * 24 * 3600) * 10**6) / 10**6
  85. class ConcurrentUserSessionMiddleware(object):
  86. """
  87. Middleware that remove concurrent user sessions when configured
  88. """
  89. def process_response(self, request, response):
  90. try:
  91. user = request.user
  92. except AttributeError: # When the request does not store user. We care only about the login request which does store the user.
  93. return response
  94. if request.user.is_authenticated() and request.session.modified and request.user.id: # request.session.modified checks if a user just logged in
  95. limit = SESSION.CONCURRENT_USER_SESSION_LIMIT.get()
  96. if limit:
  97. count = 1;
  98. for session in Session.objects.filter(~Q(session_key=request.session.session_key), expire_date__gte=datetime.now()).order_by('-expire_date'):
  99. data = session.get_decoded()
  100. if data.get('_auth_user_id') == request.user.id:
  101. if count >= limit:
  102. LOG.info('Expiring concurrent user session %s' % request.user.username)
  103. session.expire_date = datetime.now()
  104. session.save()
  105. else:
  106. count += 1
  107. return response