1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-02 07:47:32 +00:00
seahub/thirdpart/shibboleth/middleware.py
sniper-py 99a9ece04e Python3 master (#4076)
* delete thridpart/social_django

* delete social_django in seahub/urls.py

* delete social_django in seahub/settings.py

* delete seahub/notifications/management/commands/send_wxwork_notices.py

* delete social_django in code annotation

* delete seahub/social_core

* delete tests/seahub/social_core

* delete social_core in seahub/urls.py

* delete social_core in seahub/settings.py

* change app_label to auth in SocialAuthUser model

* 2to3 asserts

* 2to3 basestring

* 2to3 dict

* 2to3 except

* 2to3 filter

* 2to3 future

* 2to3 has_key

* 2to3 idioms

* 2to3 import

* 2to3 imports

* 2to3 long

* 2to3 map

* 2to3 next

* 2to3 numliterals

* 2to3 print

* 2to3 raise

* 2to3 raw_input

* 2to3 reduce

* 2to3 reload

* 2to3 set_literal

* 2to3 unicode

* 2to3 urllib

* 2to3 ws_comma

* 2to3 xrange

* 2to3 zip

* add pymysql in __init__.py

* fix encode and decode in seahub/cconvert.py

* fix seafserv_rpc.is_passwd_set in seahub/views/__init__.py

* fix smart_unicode to smart_text

* fix force_unicode to force_text

* delete seaserv.get_session_info

* delete seaserv.ccnet_rpc

* fix indent error in seahub/auth/middleware.py

* update dev-requirements

* update test-requirements

* update requirements

* fix StringIO to BytesIO in thumbnail

* fix seaserv.list_inner_pub_repos to seafile_api.get_inner_pub_repo_list

* fix seaserv.list_org_inner_pub_repos to seafile_api.list_org_inner_pub_repos

* add logger in seahub/utils/__init__.py

* fix sort cmp in seahub/views/__init__.py

* fix sort cmp in seahub/base/management/commands/export_file_access_log.py

* fix sort cmp in seahub/api2/endpoints/repo_trash.py

* fix sort cmp in seahub/api2/endpoints/shared_repos.py

* fix sort cmp in seahub/api2/endpoints/shared_folders.py

* fix sort cmp in seahub/wiki/views.py

* fix sort cmp in seahub/api2/endpoints/wiki_pages.py

* fix sort cmp in seahub/api2/endpoints/group_libraries.py

* fix sort cmp in seahub/base/models.py

* fix sort cmp in seahub/api2/endpoints/upload_links.py

* fix sort cmp in seahub/views/ajax.py

* fix sort cmp in seahub/api2/views.py

* fix sort cmp in seahub/views/wiki.py

* fix sort cmp in seahub/api2/endpoints/repos.py

* fix sort cmp in seahub/api2/endpoints/starred_items.py

* fix sort cmp in seahub/views/file.py

* fix sort cmp in seahub/api2/endpoints/dir.py

* fix sort cmp in seahub/api2/endpoints/share_links.py

* fix cmp to cmp_to_key in seahub/api2/endpoints/admin/device_trusted_ip.py

* fix cmp to cmp_to_key in tests/api/endpoints/admin/test_device_trusted_ip.py

* delete encode('utf-8') in seafile_api.list_dir_by_commit_and_path

* delete encode('utf-8') in is_file_starred

* delete encode('utf-8') in seafile_api.list_dir_by_path

* delete path.encode('utf-8') in seahub/views/file.py

* fix os.write to add encode('utf-8')

* add encode('utf-8') for hashlib

* add encode('utf-8') for hmac

* fix with open(file, 'wb') for binary file

* fix encode and decode in seahub/utils/hasher.py

* fix next in thirdpart/shibboleth/views.py

* fix next in seahub/profile/views.py

* fix next in seahub/notifications/views.py

* fix next in seahub/institutions/views.py

* fix next in seahub/options/views.py

* fix next in seahub/share/views.py

* fix next in seahub/avatar/views.py

* fix next in seahub/views/__init__.py

* fix next in seahub/group/views.py

* fix next in seahub/views/wiki.py

* fix next in seahub/views/sysadmin.py

* fix next in seahub/views/file.py

* fix string.lowercase to string.ascii_lowercase in test

* fix open file add 'rb' in test

* fix self.user.username in test

* add migrations in file_participants

* fix list_org_inner_pub_repos to list_org_inner_pub_repos_by_owner

* fix from seaserv import is_passwd_set to seafile_api.is_password_set

* fix assert bytes resp.content in test

* fix seafile_api.get_inner_pub_repo_list to seafile_api.list_inner_pub_repos_by_owner

* fix seafile_api.is_passwd_set to seafile_api.is_password_set

* fix AccountsApiTest assert length

* rewrite sort_devices cmp to operator.lt

* fix bytes + str in seahub/api2/views.py

* fix assert bytes resp.content in test

* fix hashlib encode in seahub/thirdpart/registration/models.py

* change app_label to base in SocialAuthUser

* fix base64 encode in seahub/base/database_storage/database_storage.py

* fix assert bytes resp.content

* remove path.decode in def mkstemp()

* remove path.decode in FpathToLinkTest

* remove str decode in FileTagTest

* remove mock_write_xls.assert_called_once() in SysUserAdminExportExcelTest

* fix urllib assert in FilesApiTest

* fix link fields in FileCommentsTest

* fix get_related_users_by_repo()

* fix assert list in GetRepoSharedUsersTest

* fix create user in AccountTest

* fix repeated key in dict seahub/api2/views.py

* add drone.yml

* update nginx conf in test

* update test conf in test

* update dist and push after test success

* update drone conf to dist and push

* fix assert in BeSharedReposTest

* fix seafile_api.list_org_inner_pub_repos_by_owner(org_id, username) to seafile_api.list_org_inner_pub_repos(org_id)

* fix seafile_api.list_inner_pub_repos_by_owner(username) to seafile_api.get_inner_pub_repo_list()

* update pyjwt requirement

* update dist branch in drone

* add SKIP in dist and push

* fix StringIO to BytesIO in seahub/avatar/models.py

* fix if org_id > 0 to if org_id and org_id > 0

* remove payment

* fix StringIO to BytesIO in seahub/base/database_storage/database_storage.py

* fix send_message to seafile_api.publish_event in seahub/drafts/utils.py

* fix send_message to seafile_api.publish_event in seahub/api2/views.py

* fix send_message to seafile_api.publish_event in seahub/api2/endpoints/repos.py

* fix send_message to seafile_api.publish_event in seahub/views/file.py

* fix send_message to seafile_api.publish_event in seahub/utils/__init__.py

* fix image_file.read encode in seahub/base/database_storage/database_storage.py

* fix DatabaseStorageTest

* remove .travis.yml

* drone branch include master
2019-09-11 11:46:43 +08:00

238 lines
9.0 KiB
Python
Executable File

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, ccnet_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):
if request.path.rstrip('/') != settings.SITE_ROOT + 'sso':
return
# 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
p_id = ccnet_api.get_primary_id(username)
if p_id is not None:
username = p_id
# 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 list(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