text: from collections import OrderedDict
  from fnmatch import fnmatch
  import logging
  
  from django.conf import settings
  from django.contrib.auth.middleware import RemoteUserMiddleware
  from django.core.exceptions import ImproperlyConfigured
  from django.core.urlresolvers import reverse
  from django.http import HttpResponseRedirect
  from seaserv import seafile_api
  
  from shibboleth.app_settings import SHIB_ATTRIBUTE_MAP, LOGOUT_SESSION_KEY, SHIB_USER_HEADER
  
  from seahub import auth
  from seahub.base.accounts import User
  from seahub.base.sudo_mode import update_sudo_mode_ts
  from seahub.profile.models import Profile
  from seahub.utils.file_size import get_quota_from_string
  from seahub.utils.user_permissions import get_user_role
  
  # Get an instance of a logger
  logger = logging.getLogger(__name__)
  
  
  class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware):
      """
      Authentication Middleware for use with Shibboleth.  Uses the recommended pattern
      for remote authentication from: http://code.djangoproject.com/svn/django/tags/releases/1.3/django/contrib/auth/middleware.py
      """
      def __init__(self, *a, **kw):
          super(ShibbolethRemoteUserMiddleware, self).__init__(*a, **kw)
  
      def process_request(self, request):
          # AuthenticationMiddleware is required so that request.user exists.
          if not hasattr(request, 'user'):
              raise ImproperlyConfigured(
                  "The Django remote user auth middleware requires the"
                  " authentication middleware to be installed.  Edit your"
                  " MIDDLEWARE_CLASSES setting to insert"
                  " 'django.contrib.auth.middleware.AuthenticationMiddleware'"
                  " before the RemoteUserMiddleware class.")
  
          #To support logout.  If this variable is True, do not
          #authenticate user and return now.
          if request.session.get(LOGOUT_SESSION_KEY) is True:
              return
          else:
              #Delete the shib reauth session key if present.
              request.session.pop(LOGOUT_SESSION_KEY, None)
  
          #Locate the remote user header.
          # import pprint; pprint.pprint(request.META)
          try:
              username = request.META[SHIB_USER_HEADER]
          except KeyError:
              # If specified header doesn't exist then return (leaving
              # request.user set to AnonymousUser by the
              # AuthenticationMiddleware).
              return
  
          # If the user is already authenticated and that user is the user we are
          # getting passed in the headers, then the correct user is already
          # persisted in the session and we don't need to continue.
          if request.user.is_authenticated():
              if request.user.username == username:
                  if request.user.is_staff:
                      update_sudo_mode_ts(request)
                  return
  
          # Make sure we have all required Shiboleth elements before proceeding.
          shib_meta, error = self.parse_attributes(request)
          # Add parsed attributes to the session.
          request.session['shib'] = shib_meta
          if error:
              raise ShibbolethValidationError("All required Shibboleth elements"
                                              " not found.  %s" % shib_meta)
  
          # We are seeing this user for the first time in this session, attempt
          # to authenticate the user.
          user = auth.authenticate(remote_user=username, shib_meta=shib_meta)
          if user:
              if not user.is_active:
                  return HttpResponseRedirect(reverse('shib_complete'))
  
              # User is valid.  Set request.user and persist user in the session
              # by logging the user in.
              request.user = user
              auth.login(request, user)
              user.set_unusable_password()
              user.save()
              # call make profile.
              self.make_profile(user, shib_meta)
              user_role = self.update_user_role(user, shib_meta)
              if user_role:
                  self.update_user_quota(user, user_role)
              #setup session.
              self.setup_session(request)
              request.shib_login = True
  
      def process_response(self, request, response):
          if getattr(request, 'shib_login', False):
              print '%s: set shibboleth cookie!' % id(self)
              self._set_auth_cookie(request, response)
          return response
  
      def _set_auth_cookie(self, request, response):
          from seahub.api2.utils import get_token_v1, get_token_v2
          # generate tokenv2 using information in request params
          keys = (
              'platform',
              'device_id',
              'device_name',
              'client_version',
              'platform_version',
          )
          if all(['shib_' + key in request.GET for key in keys]):
              platform = request.GET['shib_platform']
              device_id = request.GET['shib_device_id']
              device_name = request.GET['shib_device_name']
              client_version = request.GET['shib_client_version']
              platform_version = request.GET['shib_platform_version']
              token = get_token_v2(
                  request, request.user.username, platform, device_id,
                  device_name, client_version, platform_version)
          elif all(['shib_' + key not in request.GET for key in keys]):
              token = get_token_v1(request.user.username)
          else:
              return
          response.set_cookie('seahub_auth', request.user.username + '@' + token.key)
  
      def make_profile(self, user, shib_meta):
          """
          Extrat nickname(givenname surname), contact_email, institution from
          Shib attributs, and add those to user profile.
          """
          # use `display_name` as nickname in shib_meta first
          nickname = shib_meta.get('display_name', None)
          if nickname is None:
              # otherwise, fallback to givenname plus surname in shib_meta
              givenname = shib_meta.get('givenname', '')
              surname = shib_meta.get('surname', '')
              nickname = "%s %s" % (givenname, surname)
  
          institution = shib_meta.get('institution', None)
          contact_email = shib_meta.get('contact_email', None)
  
          p = Profile.objects.get_profile_by_user(user.username)
          if not p:
              p = Profile(user=user.username)
  
          if nickname.strip():  # set nickname when it's not empty
              p.nickname = nickname
  
          if institution:
              p.institution = institution
          if contact_email:
              p.contact_email = contact_email
  
          p.save()
  
      def _get_role_by_affiliation(self, affiliation):
          try:
              role_map = settings.SHIBBOLETH_AFFILIATION_ROLE_MAP
          except AttributeError:
              return
  
          role = role_map.get(affiliation)
          if role:
              return role
  
          if role_map.get('patterns') is not None:
              joker_map = role_map.get('patterns')
              try:
                  od = OrderedDict(joker_map)
              except Exception as e:
                  logger.error(e)
                  return
  
              for k in od:
                  if fnmatch(affiliation, k):
                      return od[k]
  
          return None
  
      def update_user_role(self, user, shib_meta):
          affiliation = shib_meta.get('affiliation', '')
          if not affiliation:
              return
  
          for e in affiliation.split(';'):
              role = self._get_role_by_affiliation(e)
              if role:
                  User.objects.update_role(user.email, role)
                  return role
  
      def update_user_quota(self, user, user_role):
          if user.permissions.role_quota():
              quota = get_quota_from_string(user.permissions.role_quota())
              logger.info('Set quota[%d] for user: %s, role[%s]' % (quota, user.username, user_role))
              seafile_api.set_role_quota(user_role, quota)
          else:
              return
  
      def setup_session(self, request):
          """
          If you want to add custom code to setup user sessions, you
          can extend this.
          """
          return
  
      def parse_attributes(self, request):
          """
          Parse the incoming Shibboleth attributes.
          From: https://github.com/russell/django-shibboleth/blob/master/django_shibboleth/utils.py
          Pull the mapped attributes from the apache headers.
          """
          shib_attrs = {}
          error = False
          meta = request.META
          for header, attr in SHIB_ATTRIBUTE_MAP.items():
              required, name = attr
              value = meta.get(header, None)
              shib_attrs[name] = value
              if not value or value == '':
                  if required:
                      error = True
          return shib_attrs, error
  
  class ShibbolethValidationError(Exception):
      pass
  