text: #!/usr/bin/env python
  # Licensed to Cloudera, Inc. under one
  # or more contributor license agreements.  See the NOTICE file
  # distributed with this work for additional information
  # regarding copyright ownership.  Cloudera, Inc. licenses this file
  # to you under the Apache License, Version 2.0 (the
  # "License"); you may not use this file except in compliance
  # with the License.  You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  from __future__ import division
  from __future__ import absolute_import
  from builtins import next
  from builtins import object
  import logging
  import math
  from datetime import datetime
  
  from django.contrib import messages
  from django.contrib.sessions.models import Session
  from django.db import DatabaseError
  from django.db.models import Q
  from django.utils.translation import ugettext as _
  
  from desktop.auth.views import dt_logout
  from desktop.conf import AUTH, LDAP, SESSION
  from desktop.lib.security_util import get_localhost_name
  
  from useradmin import ldap_access
  from useradmin.models import UserProfile, get_profile, User
  from useradmin.views import import_ldap_users
  
  
  LOG = logging.getLogger(__name__)
  
  
  class LdapSynchronizationMiddleware(object):
    """
    Synchronize against LDAP authority.
    """
    USER_CACHE_NAME = 'ldap_use_group_sync_cache'
  
    def process_request(self, request):
      user = request.user
      server = None
  
      # Used by tests only
      if request.method == "GET":
        server = request.GET.get('server')
  
      if not user or not user.is_authenticated:
        return
  
      if not User.objects.filter(username=user.username, userprofile__creation_method=UserProfile.CreationMethod.EXTERNAL.name).exists():
        LOG.warn("User %s is not an Ldap user" % user.username)
        return
  
      # Cache should be cleared when user logs out.
      if self.USER_CACHE_NAME not in request.session:
        if LDAP.LDAP_SERVERS.get():
          connection = ldap_access.get_connection_from_server(next(LDAP.LDAP_SERVERS.__iter__()))
        else:
          connection = ldap_access.get_connection_from_server()
  
        import_ldap_users(connection, user.username, sync_groups=True, import_by_dn=False, server=server)
  
        request.session[self.USER_CACHE_NAME] = True
        request.session.modified = True
  
  
  class LastActivityMiddleware(object):
    """
    Middleware to track the last activity of a user and automatically log out the user after a specified period of inactivity
    """
  
    def process_request(self, request):
      user = request.user
  
      if not user or not user.is_authenticated:
        return
  
      profile = get_profile(user)
      expires_after = AUTH.IDLE_SESSION_TIMEOUT.get()
      now = datetime.now()
      logout = False
  
      if profile.last_activity and expires_after > 0 and self._total_seconds(now - profile.last_activity) > expires_after:
        logout = True
  
      # Save last activity for user except when polling
      if not (request.path.strip('/') == 'notebook/api/check_status') \
          and not (request.path.strip('/').startswith('jobbrowser/api/job')) \
          and not (request.path.strip('/') == 'jobbrowser/jobs' and request.POST.get('format') == 'json') \
          and not (request.path.strip('/') == 'desktop/debug/is_idle') \
          and not (request.path.strip('/').startswith('oozie/list_oozie_')):
        try:
          profile.last_activity = datetime.now()
          profile.hostname = get_localhost_name()
          profile.save()
        except DatabaseError:
          LOG.exception('Error saving profile information')
  
      if logout:
        dt_logout(request, next_page='/')
  
  
    def _total_seconds(self, dt):
      # Keep backward compatibility with Python 2.6 which doesn't support total_seconds()
      if hasattr(dt, 'total_seconds'):
        return dt.total_seconds()
      else:
        return math.floor((dt.microseconds + (dt.seconds + dt.days * 24 * 3600) * 10**6) / 10**6)
  
  class ConcurrentUserSessionMiddleware(object):
    """
    Middleware that remove concurrent user sessions when configured
    """
    def process_response(self, request, response):
      try:
        user = request.user
      except AttributeError: # When the request does not store user. We care only about the login request which does store the user.
        return response
  
      # request.session.modified checks if a user just logged in
      if request.user.is_authenticated and request.session.modified and request.user.id:
        limit = SESSION.CONCURRENT_USER_SESSION_LIMIT.get()
        if limit:
          count = 1
          for session in Session.objects.filter(~Q(session_key=request.session.session_key),
              expire_date__gte=datetime.now()).order_by('-expire_date'):
            data = session.get_decoded()
            if data.get('_auth_user_id') == str(request.user.id):
              if count >= limit:
                LOG.info('Expiring concurrent user session %s' % request.user.username)
                session.expire_date = datetime.now()
                session.save()
              else:
                count += 1
      return response
  