mirror of
https://github.com/haiwen/seahub.git
synced 2025-05-11 17:34:56 +00:00
Improve login and create user (#5458)
* add create oauth/ldap/saml user in UserManager * improve admin add/import users * improve dingtalk/weixin/work_weixin login/create user * improve saml login/create user * improve oauth login/create user * login ldap user in seahub * improve invite user * fix code * fix github test action * fix test * fix saml login * optimize code * specify the version of python-ldap * fix code * improve code * add get_old_user * optimize oauth login code * optimize code * remove LDAP_USER_UNIQUE_ID * remove test_primary_id * improve authenticate user * improve saml login * optimize code
This commit is contained in:
parent
42773a692d
commit
532fa5ef8c
.github/workflows
requirements.txtseahub
adfs_auth
api2/endpoints
auth
avatar
base
dingtalk
django_cas_ng
group/tests
invitations
krb5_auth
oauth
organizations/api/admin
settings.pytest_utils.pyviews
weixin
work_weixin
tests
api
seahub
auth/forms
base
thirdpart/registration
views
thirdpart
2
.github/workflows/dist.yml
vendored
2
.github/workflows/dist.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- name: gettext for django
|
||||
run: |
|
||||
sudo apt-get install gettext python3-wheel libjwt-dev
|
||||
sudo apt-get install gettext python3-wheel libjwt-dev libsasl2-dev libldap2-dev
|
||||
sudo rm -rf /usr/lib/python3/dist-packages/pytz/
|
||||
|
||||
- name: Build dist branch
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
sudo apt-get install -y uuid-dev intltool libsqlite3-dev build-essential
|
||||
sudo apt-get install -y libarchive-dev libtool libjansson-dev valac
|
||||
sudo apt-get install -y libfuse-dev cmake re2c flex sqlite3
|
||||
sudo apt-get install -y libssl-dev libldap2-dev libonig-dev
|
||||
sudo apt-get install -y libssl-dev libsasl2-dev libldap2-dev libonig-dev
|
||||
sudo apt-get install -y libxml2 libxml2-dev libjwt-dev
|
||||
|
||||
- name: clone and build
|
||||
|
@ -24,3 +24,4 @@ captcha==0.4
|
||||
openpyxl==3.0.*
|
||||
Markdown==3.4.*
|
||||
bleach==5.0.*
|
||||
python-ldap==3.4.*
|
||||
|
@ -24,6 +24,7 @@ from django.contrib.auth.backends import ModelBackend
|
||||
from seaserv import ccnet_api, seafile_api
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
from seahub.profile.models import Profile, DetailedProfile
|
||||
from seahub.utils.file_size import get_quota_from_string
|
||||
from seahub.role_permissions.utils import get_enabled_role_permissions_by_role
|
||||
@ -31,18 +32,12 @@ from registration.models import notify_admins_on_activate_request, notify_admins
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SAML_PROVIDER_IDENTIFIER = getattr(settings, 'SAML_PROVIDER_IDENTIFIER', '')
|
||||
SHIBBOLETH_AFFILIATION_ROLE_MAP = getattr(settings, 'SHIBBOLETH_AFFILIATION_ROLE_MAP', False)
|
||||
|
||||
|
||||
class Saml2Backend(ModelBackend):
|
||||
|
||||
def get_user(self, username):
|
||||
try:
|
||||
user = User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
return user
|
||||
|
||||
def authenticate(self, session_info=None, attribute_mapping=None, create_unknown_user=True, **kwargs):
|
||||
if session_info is None or attribute_mapping is None:
|
||||
logger.error('Session info or attribute mapping are None')
|
||||
@ -54,59 +49,59 @@ class Saml2Backend(ModelBackend):
|
||||
|
||||
attributes = session_info['ava']
|
||||
if not attributes:
|
||||
logger.error('The attributes dictionary is empty')
|
||||
logger.warning('The attributes dictionary is empty')
|
||||
|
||||
logger.debug('attributes: %s', attributes)
|
||||
saml_user = None
|
||||
if session_info.get('name_id'):
|
||||
logger.debug('name_id: %s', session_info['name_id'])
|
||||
saml_user = session_info['name_id'].text
|
||||
else:
|
||||
logger.error('The nameid is not available. Cannot find user without a nameid.')
|
||||
|
||||
if saml_user is None:
|
||||
logger.error('Could not determine user identifier')
|
||||
name_id = session_info.get('name_id', '')
|
||||
if not name_id:
|
||||
logger.error('The name_id is not available. Could not determine user identifier.')
|
||||
return None
|
||||
name_id = name_id.text
|
||||
|
||||
main_attribute = self.clean_user_main_attribute(saml_user)
|
||||
|
||||
# check if user exist in local ccnet db/ldapimport database
|
||||
username = main_attribute
|
||||
local_ccnet_users = ccnet_api.search_emailusers('DB', username, -1, -1)
|
||||
if not local_ccnet_users:
|
||||
local_ccnet_users = ccnet_api.search_emailusers('LDAP', username, -1, -1)
|
||||
|
||||
if not local_ccnet_users:
|
||||
if create_unknown_user:
|
||||
activate_after_creation = getattr(settings, 'SAML_ACTIVATE_USER_AFTER_CREATION', True)
|
||||
user = User.objects.create_user(email=username, is_active=activate_after_creation)
|
||||
# create org user
|
||||
url_prefix = kwargs.get('url_prefix', None)
|
||||
if url_prefix:
|
||||
org = ccnet_api.get_org_by_url_prefix(url_prefix)
|
||||
if org:
|
||||
org_id = org.org_id
|
||||
ccnet_api.add_org_user(org_id, username, 0)
|
||||
|
||||
if not activate_after_creation:
|
||||
notify_admins_on_activate_request(username)
|
||||
elif settings.NOTIFY_ADMIN_AFTER_REGISTRATION:
|
||||
notify_admins_on_register_complete(username)
|
||||
|
||||
else:
|
||||
saml_user = SocialAuthUser.objects.get_by_provider_and_uid(SAML_PROVIDER_IDENTIFIER, name_id)
|
||||
if saml_user:
|
||||
try:
|
||||
user = User.objects.get(email=saml_user.username)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
if not user:
|
||||
# Means found user in social_auth_usersocialauth but not found user in EmailUser,
|
||||
# delete it and recreate one.
|
||||
logger.warning('The DB data is invalid, delete it and recreate one.')
|
||||
SocialAuthUser.objects.filter(provider=SAML_PROVIDER_IDENTIFIER, uid=name_id).delete()
|
||||
else:
|
||||
user = User.objects.get(email=username)
|
||||
# compatible with old users via name_id
|
||||
try:
|
||||
user = User.objects.get_old_user(name_id, SAML_PROVIDER_IDENTIFIER, name_id)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
|
||||
if not user and create_unknown_user:
|
||||
activate_after_creation = getattr(settings, 'SAML_ACTIVATE_USER_AFTER_CREATION', True)
|
||||
try:
|
||||
user = User.objects.create_saml_user(is_active=activate_after_creation)
|
||||
SocialAuthUser.objects.add(user.username, SAML_PROVIDER_IDENTIFIER, name_id)
|
||||
except Exception as e:
|
||||
logger.error(f'create saml user failed. {e}')
|
||||
return None
|
||||
|
||||
# create org user
|
||||
url_prefix = kwargs.get('url_prefix', None)
|
||||
if url_prefix:
|
||||
org = ccnet_api.get_org_by_url_prefix(url_prefix)
|
||||
if org:
|
||||
org_id = org.org_id
|
||||
ccnet_api.add_org_user(org_id, user.username, 0)
|
||||
|
||||
if not activate_after_creation:
|
||||
notify_admins_on_activate_request(user.username)
|
||||
elif settings.NOTIFY_ADMIN_AFTER_REGISTRATION:
|
||||
notify_admins_on_register_complete(user.username)
|
||||
|
||||
if user:
|
||||
self.make_profile(user, attributes, attribute_mapping)
|
||||
|
||||
return user
|
||||
|
||||
def clean_user_main_attribute(self, main_attribute):
|
||||
"""Hook to clean the extracted user-identifying value. No-op by default."""
|
||||
return main_attribute
|
||||
|
||||
def update_user_role(self, user, parse_result):
|
||||
role = parse_result.get('role', '')
|
||||
if role:
|
||||
|
@ -11,7 +11,7 @@ from django.utils.translation import gettext as _
|
||||
|
||||
from seaserv import ccnet_api
|
||||
|
||||
from seahub.utils import render_error, get_service_url
|
||||
from seahub.utils import get_service_url
|
||||
from seahub.organizations.models import OrgSAMLConfig
|
||||
from seahub import settings
|
||||
|
||||
@ -24,6 +24,7 @@ if ENABLE_ADFS_LOGIN or ENABLE_MULTI_ADFS:
|
||||
XMLSEC_BINARY_PATH = getattr(settings, 'SAML_XMLSEC_BINARY_PATH', '/usr/bin/xmlsec1')
|
||||
CERTS_DIR = getattr(settings, 'SAML_CERTS_DIR', '/opt/seafile/seahub-data/certs')
|
||||
SAML_ATTRIBUTE_MAPPING = getattr(settings, 'SAML_ATTRIBUTE_MAPPING', {})
|
||||
SAML_PROVIDER_IDENTIFIER = getattr(settings, 'SAML_PROVIDER_IDENTIFIER', '')
|
||||
|
||||
|
||||
def settings_check(func):
|
||||
@ -33,18 +34,19 @@ def settings_check(func):
|
||||
logger.error('Feature not enabled.')
|
||||
error = True
|
||||
else:
|
||||
if not XMLSEC_BINARY_PATH or not CERTS_DIR or not SAML_ATTRIBUTE_MAPPING:
|
||||
if not XMLSEC_BINARY_PATH or not CERTS_DIR or not SAML_ATTRIBUTE_MAPPING or not SAML_PROVIDER_IDENTIFIER:
|
||||
logger.error('ADFS login relevant settings invalid.')
|
||||
logger.error('SAML_XMLSEC_BINARY_PATH: %s' % XMLSEC_BINARY_PATH)
|
||||
logger.error('SAML_CERTS_DIR: %s' % CERTS_DIR)
|
||||
logger.error('SAML_ATTRIBUTE_MAPPING: %s' % SAML_ATTRIBUTE_MAPPING)
|
||||
logger.error('SAML_PROVIDER_IDENTIFIER: %s' % SAML_PROVIDER_IDENTIFIER)
|
||||
error = True
|
||||
if ENABLE_ADFS_LOGIN and not REMOTE_METADATA_URL:
|
||||
logger.error('SAML relevant settings invalid.')
|
||||
logger.error('SAML_REMOTE_METADATA_URL: %s' % REMOTE_METADATA_URL)
|
||||
error = True
|
||||
if error:
|
||||
return render_error(request, _('Error, please contact administrator.'))
|
||||
raise Exception(_('Error, please contact administrator.'))
|
||||
return func(request)
|
||||
return _decorated
|
||||
|
||||
@ -66,7 +68,7 @@ def config_settings_loader(request):
|
||||
if org_id != -1:
|
||||
org_saml_config = OrgSAMLConfig.objects.get_config_by_org_id(org_id)
|
||||
if not org_saml_config:
|
||||
return render_error(request, 'Failed to get org %s saml_config' % org_id)
|
||||
raise Exception('Failed to get org %s saml_config' % org_id)
|
||||
|
||||
# get org remote_metadata_url
|
||||
remote_metadata_url = org_saml_config.metadata_url
|
||||
|
@ -294,6 +294,7 @@ class Account(APIView):
|
||||
return api_error(status.HTTP_520_OPERATION_FAILED,
|
||||
'Failed to update user.')
|
||||
|
||||
email = user.email
|
||||
try:
|
||||
# update account additional info
|
||||
self._update_account_additional_info(request, email)
|
||||
@ -324,6 +325,7 @@ class Account(APIView):
|
||||
return api_error(status.HTTP_520_OPERATION_FAILED,
|
||||
'Failed to add user.')
|
||||
|
||||
email = user.email
|
||||
try:
|
||||
# update account additional info
|
||||
self._update_account_additional_info(request, email)
|
||||
|
@ -21,7 +21,6 @@ from seahub.api2.utils import api_error
|
||||
from seahub.api2.permissions import IsProVersion
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.utils.auth import gen_user_virtual_id
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.avatar.models import Avatar
|
||||
@ -210,9 +209,9 @@ class AdminDingtalkUsersBatch(APIView):
|
||||
})
|
||||
continue
|
||||
|
||||
email = gen_user_virtual_id()
|
||||
try:
|
||||
User.objects.create_user(email)
|
||||
oauth_user = User.objects.create_oauth_user()
|
||||
email = oauth_user.username
|
||||
SocialAuthUser.objects.add(email, 'dingtalk', user_id)
|
||||
success.append({
|
||||
'userid': user_id,
|
||||
@ -226,6 +225,7 @@ class AdminDingtalkUsersBatch(APIView):
|
||||
'name': user.get('name'),
|
||||
'error_msg': '导入失败'
|
||||
})
|
||||
continue
|
||||
|
||||
try:
|
||||
update_dingtalk_user_info(email,
|
||||
@ -398,9 +398,9 @@ class AdminDingtalkDepartmentsImport(APIView):
|
||||
email = social_auth_queryset.get(uid=uid).username
|
||||
else:
|
||||
# create user
|
||||
email = gen_user_virtual_id()
|
||||
try:
|
||||
User.objects.create_user(email)
|
||||
oauth_user = User.objects.create_oauth_user()
|
||||
email = oauth_user.username
|
||||
SocialAuthUser.objects.add(email, 'dingtalk', uid)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
@ -215,7 +215,7 @@ class AdminOrgUsers(APIView):
|
||||
# add user to org
|
||||
# set `is_staff` parameter as `0`
|
||||
try:
|
||||
ccnet_api.add_org_user(org_id, email, 0)
|
||||
ccnet_api.add_org_user(org_id, user.email, 0)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error_msg = 'Internal Server Error'
|
||||
@ -223,10 +223,10 @@ class AdminOrgUsers(APIView):
|
||||
|
||||
name = request.POST.get('name', None)
|
||||
if name:
|
||||
Profile.objects.add_or_update(email, name)
|
||||
Profile.objects.add_or_update(user.email, name)
|
||||
|
||||
if config.FORCE_PASSWORD_CHANGE:
|
||||
UserOptions.objects.set_force_passwd_change(email)
|
||||
UserOptions.objects.set_force_passwd_change(user.email)
|
||||
|
||||
user_info = get_org_user_info(org_id, user)
|
||||
user_info['active'] = is_active
|
||||
|
@ -53,6 +53,7 @@ from seahub.admin_log.models import USER_DELETE, USER_ADD
|
||||
from seahub.api2.endpoints.group_owned_libraries import get_group_id_by_repo_owner
|
||||
from seahub.group.utils import group_id_to_name
|
||||
from seahub.institutions.models import InstitutionAdmin
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.share.models import FileShare, UploadLinkShare
|
||||
@ -621,11 +622,6 @@ class AdminUsers(APIView):
|
||||
error_msg = "Name should not include '/'."
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
contact_email = request.data.get('contact_email', None)
|
||||
if contact_email and not is_valid_email(contact_email):
|
||||
error_msg = 'contact_email invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
quota_total_mb = request.data.get("quota_total", None)
|
||||
if quota_total_mb:
|
||||
try:
|
||||
@ -646,8 +642,9 @@ class AdminUsers(APIView):
|
||||
error_msg = 'Failed to set quota: maximum quota is %d MB' % org_quota_mb
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
vid = get_virtual_id_by_email(email)
|
||||
try:
|
||||
User.objects.get(email=email)
|
||||
User.objects.get(email=vid)
|
||||
user_exist = True
|
||||
except User.DoesNotExist:
|
||||
user_exist = False
|
||||
@ -665,7 +662,7 @@ class AdminUsers(APIView):
|
||||
try:
|
||||
user_obj = User.objects.create_user(email, password, is_staff, is_active)
|
||||
create_user_info(request, email=user_obj.username, role=role,
|
||||
nickname=name, contact_email=contact_email,
|
||||
nickname=name, contact_email=email,
|
||||
quota_total_mb=quota_total_mb)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
@ -687,7 +684,7 @@ class AdminUsers(APIView):
|
||||
logger.error(str(e))
|
||||
add_user_tip = _('Successfully added user %(user)s. But email notification can not be sent, because Email service is not properly configured.') % {'user': email}
|
||||
|
||||
user_info = get_user_info(email)
|
||||
user_info = get_user_info(user_obj.username)
|
||||
user_info['add_user_tip'] = add_user_tip
|
||||
|
||||
# send admin operation log signal
|
||||
@ -698,7 +695,7 @@ class AdminUsers(APIView):
|
||||
operation=USER_ADD, detail=admin_op_detail)
|
||||
|
||||
if config.FORCE_PASSWORD_CHANGE:
|
||||
UserOptions.objects.set_force_passwd_change(email)
|
||||
UserOptions.objects.set_force_passwd_change(user_obj.email)
|
||||
|
||||
return Response(user_info)
|
||||
|
||||
|
@ -38,6 +38,7 @@ from seahub.base.models import UserLastLogin
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.role_permissions.utils import get_available_roles
|
||||
from seahub.utils.user_permissions import get_user_role
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -279,6 +280,7 @@ class AdminImportUsers(APIView):
|
||||
wb = load_workbook(filename=fs, read_only=True)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')
|
||||
|
||||
# example file is like:
|
||||
# Email Password Name(Optional) Role(Optional) Space Quota(MB, Optional) Login ID
|
||||
@ -317,7 +319,7 @@ class AdminImportUsers(APIView):
|
||||
continue
|
||||
|
||||
if record[1]:
|
||||
password = record[1].strip()
|
||||
password = str(record[1]).strip()
|
||||
if not password:
|
||||
result['failed'].append({
|
||||
'email': email,
|
||||
@ -331,8 +333,9 @@ class AdminImportUsers(APIView):
|
||||
})
|
||||
continue
|
||||
|
||||
vid = get_virtual_id_by_email(email)
|
||||
try:
|
||||
User.objects.get(email=email)
|
||||
User.objects.get(email=vid)
|
||||
result['failed'].append({
|
||||
'email': email,
|
||||
'error_msg': 'user %s exists.' % email
|
||||
@ -341,26 +344,28 @@ class AdminImportUsers(APIView):
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
user = User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
if config.FORCE_PASSWORD_CHANGE:
|
||||
UserOptions.objects.set_force_passwd_change(email)
|
||||
UserOptions.objects.set_force_passwd_change(user.email)
|
||||
|
||||
# update the user's optional info
|
||||
# update nikename
|
||||
if record[2]:
|
||||
try:
|
||||
nickname = record[2].strip()
|
||||
if len(nickname) <= 64 and '/' not in nickname:
|
||||
Profile.objects.add_or_update(email, nickname, '')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
nickname = email.split('@')[0]
|
||||
try:
|
||||
if record[2]:
|
||||
input_nickname = str(record[2]).strip()
|
||||
if len(input_nickname) <= 64 and '/' not in input_nickname:
|
||||
nickname = input_nickname
|
||||
Profile.objects.add_or_update(user.email, nickname, '')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
# update role
|
||||
if record[3]:
|
||||
try:
|
||||
role = record[3].strip()
|
||||
if is_pro_version() and role in get_available_roles():
|
||||
User.objects.update_role(email, role)
|
||||
User.objects.update_role(user.email, role)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
@ -370,14 +375,14 @@ class AdminImportUsers(APIView):
|
||||
space_quota_mb = int(record[4])
|
||||
if space_quota_mb >= 0:
|
||||
space_quota = int(space_quota_mb) * get_file_size_unit('MB')
|
||||
seafile_api.set_user_quota(email, space_quota)
|
||||
seafile_api.set_user_quota(user.email, space_quota)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
# login id
|
||||
if record[5]:
|
||||
try:
|
||||
Profile.objects.add_or_update(email, login_id=record[5])
|
||||
Profile.objects.add_or_update(user.email, login_id=record[5])
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
@ -390,12 +395,10 @@ class AdminImportUsers(APIView):
|
||||
'password': password
|
||||
})
|
||||
|
||||
user = User.objects.get(email=email)
|
||||
|
||||
info = {}
|
||||
info['email'] = email
|
||||
info['name'] = email2nickname(email)
|
||||
info['contact_email'] = email2contact_email(email)
|
||||
info = dict()
|
||||
info['email'] = user.email
|
||||
info['name'] = email2nickname(user.email)
|
||||
info['contact_email'] = email2contact_email(user.email)
|
||||
|
||||
info['is_staff'] = user.is_staff
|
||||
info['is_active'] = user.is_active
|
||||
|
@ -23,7 +23,6 @@ from seahub.work_weixin.utils import handler_work_weixin_api_response, \
|
||||
from seahub.work_weixin.settings import WORK_WEIXIN_DEPARTMENTS_URL, \
|
||||
WORK_WEIXIN_DEPARTMENT_MEMBERS_URL, WORK_WEIXIN_PROVIDER, WORK_WEIXIN_UID_PREFIX
|
||||
from seahub.base.accounts import User
|
||||
from seahub.utils.auth import gen_user_virtual_id
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
from seahub.group.utils import validate_group_name
|
||||
from seahub.auth.models import ExternalDepartment
|
||||
@ -161,12 +160,13 @@ def _handler_work_weixin_user_data(api_user, social_auth_queryset):
|
||||
return error_data
|
||||
|
||||
|
||||
def _import_user_from_work_weixin(email, api_user):
|
||||
api_user['username'] = email
|
||||
def _import_user_from_work_weixin(api_user):
|
||||
uid = WORK_WEIXIN_UID_PREFIX + api_user.get('userid')
|
||||
try:
|
||||
User.objects.create_user(email)
|
||||
SocialAuthUser.objects.add(email, WORK_WEIXIN_PROVIDER, uid)
|
||||
contact_email = api_user.get('contact_email') if api_user.get('contact_email') else None
|
||||
user = User.objects.create_oauth_user(contact_email)
|
||||
api_user['username'] = user.username
|
||||
SocialAuthUser.objects.add(user.username, WORK_WEIXIN_PROVIDER, uid)
|
||||
update_work_weixin_user_info(api_user)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
@ -202,12 +202,11 @@ class AdminWorkWeixinUsersBatch(APIView):
|
||||
|
||||
error_data = _handler_work_weixin_user_data(api_user, social_auth_queryset)
|
||||
if not error_data:
|
||||
email = gen_user_virtual_id()
|
||||
if _import_user_from_work_weixin(email, api_user):
|
||||
if _import_user_from_work_weixin(api_user):
|
||||
success.append({
|
||||
'userid': api_user.get('userid'),
|
||||
'name': api_user.get('name'),
|
||||
'email': email,
|
||||
'email': api_user.get('username'),
|
||||
})
|
||||
else:
|
||||
failed.append({
|
||||
@ -334,7 +333,7 @@ class AdminWorkWeixinDepartmentsImport(APIView):
|
||||
if api_department_list is None:
|
||||
error_msg = '获取企业微信组织架构失败'
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
api_department_list = sorted(api_department_list, key=lambda x:x['id'])
|
||||
api_department_list = sorted(api_department_list, key=lambda x: x['id'])
|
||||
|
||||
# list department members from work weixin
|
||||
api_user_list = self._list_department_members_from_work_weixin(access_token, department_id)
|
||||
@ -415,16 +414,17 @@ class AdminWorkWeixinDepartmentsImport(APIView):
|
||||
|
||||
# determine the user exists
|
||||
if social_auth_queryset.filter(uid=uid).exists():
|
||||
email = social_auth_queryset.get(uid=uid).username
|
||||
email = social_auth_queryset.get(uid=uid).username # this email means username
|
||||
else:
|
||||
# create user
|
||||
email = gen_user_virtual_id()
|
||||
create_user_success = _import_user_from_work_weixin(email, api_user)
|
||||
create_user_success = _import_user_from_work_weixin(api_user)
|
||||
if not create_user_success:
|
||||
failed_msg = self._api_user_failed_msg(
|
||||
'', api_user_name, department_id, '导入用户失败')
|
||||
failed.append(failed_msg)
|
||||
continue
|
||||
# api_user's username is from `User.objects.create_oauth_user` in `_import_user_from_work_weixin`
|
||||
email = api_user.get('username')
|
||||
|
||||
# bind user to department
|
||||
api_user_department_list = api_user.get('department')
|
||||
|
@ -12,6 +12,7 @@ from seahub.api2.permissions import CanInviteGuest
|
||||
from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error
|
||||
from seahub.base.accounts import User
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
from seahub.utils import is_valid_email
|
||||
from seahub.invitations.models import Invitation
|
||||
from seahub.invitations.utils import block_accepter
|
||||
@ -58,8 +59,9 @@ class InvitationsView(APIView):
|
||||
return api_error(status.HTTP_400_BAD_REQUEST,
|
||||
_('%s is already invited.') % accepter)
|
||||
|
||||
vid = get_virtual_id_by_email(accepter)
|
||||
try:
|
||||
user = User.objects.get(accepter)
|
||||
user = User.objects.get(vid)
|
||||
# user is active return exist
|
||||
if user.is_active is True:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST,
|
||||
@ -128,8 +130,9 @@ class InvitationsBatchView(APIView):
|
||||
|
||||
continue
|
||||
|
||||
vid = get_virtual_id_by_email(accepter)
|
||||
try:
|
||||
user = User.objects.get(accepter)
|
||||
user = User.objects.get(vid)
|
||||
# user is active return exist
|
||||
if user.is_active is True:
|
||||
result['failed'].append({
|
||||
|
@ -45,7 +45,7 @@ class RemoteUserBackend(object):
|
||||
# Create a User object if not already in the database?
|
||||
create_unknown_user = True
|
||||
|
||||
def authenticate(self, request, remote_user):
|
||||
def authenticate(self, *args, **kwargs):
|
||||
raise NotImplementedError('authenticate() must be overridden')
|
||||
|
||||
def get_user(self, user_id):
|
||||
@ -149,13 +149,13 @@ class SeafileRemoteUserBackend(AuthBackend):
|
||||
return None
|
||||
|
||||
try:
|
||||
user = User.objects.create_user(email=username,
|
||||
is_active=self.auto_activate)
|
||||
user = User.objects.create_remote_user(email=username,
|
||||
is_active=self.auto_activate)
|
||||
|
||||
if not self.auto_activate:
|
||||
notify_admins_on_activate_request(username)
|
||||
notify_admins_on_activate_request(user.username)
|
||||
elif settings.NOTIFY_ADMIN_AFTER_REGISTRATION:
|
||||
notify_admins_on_register_complete(username)
|
||||
notify_admins_on_register_complete(user.username)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
@ -170,7 +170,7 @@ class SeafileRemoteUserBackend(AuthBackend):
|
||||
return None
|
||||
|
||||
# get user again with updated extra info after configure
|
||||
return self.get_user(username)
|
||||
return self.get_user(user.username)
|
||||
|
||||
def clean_username(self, username):
|
||||
"""
|
||||
|
@ -5,8 +5,6 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.http import int_to_base36
|
||||
from collections import OrderedDict
|
||||
|
||||
from seaserv import ccnet_api
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.base.templatetags.seahub_tags import email2contact_email
|
||||
from seahub.auth import authenticate
|
||||
@ -14,7 +12,8 @@ from seahub.auth.tokens import default_token_generator
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.utils import IS_EMAIL_CONFIGURED, send_html_email, \
|
||||
is_ldap_user, is_user_password_strong, get_site_name, is_valid_email
|
||||
is_ldap_user, is_user_password_strong, get_site_name
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
|
||||
from captcha.fields import CaptchaField
|
||||
|
||||
@ -39,12 +38,6 @@ class AuthenticationForm(forms.Form):
|
||||
self.user_cache = None
|
||||
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_primary_id_by_username(self, username):
|
||||
"""Get user's primary id in case the username is changed.
|
||||
"""
|
||||
p_id = ccnet_api.get_primary_id(username)
|
||||
return p_id if p_id is not None else username
|
||||
|
||||
def clean_login(self):
|
||||
return self.cleaned_data['login'].strip()
|
||||
|
||||
@ -53,27 +46,22 @@ class AuthenticationForm(forms.Form):
|
||||
password = self.cleaned_data.get('password')
|
||||
|
||||
if username and password:
|
||||
|
||||
if not is_valid_email(username):
|
||||
# convert login id to username if any
|
||||
username = Profile.objects.convert_login_str_to_username(username)
|
||||
|
||||
self.user_cache = authenticate(username=username,
|
||||
password=password)
|
||||
self.user_cache = authenticate(username=username, password=password)
|
||||
if self.user_cache is None:
|
||||
"""then try login id/contact email/primary id"""
|
||||
# convert contact email to username if any
|
||||
# convert login id or contact email to username if any
|
||||
username = Profile.objects.convert_login_str_to_username(username)
|
||||
# convert username to primary id if any
|
||||
username = self.get_primary_id_by_username(username)
|
||||
|
||||
self.user_cache = authenticate(username=username, password=password)
|
||||
# After local user authentication process is completed, authenticate LDAP user
|
||||
if self.user_cache is None and settings.ENABLE_LDAP:
|
||||
self.user_cache = authenticate(ldap_user=username, password=password)
|
||||
|
||||
if self.user_cache is None:
|
||||
err_msg = _("Please enter a correct email/username and password. Note that both fields are case-sensitive.")
|
||||
|
||||
if settings.LOGIN_ERROR_DETAILS:
|
||||
try:
|
||||
u = User.objects.get(email=username)
|
||||
User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
err_msg = _("That e-mail address doesn't have an associated user account. Are you sure you've registered?")
|
||||
self.errors['not_found'] = err_msg
|
||||
@ -122,10 +110,11 @@ class PasswordResetForm(forms.Form):
|
||||
raise forms.ValidationError(_('Failed to send email, email service is not properly configured, please contact administrator.'))
|
||||
|
||||
email = self.cleaned_data["email"].lower().strip()
|
||||
vid = get_virtual_id_by_email(email)
|
||||
|
||||
# TODO: add filter method to UserManager
|
||||
try:
|
||||
self.users_cache = User.objects.get(email=email)
|
||||
self.users_cache = User.objects.get(email=vid)
|
||||
except User.DoesNotExist:
|
||||
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||
from django.core.cache import cache
|
||||
from django.conf import settings
|
||||
from urllib.parse import quote
|
||||
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.utils import normalize_cache_key
|
||||
@ -9,6 +8,7 @@ from seahub.utils.ip import get_remote_ip
|
||||
|
||||
LOGIN_ATTEMPT_PREFIX = 'UserLoginAttempt_'
|
||||
|
||||
|
||||
def get_login_failed_attempts(username=None, ip=None):
|
||||
"""Get login failed attempts base on username and ip.
|
||||
If both username and ip are provided, return the max value.
|
||||
@ -32,6 +32,7 @@ def get_login_failed_attempts(username=None, ip=None):
|
||||
|
||||
return max(username_attempts, ip_attempts)
|
||||
|
||||
|
||||
def incr_login_failed_attempts(username=None, ip=None):
|
||||
"""Increase login failed attempts by 1 for both username and ip.
|
||||
|
||||
@ -61,6 +62,7 @@ def incr_login_failed_attempts(username=None, ip=None):
|
||||
|
||||
return max(username_attempts, ip_attempts)
|
||||
|
||||
|
||||
def clear_login_failed_attempts(request, username):
|
||||
"""Clear login failed attempts records.
|
||||
|
||||
@ -74,3 +76,11 @@ def clear_login_failed_attempts(request, username):
|
||||
p = Profile.objects.get_profile_by_user(username)
|
||||
if p and p.login_id:
|
||||
cache.delete(normalize_cache_key(p.login_id, prefix=LOGIN_ATTEMPT_PREFIX))
|
||||
|
||||
|
||||
def get_virtual_id_by_email(email):
|
||||
p = Profile.objects.get_profile_by_contact_email(email)
|
||||
if p is None:
|
||||
return email
|
||||
else:
|
||||
return p.user
|
||||
|
@ -10,6 +10,7 @@ from seahub.base.accounts import User
|
||||
from seahub.avatar.settings import AVATAR_DEFAULT_URL, AVATAR_MAX_AVATARS_PER_USER
|
||||
from seahub.avatar.util import get_primary_avatar
|
||||
from seahub.avatar.models import Avatar
|
||||
from seahub.test_utils import Fixtures
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
@ -26,13 +27,13 @@ def upload_helper(o, filename):
|
||||
f.close()
|
||||
return response
|
||||
|
||||
class AvatarTestCase(TestCase):
|
||||
class AvatarTestCase(TestCase, Fixtures):
|
||||
"""
|
||||
Helper base class for all the follow test cases.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.testdatapath = os.path.join(os.path.dirname(__file__), "testdata")
|
||||
self.user = User.objects.create_user('lennon@thebeatles.com', 'testpassword', is_active=True)
|
||||
self.user = self.create_user('lennon@thebeatles.com', 'testpassword', is_active=True)
|
||||
|
||||
response = self.client.post('/accounts/login/', {
|
||||
'username': 'lennon@thebeatles.com',
|
||||
|
@ -14,6 +14,9 @@ from seaserv import ccnet_threaded_rpc, unset_repo_passwd, \
|
||||
seafile_api, ccnet_api
|
||||
from constance import config
|
||||
from registration import signals
|
||||
import ldap
|
||||
from ldap import sasl
|
||||
from ldap import filter
|
||||
|
||||
from seahub.auth import login
|
||||
from seahub.constants import DEFAULT_USER, DEFAULT_ORG, DEFAULT_ADMIN
|
||||
@ -26,6 +29,8 @@ from seahub.utils import is_user_password_strong, get_site_name, \
|
||||
from seahub.utils.mail import send_html_email_with_dj_template
|
||||
from seahub.utils.licenseparse import user_number_over_limit
|
||||
from seahub.share.models import ExtraSharePermission
|
||||
from seahub.utils.auth import gen_user_virtual_id
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
|
||||
try:
|
||||
from seahub.settings import CLOUD_MODE
|
||||
@ -36,6 +41,22 @@ try:
|
||||
except ImportError:
|
||||
MULTI_TENANCY = False
|
||||
|
||||
from seahub.settings import ENABLE_LDAP, LDAP_USER_FIRST_NAME_ATTR, LDAP_USER_LAST_NAME_ATTR, \
|
||||
LDAP_USER_NAME_REVERSE, LDAP_FILTER, LDAP_CONTACT_EMAIL_ATTR, LDAP_USER_ROLE_ATTR, \
|
||||
ACTIVATE_USER_WHEN_IMPORT, ENABLE_SASL, SASL_MECHANISM, SASL_AUTHC_ID_ATTR
|
||||
try:
|
||||
from seahub.settings import LDAP_SERVER_URL, LDAP_BASE_DN, LDAP_ADMIN_DN, LDAP_ADMIN_PASSWORD, \
|
||||
LDAP_PROVIDER, LDAP_LOGIN_ATTR
|
||||
except ImportError:
|
||||
LDAP_SERVER_URL = ''
|
||||
LDAP_BASE_DN = ''
|
||||
LDAP_ADMIN_DN = ''
|
||||
LDAP_ADMIN_PASSWORD = ''
|
||||
LDAP_PROVIDER = ''
|
||||
LDAP_LOGIN_ATTR = ''
|
||||
|
||||
LDAP_UPDATE_USER_WHEN_LOGIN = getattr(settings, 'LDAP_UPDATE_USER_WHEN_LOGIN', True)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ANONYMOUS_EMAIL = 'Anonymous'
|
||||
@ -49,9 +70,90 @@ class UserManager(object):
|
||||
"""
|
||||
Creates and saves a User with given username and password.
|
||||
"""
|
||||
virtual_id = gen_user_virtual_id()
|
||||
|
||||
# Lowercasing email address to avoid confusion.
|
||||
email = email.lower()
|
||||
|
||||
user = User(email=virtual_id)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
# Set email as contact email.
|
||||
Profile.objects.add_or_update(username=virtual_id, contact_email=email)
|
||||
|
||||
return self.get(email=virtual_id)
|
||||
|
||||
def update_role(self, email, role):
|
||||
"""
|
||||
If user has a role, update it; or create a role for user.
|
||||
"""
|
||||
ccnet_api.update_role_emailuser(email, role)
|
||||
return self.get(email=email)
|
||||
|
||||
def create_oauth_user(self, email=None, password=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves an oauth user which can without email.
|
||||
"""
|
||||
virtual_id = gen_user_virtual_id()
|
||||
|
||||
user = User(email=virtual_id)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
# Set email as contact email.
|
||||
if email:
|
||||
email = email.lower()
|
||||
Profile.objects.add_or_update(username=virtual_id, contact_email=email)
|
||||
|
||||
return self.get(email=virtual_id)
|
||||
|
||||
def create_ldap_user(self, email=None, password=None, nickname=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves a ldap user which can without email.
|
||||
"""
|
||||
virtual_id = gen_user_virtual_id()
|
||||
|
||||
user = User(email=virtual_id)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
# Set email as contact email.
|
||||
if email:
|
||||
email = email.lower()
|
||||
Profile.objects.add_or_update(username=virtual_id, contact_email=email, nickname=nickname)
|
||||
|
||||
return self.get(email=virtual_id)
|
||||
|
||||
def create_saml_user(self, email=None, password=None, nickname=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves a saml user which can without email.
|
||||
"""
|
||||
virtual_id = gen_user_virtual_id()
|
||||
|
||||
user = User(email=virtual_id)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
# Set email as contact email.
|
||||
if email:
|
||||
email = email.lower()
|
||||
Profile.objects.add_or_update(username=virtual_id, contact_email=email, nickname=nickname)
|
||||
|
||||
return self.get(email=virtual_id)
|
||||
|
||||
def create_remote_user(self, email, password=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves a remote user with given username.
|
||||
"""
|
||||
user = User(email=email)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
@ -60,11 +162,40 @@ class UserManager(object):
|
||||
|
||||
return self.get(email=email)
|
||||
|
||||
def update_role(self, email, role):
|
||||
def create_cas_user(self, email, password=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
If user has a role, update it; or create a role for user.
|
||||
Creates and saves a CAS user with given username.
|
||||
"""
|
||||
ccnet_api.update_role_emailuser(email, role)
|
||||
user = User(email=email)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
return self.get(email=email)
|
||||
|
||||
def create_krb_user(self, email, password=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves a KRB5 user with given username.
|
||||
"""
|
||||
user = User(email=email)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
return self.get(email=email)
|
||||
|
||||
def create_shib_user(self, email, password=None, is_staff=False, is_active=False):
|
||||
"""
|
||||
Creates and saves a SHIB user with given username.
|
||||
"""
|
||||
user = User(email=email)
|
||||
user.is_staff = is_staff
|
||||
user.is_active = is_active
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
return self.get(email=email)
|
||||
|
||||
def create_superuser(self, email, password):
|
||||
@ -122,6 +253,43 @@ class UserManager(object):
|
||||
|
||||
return user
|
||||
|
||||
def get_old_user(self, email, provider, uid):
|
||||
if not email:
|
||||
raise User.DoesNotExist('User matching query does not exits.')
|
||||
|
||||
emailuser = ccnet_threaded_rpc.get_emailuser(email)
|
||||
if not emailuser:
|
||||
raise User.DoesNotExist('User matching query does not exits.')
|
||||
|
||||
try:
|
||||
SocialAuthUser.objects.add(emailuser.email, provider, uid)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
user = User(emailuser.email)
|
||||
user.id = emailuser.id
|
||||
user.enc_password = emailuser.password
|
||||
user.is_staff = emailuser.is_staff
|
||||
user.is_active = emailuser.is_active
|
||||
user.ctime = emailuser.ctime
|
||||
user.org = emailuser.org
|
||||
user.source = emailuser.source
|
||||
user.role = emailuser.role
|
||||
user.reference_id = emailuser.reference_id
|
||||
|
||||
if user.is_staff:
|
||||
try:
|
||||
role_obj = AdminRole.objects.get_admin_role(emailuser.email)
|
||||
admin_role = role_obj.role
|
||||
except AdminRole.DoesNotExist:
|
||||
admin_role = DEFAULT_ADMIN
|
||||
|
||||
user.admin_role = admin_role
|
||||
else:
|
||||
user.admin_role = ''
|
||||
|
||||
return user
|
||||
|
||||
|
||||
class UserPermissions(object):
|
||||
def __init__(self, user):
|
||||
@ -583,6 +751,176 @@ class AuthBackend(object):
|
||||
return user
|
||||
|
||||
|
||||
def parse_ldap_res(ldap_search_result):
|
||||
first_name = ''
|
||||
last_name = ''
|
||||
contact_email = ''
|
||||
user_role = ''
|
||||
authc_id = ''
|
||||
dn = ldap_search_result[0][0]
|
||||
first_name_list = ldap_search_result[0][1].get(LDAP_USER_FIRST_NAME_ATTR, [])
|
||||
last_name_list = ldap_search_result[0][1].get(LDAP_USER_LAST_NAME_ATTR, [])
|
||||
contact_email_list = ldap_search_result[0][1].get(LDAP_CONTACT_EMAIL_ATTR, [])
|
||||
user_role_list = ldap_search_result[0][1].get(LDAP_USER_ROLE_ATTR, [])
|
||||
authc_id_list = list()
|
||||
if ENABLE_SASL and SASL_MECHANISM:
|
||||
authc_id_list = ldap_search_result[0][1].get(SASL_AUTHC_ID_ATTR, [])
|
||||
|
||||
if first_name_list:
|
||||
first_name = first_name_list[0].decode()
|
||||
if last_name_list:
|
||||
last_name = last_name_list[0].decode()
|
||||
|
||||
if LDAP_USER_NAME_REVERSE:
|
||||
nickname = last_name + ' ' + first_name
|
||||
else:
|
||||
nickname = first_name + ' ' + last_name
|
||||
|
||||
if contact_email_list:
|
||||
contact_email = contact_email_list[0].decode()
|
||||
|
||||
if user_role_list:
|
||||
user_role = user_role_list[0].decode()
|
||||
|
||||
if authc_id_list:
|
||||
authc_id = authc_id_list[0].decode()
|
||||
|
||||
return dn, nickname, contact_email, user_role, authc_id
|
||||
|
||||
|
||||
class CustomLDAPBackend(object):
|
||||
""" A custom LDAP authentication backend """
|
||||
|
||||
def get_user(self, username):
|
||||
try:
|
||||
user = User.objects.get(username)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
return user
|
||||
|
||||
def authenticate(self, ldap_user=None, password=None):
|
||||
if not is_pro_version() or not ENABLE_LDAP:
|
||||
return
|
||||
|
||||
admin_bind_conn = ldap.initialize(LDAP_SERVER_URL)
|
||||
try:
|
||||
admin_bind_conn.set_option(ldap.OPT_REFERRALS, 0)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to set referrals option. {e}')
|
||||
return
|
||||
|
||||
try:
|
||||
admin_bind_conn.protocol_version = ldap.VERSION3
|
||||
if ENABLE_SASL and SASL_MECHANISM:
|
||||
sasl_cb_value_dict = {}
|
||||
if SASL_MECHANISM != 'EXTERNAL' and SASL_MECHANISM != 'GSSAPI':
|
||||
sasl_cb_value_dict = {
|
||||
sasl.CB_AUTHNAME: LDAP_ADMIN_DN,
|
||||
sasl.CB_PASS: LDAP_ADMIN_PASSWORD,
|
||||
}
|
||||
sasl_auth = sasl.sasl(sasl_cb_value_dict, SASL_MECHANISM)
|
||||
admin_bind_conn.sasl_interactive_bind_s('', sasl_auth)
|
||||
else:
|
||||
admin_bind_conn.simple_bind_s(LDAP_ADMIN_DN, LDAP_ADMIN_PASSWORD)
|
||||
except Exception as e:
|
||||
logger.error(f'ldap admin bind failed. {e}')
|
||||
return
|
||||
|
||||
username = Profile.objects.convert_login_str_to_username(ldap_user)
|
||||
auth_user = SocialAuthUser.objects.filter(username=username, provider=LDAP_PROVIDER).first()
|
||||
if auth_user:
|
||||
login_attr = auth_user.uid
|
||||
else:
|
||||
login_attr = username
|
||||
|
||||
if LDAP_LOGIN_ATTR.lower() in ['email', 'mail']:
|
||||
filterstr = filter.filter_format('(&(mail=%s))', [login_attr])
|
||||
else:
|
||||
filterstr = filter.filter_format(f'(&({LDAP_LOGIN_ATTR}=%s))', [login_attr])
|
||||
|
||||
if LDAP_FILTER:
|
||||
filterstr = filterstr[:-1] + '(' + LDAP_FILTER + '))'
|
||||
|
||||
try:
|
||||
result_data = admin_bind_conn.search_s(LDAP_BASE_DN, ldap.SCOPE_SUBTREE, filterstr)
|
||||
except Exception as e:
|
||||
logger.error(f'ldap user search failed. {e}')
|
||||
return
|
||||
|
||||
# user not found in ldap
|
||||
if not result_data:
|
||||
logger.error(f'ldap user {login_attr} not found.')
|
||||
return
|
||||
|
||||
# delete old ldap connection instance and create new, if not, some err will occur
|
||||
admin_bind_conn.unbind_s()
|
||||
del admin_bind_conn
|
||||
|
||||
try:
|
||||
dn, nickname, contact_email, user_role, authc_id = parse_ldap_res(result_data)
|
||||
except Exception as e:
|
||||
logger.error(f'parse ldap result failed {e}')
|
||||
return
|
||||
|
||||
user_bind_conn = ldap.initialize(LDAP_SERVER_URL)
|
||||
try:
|
||||
user_bind_conn.protocol_version = ldap.VERSION3
|
||||
if ENABLE_SASL and SASL_MECHANISM:
|
||||
sasl_cb_value_dict = {}
|
||||
if SASL_MECHANISM != 'EXTERNAL' and SASL_MECHANISM != 'GSSAPI':
|
||||
sasl_cb_value_dict = {
|
||||
sasl.CB_AUTHNAME: authc_id,
|
||||
sasl.CB_PASS: password,
|
||||
}
|
||||
sasl_auth = sasl.sasl(sasl_cb_value_dict, SASL_MECHANISM)
|
||||
user_bind_conn.sasl_interactive_bind_s('', sasl_auth)
|
||||
else:
|
||||
user_bind_conn.simple_bind_s(dn, password)
|
||||
except Exception as e:
|
||||
logger.error(f'ldap user bind failed. {e}')
|
||||
return
|
||||
user_bind_conn.unbind_s()
|
||||
|
||||
# check if existed
|
||||
ldap_user = SocialAuthUser.objects.filter(provider=LDAP_PROVIDER, uid=login_attr).first()
|
||||
if ldap_user:
|
||||
user = self.get_user(ldap_user.username)
|
||||
if not user:
|
||||
# Means found user in social_auth_usersocialauth but not found user in EmailUser,
|
||||
# delete it and recreate one.
|
||||
logger.warning('The DB data is invalid, delete it and recreate one.')
|
||||
SocialAuthUser.objects.filter(provider=LDAP_PROVIDER, uid=login_attr).delete()
|
||||
else:
|
||||
# compatible with old users
|
||||
try:
|
||||
user = User.objects.get_old_user(username, LDAP_PROVIDER, login_attr)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
|
||||
if not user:
|
||||
try:
|
||||
user = User.objects.create_ldap_user(is_active=ACTIVATE_USER_WHEN_IMPORT)
|
||||
SocialAuthUser.objects.add(user.username, LDAP_PROVIDER, login_attr)
|
||||
except Exception as e:
|
||||
logger.error(f'recreate ldap user failed. {e}')
|
||||
return
|
||||
|
||||
username = user.username
|
||||
if LDAP_UPDATE_USER_WHEN_LOGIN:
|
||||
profile_kwargs = {
|
||||
'nickname': nickname,
|
||||
'contact_email': contact_email,
|
||||
}
|
||||
try:
|
||||
Profile.objects.add_or_update(username, **profile_kwargs)
|
||||
except Exception as e:
|
||||
logger.error(f'update ldap user failed {e}')
|
||||
|
||||
if user_role:
|
||||
User.objects.update_role(username, user_role)
|
||||
return user
|
||||
|
||||
|
||||
# Register related
|
||||
class RegistrationBackend(object):
|
||||
"""
|
||||
|
@ -18,12 +18,12 @@ from seahub.api2.utils import get_api_token
|
||||
from seahub import auth
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.utils import render_error, get_site_scheme_and_netloc
|
||||
from seahub.utils.auth import gen_user_virtual_id, VIRTUAL_ID_EMAIL_DOMAIN
|
||||
from seahub.utils.auth import VIRTUAL_ID_EMAIL_DOMAIN
|
||||
from seahub.base.accounts import User
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
from seahub.auth.decorators import login_required
|
||||
from seahub.dingtalk.utils import dingtalk_get_detailed_user_info, \
|
||||
dingtalk_get_orgapp_token, dingtalk_get_userid_by_unionid_new, \
|
||||
dingtalk_get_userid_by_unionid_new, \
|
||||
dingtalk_get_detailed_user_info_new
|
||||
|
||||
from seahub.dingtalk.settings import ENABLE_DINGTALK
|
||||
@ -107,12 +107,14 @@ def dingtalk_callback(request):
|
||||
auth_user = SocialAuthUser.objects.get_by_provider_and_uid('dingtalk', user_info['unionid'])
|
||||
if auth_user:
|
||||
email = auth_user.username
|
||||
is_new_user = False
|
||||
else:
|
||||
email = gen_user_virtual_id()
|
||||
SocialAuthUser.objects.add(email, 'dingtalk', user_info['unionid'])
|
||||
email = None
|
||||
is_new_user = True
|
||||
|
||||
try:
|
||||
user = auth.authenticate(remote_user=email)
|
||||
email = user.username
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
except Exception as e:
|
||||
@ -122,6 +124,10 @@ def dingtalk_callback(request):
|
||||
if not user or not user.is_active:
|
||||
return render_error(request, _('User %s not found or inactive.') % email)
|
||||
|
||||
# bind
|
||||
if is_new_user:
|
||||
SocialAuthUser.objects.add(user.username, 'dingtalk', user_info['unionid'])
|
||||
|
||||
# User is valid. Set request.user and persist user in the session
|
||||
# by logging the user in.
|
||||
request.user = user
|
||||
@ -130,18 +136,13 @@ def dingtalk_callback(request):
|
||||
|
||||
# update user's profile
|
||||
name = user_info['nick'] if 'nick' in user_info else ''
|
||||
if name:
|
||||
|
||||
user_detail_info = dingtalk_get_detailed_user_info(user_info['unionid'])
|
||||
contact_email = user_detail_info.get('email', '')
|
||||
if name or contact_email:
|
||||
profile = Profile.objects.get_profile_by_user(email)
|
||||
if not profile:
|
||||
profile = Profile(user=email)
|
||||
|
||||
profile.nickname = name.strip()
|
||||
profile.save()
|
||||
|
||||
user_detail_info = dingtalk_get_detailed_user_info(user_info['unionid'])
|
||||
contact_email = user_detail_info.get('email', '')
|
||||
if contact_email:
|
||||
profile.contact_email = contact_email
|
||||
profile.save()
|
||||
|
||||
@ -343,12 +344,14 @@ def dingtalk_callback_new(request):
|
||||
auth_user = SocialAuthUser.objects.get_by_provider_and_uid('dingtalk', union_id)
|
||||
if auth_user:
|
||||
email = auth_user.username
|
||||
is_new_user = False
|
||||
else:
|
||||
email = gen_user_virtual_id()
|
||||
SocialAuthUser.objects.add(email, 'dingtalk', union_id)
|
||||
email = None
|
||||
is_new_user = True
|
||||
|
||||
try:
|
||||
user = auth.authenticate(remote_user=email)
|
||||
email = user.username
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
except Exception as e:
|
||||
@ -358,6 +361,10 @@ def dingtalk_callback_new(request):
|
||||
if not user or not user.is_active:
|
||||
return render_error(request, _('User %s not found or inactive.') % email)
|
||||
|
||||
# bind
|
||||
if is_new_user:
|
||||
SocialAuthUser.objects.add(user.username, 'dingtalk', union_id)
|
||||
|
||||
# User is valid. Set request.user and persist user in the session
|
||||
# by logging the user in.
|
||||
request.user = user
|
||||
|
@ -70,7 +70,7 @@ class CASBackend(ModelBackend):
|
||||
user = User.objects.get(email=username)
|
||||
created = False
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user(
|
||||
user = User.objects.create_cas_user(
|
||||
email=username, is_active=True)
|
||||
user = self.configure_user(user)
|
||||
created = True
|
||||
|
@ -8,14 +8,15 @@ from django.test import TestCase, Client
|
||||
from group.models import GroupMessage
|
||||
from base.accounts import User
|
||||
from notifications.models import UserNotification
|
||||
from seahub.test_utils import Fixtures
|
||||
|
||||
class GroupTestCase(TestCase):
|
||||
class GroupTestCase(TestCase, Fixtures):
|
||||
"""
|
||||
Helper base class for all the follow test cases.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.testdatapath = os.path.join(os.path.dirname(__file__), "testdata")
|
||||
self.user = User.objects.create_user('lennon@thebeatles.com', 'testpassword', is_active=True)
|
||||
self.user = self.create_user('lennon@thebeatles.com', 'testpassword', is_active=True)
|
||||
|
||||
# Login user
|
||||
response = self.client.post('/accounts/login/', {
|
||||
|
@ -10,6 +10,7 @@ from seaserv import seafile_api
|
||||
|
||||
from seahub.auth import login as auth_login, authenticate
|
||||
from seahub.auth import get_backends
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
from seahub.base.accounts import User
|
||||
from seahub.constants import GUEST_USER
|
||||
from seahub.invitations.models import Invitation, RepoShareInvitation
|
||||
@ -29,9 +30,10 @@ def token_view(request, token):
|
||||
if i.is_expired():
|
||||
raise Http404
|
||||
|
||||
vid = get_virtual_id_by_email(i.accepter)
|
||||
if request.method == 'GET':
|
||||
try:
|
||||
user = User.objects.get(email=i.accepter)
|
||||
user = User.objects.get(email=vid)
|
||||
if user.is_active is True:
|
||||
# user is active return exist
|
||||
messages.error(request, _('A user with this email already exists.'))
|
||||
@ -46,7 +48,7 @@ def token_view(request, token):
|
||||
return HttpResponseRedirect(request.headers.get('referer'))
|
||||
|
||||
try:
|
||||
user = User.objects.get(email=i.accepter)
|
||||
user = User.objects.get(email=vid)
|
||||
if user.is_active is True:
|
||||
# user is active return exist
|
||||
messages.error(request, _('A user with this email already exists.'))
|
||||
@ -83,7 +85,7 @@ def token_view(request, token):
|
||||
# repo share invitation
|
||||
try:
|
||||
shared_queryset = RepoShareInvitation.objects.list_by_invitation(invitation=i)
|
||||
accepter = i.accepter
|
||||
accepter = user.username
|
||||
|
||||
for shared_obj in shared_queryset:
|
||||
repo_id = shared_obj.repo_id
|
||||
|
@ -48,8 +48,8 @@ class RemoteKrbBackend(RemoteUserBackend):
|
||||
user = self.get_user(username)
|
||||
if not user:
|
||||
if self.create_unknown_user:
|
||||
user = User.objects.create_user(email=username,
|
||||
is_active=True)
|
||||
user = User.objects.create_krb_user(email=username,
|
||||
is_active=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
@ -58,21 +58,17 @@ class OauthRemoteUserBackend(RemoteUserBackend):
|
||||
Returns None if ``create_unknown_user`` is ``False`` and a ``User``
|
||||
object with the given username is not found in the database.
|
||||
"""
|
||||
if not remote_user:
|
||||
return
|
||||
if remote_user:
|
||||
username = self.clean_username(remote_user)
|
||||
user = self.get_user(username)
|
||||
else:
|
||||
user = None
|
||||
|
||||
username = self.clean_username(remote_user)
|
||||
try:
|
||||
user = User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
if self.create_unknown_user:
|
||||
user = User.objects.create_user(
|
||||
email=username, is_active=self.activate_after_creation)
|
||||
if not self.activate_after_creation:
|
||||
notify_admins_on_activate_request(username)
|
||||
elif settings.NOTIFY_ADMIN_AFTER_REGISTRATION:
|
||||
notify_admins_on_register_complete(username)
|
||||
else:
|
||||
user = None
|
||||
if not user and self.create_unknown_user:
|
||||
user = User.objects.create_oauth_user(is_active=self.activate_after_creation)
|
||||
if not self.activate_after_creation:
|
||||
notify_admins_on_activate_request(user.username)
|
||||
elif settings.NOTIFY_ADMIN_AFTER_REGISTRATION:
|
||||
notify_admins_on_register_complete(user.username)
|
||||
|
||||
return user
|
||||
|
@ -15,6 +15,7 @@ from seahub.utils import is_valid_email, render_error, get_service_url
|
||||
from seahub.utils.file_size import get_quota_from_string
|
||||
from seahub.base.accounts import User
|
||||
from seahub.role_permissions.utils import get_enabled_role_permissions_by_role
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
import seahub.settings as settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -50,10 +51,7 @@ if ENABLE_OAUTH:
|
||||
|
||||
# Used for init an user for Seahub.
|
||||
PROVIDER_DOMAIN = getattr(settings, 'OAUTH_PROVIDER_DOMAIN', '')
|
||||
ATTRIBUTE_MAP = {
|
||||
'id': (True, "email"),
|
||||
}
|
||||
ATTRIBUTE_MAP.update(getattr(settings, 'OAUTH_ATTRIBUTE_MAP', {}))
|
||||
OAUTH_ATTRIBUTE_MAP = getattr(settings, 'OAUTH_ATTRIBUTE_MAP', {})
|
||||
|
||||
|
||||
def oauth_check(func):
|
||||
@ -154,36 +152,46 @@ def oauth_callback(request):
|
||||
logger.error(e)
|
||||
return render_error(request, _('Error, please contact administrator.'))
|
||||
|
||||
def format_user_info(user_info_resp):
|
||||
logger.info('user info resp: %s' % user_info_resp.text)
|
||||
error = False
|
||||
user_info = {}
|
||||
user_info_json = user_info_resp.json()
|
||||
oauth_user_info = {}
|
||||
user_info_json = user_info_resp.json()
|
||||
for oauth_attr, attr_tuple in OAUTH_ATTRIBUTE_MAP.items():
|
||||
required, user_attr = attr_tuple
|
||||
attr_value = user_info_json.get(oauth_attr, '')
|
||||
if attr_value:
|
||||
oauth_user_info[user_attr] = attr_value
|
||||
elif required:
|
||||
logger.error('Required user attr not found.')
|
||||
logger.error(user_info_json)
|
||||
return render_error(request, _('Error, please contact administrator.'))
|
||||
|
||||
for item, attr in list(ATTRIBUTE_MAP.items()):
|
||||
required, user_attr = attr
|
||||
value = user_info_json.get(item, '')
|
||||
|
||||
if value:
|
||||
# ccnet email
|
||||
if user_attr == 'email':
|
||||
user_info[user_attr] = value if is_valid_email(str(value)) else \
|
||||
'%s@%s' % (str(value), PROVIDER_DOMAIN)
|
||||
else:
|
||||
user_info[user_attr] = value
|
||||
elif required:
|
||||
error = True
|
||||
|
||||
return user_info, error
|
||||
|
||||
user_info, error = format_user_info(user_info_resp)
|
||||
if error:
|
||||
logger.error('Required user info not found.')
|
||||
logger.error(user_info)
|
||||
uid = oauth_user_info.get('uid', '') or oauth_user_info.get('email', '')
|
||||
if not uid:
|
||||
logger.error('oauth user uid and email not found.')
|
||||
logger.error('user_info_json: %s' % user_info_json)
|
||||
return render_error(request, _('Error, please contact administrator.'))
|
||||
|
||||
# seahub authenticate user
|
||||
email = user_info['email']
|
||||
# compatible with old users via email
|
||||
old_email = oauth_user_info.get('email', '')
|
||||
|
||||
oauth_user = SocialAuthUser.objects.get_by_provider_and_uid(PROVIDER_DOMAIN, uid)
|
||||
if oauth_user:
|
||||
email = oauth_user.username
|
||||
is_new_user = False
|
||||
elif old_email:
|
||||
if not is_valid_email(old_email):
|
||||
# In previous versions, if 'email' is not in mailbox format,
|
||||
# we combine 'email' and 'provider' to mailbox format.
|
||||
old_email = '%s@%s' % (str(old_email), PROVIDER_DOMAIN)
|
||||
try:
|
||||
old_user = User.objects.get_old_user(old_email, PROVIDER_DOMAIN, uid)
|
||||
email = old_user.username
|
||||
is_new_user = False
|
||||
except User.DoesNotExist:
|
||||
email = None
|
||||
is_new_user = True
|
||||
else:
|
||||
email = None
|
||||
is_new_user = True
|
||||
|
||||
try:
|
||||
user = auth.authenticate(remote_user=email)
|
||||
@ -193,10 +201,12 @@ def oauth_callback(request):
|
||||
logger.error(e)
|
||||
return render_error(request, _('Error, please contact administrator.'))
|
||||
|
||||
if not user or not user.is_active:
|
||||
logger.error('User %s not found or inactive.' % email)
|
||||
# a page for authenticate user failed
|
||||
return render_error(request, _('User %s not found.') % email)
|
||||
if not user:
|
||||
return render_error(request, _('Error, new user registration is not allowed, please contact administrator.'))
|
||||
|
||||
email = user.username
|
||||
if is_new_user:
|
||||
SocialAuthUser.objects.add(email, PROVIDER_DOMAIN, uid)
|
||||
|
||||
# User is valid. Set request.user and persist user in the session
|
||||
# by logging the user in.
|
||||
@ -204,8 +214,8 @@ def oauth_callback(request):
|
||||
auth.login(request, user)
|
||||
|
||||
# update user's profile
|
||||
name = user_info['name'] if 'name' in user_info else ''
|
||||
contact_email = user_info['contact_email'] if 'contact_email' in user_info else ''
|
||||
name = oauth_user_info.get('name', '')
|
||||
contact_email = oauth_user_info.get('contact_email', '')
|
||||
|
||||
profile = Profile.objects.get_profile_by_user(email)
|
||||
if not profile:
|
||||
@ -220,12 +230,12 @@ def oauth_callback(request):
|
||||
profile.save()
|
||||
|
||||
if CUSTOM_GET_USER_ROLE:
|
||||
remote_role_value = user_info.get('role', '')
|
||||
remote_role_value = oauth_user_info.get('role', '')
|
||||
if remote_role_value:
|
||||
role = custom_get_user_role(remote_role_value)
|
||||
|
||||
# update user role
|
||||
ccnet_api.update_role_emailuser(user_info['email'], role)
|
||||
ccnet_api.update_role_emailuser(email, role)
|
||||
|
||||
# update user role quota
|
||||
role_quota = get_enabled_role_permissions_by_role(role)['role_quota']
|
||||
|
@ -17,6 +17,7 @@ from seahub.base.accounts import User
|
||||
from seahub.settings import INIT_PASSWD, SEND_EMAIL_ON_RESETTING_USER_PASSWD
|
||||
from seahub.utils import IS_EMAIL_CONFIGURED
|
||||
from seahub.views.sysadmin import send_user_reset_email
|
||||
from seahub.profile.models import Profile
|
||||
|
||||
from seahub.organizations.views import org_user_exists
|
||||
|
||||
@ -62,8 +63,13 @@ class OrgAdminUserSetPassword(APIView):
|
||||
# send password reset email
|
||||
if IS_EMAIL_CONFIGURED:
|
||||
if SEND_EMAIL_ON_RESETTING_USER_PASSWD:
|
||||
send_to = user.username
|
||||
profile = Profile.objects.get_profile_by_user(user.username)
|
||||
if profile and profile.contact_email:
|
||||
send_to = profile.contact_email
|
||||
|
||||
try:
|
||||
send_user_reset_email(request, user.email, new_password)
|
||||
send_user_reset_email(request, send_to, new_password)
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
|
||||
|
@ -16,6 +16,7 @@ from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.api2.utils import api_error, to_python_boolean
|
||||
from seahub.api2.endpoints.utils import is_org_user
|
||||
from seahub.auth.utils import get_virtual_id_by_email
|
||||
from seahub.base.accounts import User
|
||||
from seahub.base.models import UserLastLogin
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email
|
||||
@ -260,6 +261,10 @@ class OrgAdminUsers(APIView):
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
if Profile.objects.filter(contact_email=email).first():
|
||||
error_msg = _('User %s already exists.') % email
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
try:
|
||||
user = User.objects.create_user(email, password, is_staff=False,
|
||||
is_active=True)
|
||||
@ -682,17 +687,18 @@ class OrgAdminImportUsers(APIView):
|
||||
})
|
||||
continue
|
||||
|
||||
if not record[1] or not record[1].strip():
|
||||
if not record[1] or not str(record[1]).strip():
|
||||
result['failed'].append({
|
||||
'email': email,
|
||||
'error_msg': 'password invalid.'
|
||||
})
|
||||
continue
|
||||
else:
|
||||
password = record[1].strip()
|
||||
password = str(record[1]).strip()
|
||||
|
||||
vid = get_virtual_id_by_email(email)
|
||||
try:
|
||||
User.objects.get(email=email)
|
||||
User.objects.get(email=vid)
|
||||
result['failed'].append({
|
||||
'email': email,
|
||||
'error_msg': 'user %s exists.' % email
|
||||
@ -701,8 +707,8 @@ class OrgAdminImportUsers(APIView):
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
set_org_user(org_id, email)
|
||||
user = User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
set_org_user(org_id, user.email)
|
||||
|
||||
if IS_EMAIL_CONFIGURED:
|
||||
if SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER:
|
||||
@ -717,7 +723,7 @@ class OrgAdminImportUsers(APIView):
|
||||
try:
|
||||
nickname = record[2].strip()
|
||||
if len(nickname) <= 64 and '/' not in nickname:
|
||||
Profile.objects.add_or_update(email, nickname, '')
|
||||
Profile.objects.add_or_update(user.email, nickname, '')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
@ -727,23 +733,21 @@ class OrgAdminImportUsers(APIView):
|
||||
space_quota_mb = int(record[3])
|
||||
if space_quota_mb >= 0:
|
||||
space_quota = int(space_quota_mb) * get_file_size_unit('MB')
|
||||
seafile_api.set_org_user_quota(org_id, email, space_quota)
|
||||
seafile_api.set_org_user_quota(org_id, user.email, space_quota)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
user = User.objects.get(email=email)
|
||||
|
||||
info = {}
|
||||
info['email'] = email
|
||||
info['name'] = email2nickname(email)
|
||||
info['contact_email'] = email2contact_email(email)
|
||||
info['email'] = user.email
|
||||
info['name'] = email2nickname(user.email)
|
||||
info['contact_email'] = email2contact_email(user.email)
|
||||
|
||||
info['is_staff'] = user.is_staff
|
||||
info['is_active'] = user.is_active
|
||||
|
||||
info['quota_usage'] = 0
|
||||
try:
|
||||
info['quota_total'] = get_org_user_quota(org_id, email)
|
||||
info['quota_total'] = get_org_user_quota(org_id, user.email)
|
||||
except SearpcError as e:
|
||||
logger.error(e)
|
||||
info['quota_total'] = -1
|
||||
|
@ -316,6 +316,21 @@ ENABLE_WEIXIN = False
|
||||
# enable dingtalk
|
||||
ENABLE_DINGTALK = False
|
||||
|
||||
# enable ldap
|
||||
ENABLE_LDAP = False
|
||||
LDAP_USER_FIRST_NAME_ATTR = ''
|
||||
LDAP_USER_LAST_NAME_ATTR = ''
|
||||
LDAP_USER_NAME_REVERSE = False
|
||||
LDAP_FILTER = ''
|
||||
LDAP_CONTACT_EMAIL_ATTR = ''
|
||||
LDAP_USER_ROLE_ATTR = ''
|
||||
ACTIVATE_USER_WHEN_IMPORT = True
|
||||
|
||||
# enable ldap sasl auth
|
||||
ENABLE_SASL = False
|
||||
SASL_MECHANISM = ''
|
||||
SASL_AUTHC_ID_ATTR = ''
|
||||
|
||||
# allow user to clean library trash
|
||||
ENABLE_USER_CLEAN_TRASH = True
|
||||
|
||||
@ -974,6 +989,9 @@ if ENABLE_ADFS_LOGIN or ENABLE_MULTI_ADFS:
|
||||
AUTHENTICATION_BACKENDS += ('seahub.adfs_auth.backends.Saml2Backend',)
|
||||
SAML_CONFIG_LOADER = 'seahub.adfs_auth.utils.config_settings_loader'
|
||||
|
||||
if ENABLE_LDAP:
|
||||
AUTHENTICATION_BACKENDS += ('seahub.base.accounts.CustomLDAPBackend',)
|
||||
|
||||
#####################
|
||||
# Custom Nav Items #
|
||||
#####################
|
||||
|
@ -185,11 +185,13 @@ class Fixtures(Exam):
|
||||
if not email:
|
||||
email = uuid4().hex + '@test.com'
|
||||
|
||||
kwargs.setdefault('email', email)
|
||||
kwargs.setdefault('is_staff', False)
|
||||
kwargs.setdefault('is_active', True)
|
||||
user = User(email=email)
|
||||
user.is_staff = kwargs.get('is_staff', False)
|
||||
user.is_active = kwargs.get('is_active', True)
|
||||
user.set_password('secret')
|
||||
user.save()
|
||||
|
||||
return User.objects.create_user(password='secret', **kwargs)
|
||||
return User.objects.get(email)
|
||||
|
||||
def remove_user(self, email=None):
|
||||
if not email:
|
||||
@ -280,7 +282,11 @@ class Fixtures(Exam):
|
||||
return new_org
|
||||
|
||||
quota = int(quota)
|
||||
User.objects.create_user(username, password, is_staff=False, is_active=True)
|
||||
user = User(email=username)
|
||||
user.is_staff = False
|
||||
user.is_active = True
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
create_org(org_name, prefix, username)
|
||||
new_org = ccnet_threaded_rpc.get_org_by_url_prefix(prefix)
|
||||
from seahub.organizations.models import OrgMemberQuota
|
||||
@ -295,7 +301,12 @@ class Fixtures(Exam):
|
||||
try:
|
||||
user = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
user = User(email=email)
|
||||
user.is_staff = False
|
||||
user.is_active = True
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
user = User.objects.get(email=email)
|
||||
ccnet_api.add_org_user(self.org.org_id, email, 0)
|
||||
return user
|
||||
|
||||
@ -305,7 +316,12 @@ class Fixtures(Exam):
|
||||
try:
|
||||
admin = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
admin = User.objects.create_user(email, password, is_staff=False, is_active=True)
|
||||
user = User(email=email)
|
||||
user.is_staff = False
|
||||
user.is_active = True
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
admin = User.objects.get(email=email)
|
||||
ccnet_api.add_org_user(self.org.org_id, email, 1)
|
||||
return admin
|
||||
|
||||
|
@ -608,17 +608,17 @@ def user_add(request):
|
||||
operation=USER_ADD, detail=admin_op_detail)
|
||||
|
||||
if user:
|
||||
User.objects.update_role(email, role)
|
||||
User.objects.update_role(user.email, role)
|
||||
if config.FORCE_PASSWORD_CHANGE:
|
||||
UserOptions.objects.set_force_passwd_change(email)
|
||||
UserOptions.objects.set_force_passwd_change(user.email)
|
||||
if name:
|
||||
Profile.objects.add_or_update(email, name, '')
|
||||
Profile.objects.add_or_update(user.email, name, '')
|
||||
if department:
|
||||
DetailedProfile.objects.add_or_update(email, department, '')
|
||||
DetailedProfile.objects.add_or_update(user.email, department, '')
|
||||
|
||||
if request.user.org:
|
||||
org_id = request.user.org.org_id
|
||||
ccnet_threaded_rpc.add_org_user(org_id, email, 0)
|
||||
ccnet_threaded_rpc.add_org_user(org_id, user.email, 0)
|
||||
if IS_EMAIL_CONFIGURED:
|
||||
try:
|
||||
send_user_add_mail(request, email, password)
|
||||
|
@ -17,7 +17,6 @@ from seahub.base.accounts import User
|
||||
from seahub.avatar.models import Avatar
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.utils import render_error, get_site_scheme_and_netloc
|
||||
from seahub.utils.auth import gen_user_virtual_id
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
|
||||
from seahub.weixin.settings import ENABLE_WEIXIN, \
|
||||
@ -82,12 +81,14 @@ def weixin_oauth_callback(request):
|
||||
auth_user = SocialAuthUser.objects.get_by_provider_and_uid('weixin', openid)
|
||||
if auth_user:
|
||||
email = auth_user.username
|
||||
is_new_user = False
|
||||
else:
|
||||
email = gen_user_virtual_id()
|
||||
SocialAuthUser.objects.add(email, 'weixin', openid)
|
||||
email = None
|
||||
is_new_user = True
|
||||
|
||||
try:
|
||||
user = auth.authenticate(remote_user=email)
|
||||
email = user.username
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
except Exception as e:
|
||||
@ -97,6 +98,9 @@ def weixin_oauth_callback(request):
|
||||
if not user or not user.is_active:
|
||||
return render_error(request, _('User %s not found or inactive.') % email)
|
||||
|
||||
if is_new_user:
|
||||
SocialAuthUser.objects.add(email, 'weixin', openid)
|
||||
|
||||
request.user = user
|
||||
auth.login(request, user)
|
||||
|
||||
|
@ -22,7 +22,7 @@ from seahub.work_weixin.settings import WORK_WEIXIN_AUTHORIZATION_URL, WORK_WEIX
|
||||
WORK_WEIXIN_USER_INFO_AUTO_UPDATE, REMEMBER_ME
|
||||
from seahub.work_weixin.utils import work_weixin_oauth_check, get_work_weixin_access_token, \
|
||||
handler_work_weixin_api_response, update_work_weixin_user_info
|
||||
from seahub.utils.auth import gen_user_virtual_id, VIRTUAL_ID_EMAIL_DOMAIN
|
||||
from seahub.utils.auth import VIRTUAL_ID_EMAIL_DOMAIN
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
from django.urls import reverse
|
||||
|
||||
@ -94,7 +94,7 @@ def work_weixin_oauth_callback(request):
|
||||
email = work_weixin_user.username
|
||||
is_new_user = False
|
||||
else:
|
||||
email = gen_user_virtual_id()
|
||||
email = None
|
||||
is_new_user = True
|
||||
|
||||
try:
|
||||
|
@ -11,6 +11,7 @@ from tests.common.common import USERNAME, PASSWORD, \
|
||||
|
||||
from tests.common.utils import apiurl, urljoin, randstring
|
||||
from tests.api.urls import TOKEN_URL, GROUPS_URL, ACCOUNTS_URL, REPOS_URL
|
||||
from seahub.base.accounts import User
|
||||
|
||||
class ApiTestBase(unittest.TestCase):
|
||||
_token = None
|
||||
@ -175,8 +176,11 @@ class ApiTestBase(unittest.TestCase):
|
||||
def create_user(self):
|
||||
username = '%s@test.com' % randstring(20)
|
||||
password = randstring(20)
|
||||
data = {'password': password}
|
||||
self.admin_put(urljoin(ACCOUNTS_URL, username), data=data, expected=201)
|
||||
user = User(email=username)
|
||||
user.is_staff = False
|
||||
user.is_active = True
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
return _User(username, password)
|
||||
|
||||
def remove_user(self, username):
|
||||
|
@ -1,276 +0,0 @@
|
||||
import json
|
||||
|
||||
from django.urls import reverse
|
||||
import seaserv
|
||||
from seaserv import seafile_api
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||
from seahub.profile.models import Profile
|
||||
from seahub.test_utils import BaseTestCase
|
||||
from tests.common.utils import randstring
|
||||
|
||||
class AccountTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.clear_cache()
|
||||
self.user1 = self.create_user('user_%s@test.com' % randstring(4),
|
||||
is_staff=False)
|
||||
self.user2 = self.create_user('user_%s@test.com' % randstring(4),
|
||||
is_staff=False)
|
||||
|
||||
def tearDown(self):
|
||||
self.remove_user(self.user1.username)
|
||||
self.remove_user(self.user2.username)
|
||||
|
||||
def _do_create(self):
|
||||
resp = self.client.put(
|
||||
reverse('api2-account', args=['new_user_put_create@test.com']),
|
||||
'password=123456&is_staff=1&is_active=1',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
# manually remove this account
|
||||
self.remove_user(email='new_user_put_create@test.com')
|
||||
return resp
|
||||
|
||||
def _do_get_info(self):
|
||||
return self.client.get(reverse('api2-account', args=[self.user1.email]))
|
||||
|
||||
def _do_migrate(self):
|
||||
return self.client.post(
|
||||
reverse('api2-account', args=[self.user1.username]), {
|
||||
'op': 'migrate',
|
||||
'to_user': self.user2.username,
|
||||
}
|
||||
)
|
||||
|
||||
def _do_update(self):
|
||||
return self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'password=654321&is_staff=1&is_active=0&name=user1&storage=102400&login_id=hello',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
|
||||
def _do_update_name(self):
|
||||
return self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'name=user1',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
|
||||
def _do_update_loginid(self):
|
||||
return self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'login_id=hello',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
|
||||
def _do_update_loginid_useemptystring(self):
|
||||
return self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'login_id=',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
|
||||
def _do_update_loginid_sendagain(self):
|
||||
self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'login_id=test',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
return self.client.put(
|
||||
reverse('api2-account', args=[self.user1.username]),
|
||||
'login_id=test',
|
||||
'application/x-www-form-urlencoded',
|
||||
)
|
||||
|
||||
def _do_delete(self):
|
||||
return self.client.delete(
|
||||
reverse('api2-account', args=[self.user1.username])
|
||||
)
|
||||
|
||||
def test_permission_error(self):
|
||||
self.login_as(self.user)
|
||||
|
||||
resp = self._do_create()
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
resp = self._do_get_info()
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
resp = self._do_update()
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
resp = self._do_migrate()
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
resp = self._do_delete()
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
def test_get_info(self):
|
||||
self.login_as(self.admin)
|
||||
|
||||
resp = self._do_get_info()
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 12
|
||||
assert json_resp['email'] == self.user1.username
|
||||
assert json_resp['is_staff'] is False
|
||||
assert json_resp['is_active'] is True
|
||||
assert json_resp['usage'] == 0
|
||||
|
||||
def test_create(self):
|
||||
self.login_as(self.admin)
|
||||
|
||||
resp = self._do_create()
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
def test_update(self):
|
||||
self.login_as(self.admin)
|
||||
|
||||
resp = self._do_update()
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
self.assertTrue(User.objects.get(self.user1.username).check_password(
|
||||
'654321'))
|
||||
self.assertTrue(User.objects.get(self.user1.username).is_staff)
|
||||
self.assertFalse(User.objects.get(self.user1.username).is_active)
|
||||
self.assertEqual(Profile.objects.get_profile_by_user(
|
||||
self.user1.username).login_id, 'hello')
|
||||
self.assertEqual(Profile.objects.get_profile_by_user(
|
||||
self.user1.username).nickname, 'user1')
|
||||
self.assertEqual(seafile_api.get_user_quota(
|
||||
self.user1.username), 102400000000)
|
||||
|
||||
def test_update_name(self):
|
||||
"""only test name"""
|
||||
self.login_as(self.admin)
|
||||
resp = self._do_update_name()
|
||||
self.assertEqual(Profile.objects.get_profile_by_user(
|
||||
self.user1.username).nickname, 'user1')
|
||||
|
||||
def test_update_loginid(self):
|
||||
"""only test loginid"""
|
||||
self.login_as(self.admin)
|
||||
resp = self._do_update_loginid()
|
||||
self.assertEqual(Profile.objects.get_profile_by_user(
|
||||
self.user1.username).login_id, 'hello')
|
||||
|
||||
def test_update_loginid_useemptystring(self):
|
||||
"""test loginid, longid send the empty"""
|
||||
self.login_as(self.admin)
|
||||
resp = self._do_update_loginid_useemptystring()
|
||||
self.assertEqual(400, resp.status_code)
|
||||
|
||||
def test_update_loginid_sendagain(self):
|
||||
"""test loginid,sent twice"""
|
||||
self.login_as(self.admin)
|
||||
resp = self._do_update_loginid_sendagain()
|
||||
self.assertEqual(400, resp.status_code)
|
||||
|
||||
def test_refresh_profile_cache_after_update(self):
|
||||
self.login_as(self.admin)
|
||||
self.assertEqual(email2nickname(self.user1.username),
|
||||
self.user1.username.split('@')[0])
|
||||
|
||||
resp = self._do_update()
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
self.assertEqual(email2nickname(self.user1.username), 'user1')
|
||||
|
||||
def test_migrate(self):
|
||||
self.login_as(self.admin)
|
||||
|
||||
# user1 created a repo
|
||||
user1_repo = self.create_repo(name='user1-repo', desc='',
|
||||
username=self.user1.username,
|
||||
passwd=None)
|
||||
user1_repos = seafile_api.get_owned_repo_list(self.user1.username)
|
||||
self.assertEqual(len(user1_repos), 1)
|
||||
self.assertEqual(user1_repos[0].id, user1_repo)
|
||||
|
||||
# user1 created a group and joined a group created by the other
|
||||
user1_group = self.create_group(group_name='test_group',
|
||||
username=self.user1.username)
|
||||
other_group = self.create_group(group_name='other_group',
|
||||
username=self.user.username)
|
||||
seaserv.ccnet_threaded_rpc.group_add_member(other_group.id,
|
||||
self.user.username,
|
||||
self.user1.username)
|
||||
|
||||
user1_groups = seaserv.get_personal_groups_by_user(self.user1.username)
|
||||
self.assertEqual(len(user1_groups), 2)
|
||||
|
||||
real_creator = sorted([self.user1.username, self.user.username])
|
||||
test_creator = sorted([x.creator_name for x in user1_groups])
|
||||
self.assertEqual(real_creator, test_creator)
|
||||
|
||||
real_id = sorted([user1_group.id, other_group.id])
|
||||
test_id = sorted([x.id for x in user1_groups])
|
||||
self.assertEqual(real_id, test_id)
|
||||
|
||||
# user2 had no repos
|
||||
user2_repos = seafile_api.get_owned_repo_list(self.user2.username)
|
||||
self.assertEqual(len(user2_repos), 0)
|
||||
# user2 had no groups
|
||||
user2_groups = seaserv.get_personal_groups_by_user(self.user2.username)
|
||||
self.assertEqual(len(user2_groups), 0)
|
||||
|
||||
# admin migrate account user1 to account user2
|
||||
resp = self._do_migrate()
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
### Verify ###
|
||||
# user1 should have no repos
|
||||
new_user1_repos = seafile_api.get_owned_repo_list(self.user1.username)
|
||||
self.assertEqual(len(new_user1_repos), 0)
|
||||
# user1 should still in two groups, except not the creator anymore in
|
||||
# the first group, but second group should remain the same
|
||||
user1_groups = seaserv.get_personal_groups_by_user(self.user1.username)
|
||||
self.assertEqual(len(user1_groups), 2)
|
||||
|
||||
real_creator = sorted([self.user1.username, self.user.username])
|
||||
test_creator = sorted([x.creator_name for x in user1_groups])
|
||||
self.assertNotEqual(real_creator, test_creator)
|
||||
|
||||
real_id = sorted([user1_group.id, other_group.id])
|
||||
test_id = sorted([x.id for x in user1_groups])
|
||||
self.assertEqual(real_id, test_id)
|
||||
|
||||
# user2 should have the repo used to be user1's
|
||||
new_user2_repos = seafile_api.get_owned_repo_list(self.user2.username)
|
||||
self.assertEqual(len(new_user2_repos), 1)
|
||||
self.assertEqual(new_user2_repos[0].id, user1_repo)
|
||||
# user2 should be in two groups, and is the creator of first group,
|
||||
# but second group should remain the same
|
||||
user2_groups = seaserv.get_personal_groups_by_user(self.user2.username)
|
||||
self.assertEqual(len(user2_groups), 2)
|
||||
|
||||
real_creator = sorted([self.user2.username, self.user.username])
|
||||
test_creator = sorted([x.creator_name for x in user2_groups])
|
||||
self.assertEqual(real_creator, test_creator)
|
||||
|
||||
real_id = sorted([user1_group.id, other_group.id])
|
||||
test_id = sorted([x.id for x in user2_groups])
|
||||
self.assertEqual(real_id, test_id)
|
||||
|
||||
def test_delete(self):
|
||||
self.login_as(self.admin)
|
||||
|
||||
resp = self._do_delete()
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
def test_new_user_get_info_after_edit_profile(self):
|
||||
new_user = self.create_user("test@new.user", is_staff=True)
|
||||
self.login_as(new_user)
|
||||
resp = self.client.post(reverse('edit_profile'), {
|
||||
'nickname': 'new nickname'
|
||||
})
|
||||
|
||||
resp = self.client.get(reverse('api2-account', args=[new_user.username]))
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 12
|
||||
assert json_resp['email'] == new_user.username
|
||||
assert json_resp['is_staff'] is True
|
||||
assert json_resp['is_active'] is True
|
||||
assert json_resp['usage'] == 0
|
||||
assert json_resp['institution'] == ''
|
||||
self.remove_user(new_user.username)
|
@ -72,12 +72,11 @@ class AdminUsersTest(BaseTestCase):
|
||||
|
||||
json_resp = json.loads(resp.content)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
assert json_resp['email'] == self.tmp_email
|
||||
assert json_resp['contact_email'] == self.tmp_email
|
||||
|
||||
ccnet_email = ccnet_api.get_emailuser(self.tmp_email)
|
||||
assert ccnet_email.email == self.tmp_email
|
||||
ccnet_email = ccnet_api.get_emailuser(json_resp['email'])
|
||||
|
||||
self.remove_user(self.tmp_email)
|
||||
self.remove_user(ccnet_email.email)
|
||||
|
||||
def test_create_with_invalid_user_permission(self):
|
||||
self.login_as(self.user)
|
||||
|
@ -78,7 +78,7 @@ class NotificationTest(BaseTestCase):
|
||||
|
||||
def test_permission_check_permission_denied(self):
|
||||
self.login_as(self.user)
|
||||
new_user = UserManager().create_user(email='new@new.com', password='root')
|
||||
new_user = self.create_user(email='new@new.com', password='root')
|
||||
notice_to_new_user = UserNotification.objects.add_user_message(new_user.name, 'test for new user')
|
||||
data = 'notice_id=%s' % notice_to_new_user.id
|
||||
|
||||
|
@ -1,37 +1,14 @@
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
from tests.common.utils import apiurl, urljoin, randstring
|
||||
from tests.common.utils import randstring
|
||||
from tests.api.apitestbase import ApiTestBase
|
||||
from tests.api.urls import ACCOUNTS_URL, PING_URL, \
|
||||
AUTH_PING_URL
|
||||
from tests.api.urls import PING_URL, AUTH_PING_URL
|
||||
|
||||
test_account_username = 'test_%s@test.com' % randstring(10)
|
||||
test_account_password = randstring(20)
|
||||
test_account_password2 = randstring(20)
|
||||
test_account_url = urljoin(ACCOUNTS_URL, test_account_username)
|
||||
|
||||
class AccountsApiTest(ApiTestBase):
|
||||
def test_list_accounts(self):
|
||||
# Normal user can not list accounts
|
||||
self.get(ACCOUNTS_URL, expected=403)
|
||||
accounts = self.admin_get(ACCOUNTS_URL).json()
|
||||
self.assertGreaterEqual(len(accounts), 2)
|
||||
# TODO: check returned json, test start/limit param
|
||||
|
||||
def test_create_delete_account(self):
|
||||
data = {'password': test_account_password}
|
||||
# non-admin user can not create new user
|
||||
self.put(test_account_url, data=data, expected=403)
|
||||
|
||||
self.admin_put(test_account_url, data=data, expected=201)
|
||||
|
||||
# non-admin user can not delete a user
|
||||
self.delete(test_account_url, expected=403)
|
||||
|
||||
self.admin_delete(test_account_url)
|
||||
# check the user is really deleted
|
||||
self.admin_get(test_account_url, expected=404)
|
||||
|
||||
def test_update_account_passwd(self):
|
||||
with self.get_tmp_user() as user:
|
||||
|
@ -60,7 +60,7 @@ class RepoOwnerTest(BaseTestCase):
|
||||
def test_reshare_to_user_after_transfer_repo(self):
|
||||
|
||||
tmp_user = 'tmp_user@email.com'
|
||||
User.objects.create_user(tmp_user)
|
||||
self.create_user(tmp_user)
|
||||
|
||||
# share user's repo to tmp_user with 'rw' permission
|
||||
seafile_api.share_repo(self.user_repo_id, self.user.username,
|
||||
@ -161,7 +161,7 @@ class RepoOwnerTest(BaseTestCase):
|
||||
def test_reshare_to_user_group_after_transfer_repo(self):
|
||||
|
||||
tmp_user = 'tmp_user@email.com'
|
||||
User.objects.create_user(tmp_user)
|
||||
self.create_user(tmp_user)
|
||||
|
||||
# add admin user to group
|
||||
ccnet_api.group_add_member(self.group_id, self.user_name, self.admin.username)
|
||||
|
@ -128,12 +128,3 @@ class AuthTokenSerializerTest(BaseTestCase):
|
||||
|
||||
s = AuthTokenSerializer(data=d, context={'request': self.fake_request})
|
||||
self.assertSuccess(s)
|
||||
|
||||
def test_primary_id(self):
|
||||
d = {
|
||||
'username': 'another_email@test.com',
|
||||
'password': self.user_password,
|
||||
}
|
||||
|
||||
s = AuthTokenSerializer(data=d, context={'request': self.fake_request})
|
||||
self.assertSuccess(s)
|
||||
|
@ -88,12 +88,3 @@ class AuthenticationFormTest(BaseTestCase):
|
||||
|
||||
form = AuthenticationForm(None, data)
|
||||
self.assertSuccess(form)
|
||||
|
||||
def test_primary_id(self):
|
||||
data = {
|
||||
'login': 'another_email@test.com',
|
||||
'password': self.user_password,
|
||||
}
|
||||
|
||||
form = AuthenticationForm(None, data)
|
||||
self.assertSuccess(form)
|
||||
|
@ -33,7 +33,7 @@ class UserTest(BaseTestCase):
|
||||
|
||||
assert len(UserOptions.objects.filter(email=test_email)) == 0
|
||||
|
||||
User.objects.create_user(test_email)
|
||||
self.create_user(test_email)
|
||||
UserOptions.objects.enable_server_crypto(test_email)
|
||||
|
||||
assert len(UserOptions.objects.filter(email=test_email)) == 1
|
||||
|
@ -22,8 +22,6 @@ class RegistrationTest(TestCase):
|
||||
user = RegistrationProfile.objects.create_inactive_user(site=self.site,
|
||||
send_email=False,
|
||||
**self.user_info)
|
||||
self.assertEqual(user.username, 'test@test.com')
|
||||
self.assertEqual(user.email, 'test@test.com')
|
||||
self.assertTrue(user.check_password('password'))
|
||||
self.assertFalse(user.is_active)
|
||||
|
||||
|
@ -21,7 +21,7 @@ class DemoTest(BaseTestCase):
|
||||
|
||||
@override_settings(ENABLE_DEMO_USER=True)
|
||||
def test_demo_user(self):
|
||||
u = User.objects.create_user(email=settings.CLOUD_DEMO_USER)
|
||||
u = self.create_user(email=settings.CLOUD_DEMO_USER)
|
||||
|
||||
resp = self.client.get(self.url)
|
||||
self.assertEqual(302, resp.status_code)
|
||||
|
@ -1,3 +1,5 @@
|
||||
import json
|
||||
|
||||
from django.urls import reverse
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db
|
||||
@ -24,16 +26,16 @@ class UserAddTest(BaseTestCase):
|
||||
email=self.new_user, option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
|
||||
resp = self.client.post(
|
||||
reverse('user_add',), {
|
||||
reverse('api-v2.1-admin-users',), {
|
||||
'email': self.new_user,
|
||||
'password1': '123',
|
||||
'password2': '123',
|
||||
}, HTTP_X_REQUESTED_WITH='XMLHttpRequest'
|
||||
'password': '123',
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
json_resp = json.loads(resp.content)
|
||||
assert UserOptions.objects.get(
|
||||
email=self.new_user,
|
||||
email=json_resp['email'],
|
||||
option_key=KEY_FORCE_PASSWD_CHANGE).option_val == VAL_FORCE_PASSWD_CHANGE
|
||||
|
||||
def test_can_add_when_pwd_change_not_required(self):
|
||||
@ -43,13 +45,13 @@ class UserAddTest(BaseTestCase):
|
||||
email=self.new_user, option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
|
||||
resp = self.client.post(
|
||||
reverse('user_add',), {
|
||||
reverse('api-v2.1-admin-users',), {
|
||||
'email': self.new_user,
|
||||
'password1': '123',
|
||||
'password2': '123',
|
||||
}, HTTP_X_REQUESTED_WITH='XMLHttpRequest'
|
||||
'password': '123',
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(UserOptions.objects.filter(
|
||||
email=self.new_user, option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
email=json_resp['email'], option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
|
@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.utils import send_html_email
|
||||
from seahub.profile.models import Profile
|
||||
|
||||
SHA1_RE = re.compile('^[a-f0-9]{40}$')
|
||||
|
||||
@ -281,8 +282,14 @@ class RegistrationProfile(models.Model):
|
||||
subject = ''.join(subject.splitlines())
|
||||
try:
|
||||
user = User.objects.get(id=self.emailuser_id)
|
||||
|
||||
send_to = user.username
|
||||
profile = Profile.objects.get_profile_by_user(user.username)
|
||||
if profile and profile.contact_email:
|
||||
send_to = profile.contact_email
|
||||
|
||||
send_html_email(subject, 'registration/activation_email.html',
|
||||
ctx_dict, None, [user.username])
|
||||
ctx_dict, None, [send_to])
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
@ -54,7 +54,7 @@ class ShibbolethRemoteUserBackend(RemoteUserBackend):
|
||||
|
||||
if not local_ccnet_users:
|
||||
if self.create_unknown_user:
|
||||
user = User.objects.create_user(
|
||||
user = User.objects.create_shib_user(
|
||||
email=username, is_active=self.activate_after_creation)
|
||||
if user and self.activate_after_creation is False:
|
||||
notify_admins_on_activate_request(user.email)
|
||||
|
Loading…
Reference in New Issue
Block a user