Esempio n. 1
0
    def create_ldap_user(self,
                         email=None,
                         password=None,
                         nickname=None,
                         is_staff=False,
                         is_active=False):
        """
        Creates and saves an 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)
Esempio n. 2
0
    def post(self, request):

        # parameter check
        user_list = request.data.get('userlist', [])
        if not user_list:
            error_msg = 'userlist invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # permission check
        if not ENABLE_DINGTALK:
            error_msg = 'Feature is not enabled.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if not request.user.admin_permissions.can_manage_user():
            return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')

        user_ids_in_db = []
        auth_users = SocialAuthUser.objects.filter(provider='dingtalk')
        for user in auth_users:
            user_ids_in_db.append(user.uid)

        success = []
        failed = []

        for user in user_list:

            user_id = user.get('userid')

            if user_id in user_ids_in_db:
                failed.append({
                    'userid': user_id,
                    'name': user.get('name'),
                    'error_msg': '用户已存在',
                })
                continue

            email = gen_user_virtual_id()
            try:
                User.objects.create_user(email)
                SocialAuthUser.objects.add(email, 'dingtalk', user_id)
                success.append({
                    'userid': user_id,
                    'name': user.get('name'),
                    'email': email,
                })
            except Exception as e:
                logger.error(e)
                failed.append({
                    'userid': user_id,
                    'name': user.get('name'),
                    'error_msg': '导入失败'
                })

            try:
                update_dingtalk_user_info(email, user.get('name'),
                        user.get('contact_email'), user.get('avatar'))
            except Exception as e:
                logger.error(e)

        return Response({'success': success, 'failed': failed})
Esempio n. 3
0
def get_username(strategy, details, backend, user=None, *args, **kwargs):
    if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS):
        return
    storage = strategy.storage

    if not user:
        final_username = gen_user_virtual_id()
    else:
        final_username = storage.user.get_username(user)

    return {'username': final_username}
Esempio n. 4
0
def get_username(strategy, details, backend, user=None, *args, **kwargs):
    if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS):
        return
    storage = strategy.storage

    if not user:
        final_username = gen_user_virtual_id()
    else:
        final_username = storage.user.get_username(user)

    return {'username': final_username}
Esempio n. 5
0
    def post(self, request):
        if not admin_work_weixin_departments_check():
            error_msg = 'Feature is not enabled.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if not request.user.admin_permissions.can_manage_user():
            return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')

        api_user_list = request.data.get(WORK_WEIXIN_DEPARTMENT_MEMBERS_FIELD,
                                         None)
        if not api_user_list or not isinstance(api_user_list, list):
            error_msg = 'userlist invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        success = []
        failed = []
        social_auth_queryset = SocialAuthUser.objects.filter(
            provider=WORK_WEIXIN_PROVIDER,
            uid__contains=WORK_WEIXIN_UID_PREFIX)

        for api_user in api_user_list:

            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):
                    success.append({
                        'userid': api_user.get('userid'),
                        'name': api_user.get('name'),
                        'email': email,
                    })
                else:
                    failed.append({
                        'userid': api_user.get('userid'),
                        'name': api_user.get('name'),
                        'error_msg': '导入失败'
                    })
            else:
                failed.append(error_data)

        return Response({'success': success, 'failed': failed})
Esempio n. 6
0
    def create_user(self,
                    email,
                    password=None,
                    is_staff=False,
                    is_active=False):
        """
        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)
Esempio n. 7
0
    def post(self, request):
        """import department from work weixin

        permission: IsProVersion
        """

        if not request.user.admin_permissions.can_manage_user():
            return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')

        # argument check
        department_id = request.data.get('work_weixin_department_id')
        try:
            department_id = int(department_id)
        except Exception as e:
            logger.error(e)
            error_msg = 'work_weixin_department_ids invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # is pro version and work weixin check
        if not IsProVersion or not admin_work_weixin_departments_check():
            error_msg = 'Feature is not enabled.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        access_token = get_work_weixin_access_token()
        if not access_token:
            logger.error('can not get work weixin access_token')
            error_msg = '获取企业微信组织架构失败'
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # list departments from work weixin
        api_department_list = self._list_departments_from_work_weixin(
            access_token, department_id)
        if api_department_list is None:
            error_msg = '获取企业微信组织架构失败'
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # list department members from work weixin
        api_user_list = self._list_department_members_from_work_weixin(
            access_token, department_id)
        if api_user_list is None:
            error_msg = '获取企业微信组织架构成员失败'
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # main
        success = list()
        failed = list()
        department_map_to_group_dict = dict()

        for index, department_obj in enumerate(api_department_list):
            # check department argument
            new_group_name = department_obj.get('name')
            department_obj_id = department_obj.get('id')
            if department_obj_id is None or not new_group_name or not validate_group_name(
                    new_group_name):
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门参数错误')
                failed.append(failed_msg)
                continue

            # check parent group
            if index == 0:
                parent_group_id = -1
            else:
                parent_department_id = department_obj.get('parentid')
                parent_group_id = department_map_to_group_dict.get(
                    parent_department_id)

            if parent_group_id is None:
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '父级部门不存在')
                failed.append(failed_msg)
                continue

            # check department exist by group name
            exist, exist_group = self._admin_check_group_name_conflict(
                new_group_name)
            if exist:
                department_map_to_group_dict[
                    department_obj_id] = exist_group.id
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门已存在')
                failed.append(failed_msg)
                continue

            # import department
            try:
                group_id = ccnet_api.create_group(
                    new_group_name,
                    DEPARTMENT_OWNER,
                    parent_group_id=parent_group_id)

                seafile_api.set_group_quota(group_id, -2)

                department_map_to_group_dict[department_obj_id] = group_id
                success_msg = self._api_department_success_msg(
                    department_obj_id, new_group_name, group_id)
                success.append(success_msg)
            except Exception as e:
                logger.error(e)
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门导入失败')
                failed.append(failed_msg)

        # todo filter ccnet User database
        social_auth_queryset = SocialAuthUser.objects.filter(
            provider=WORK_WEIXIN_PROVIDER,
            uid__contains=WORK_WEIXIN_UID_PREFIX)

        # import api_user
        for api_user in api_user_list:
            uid = WORK_WEIXIN_UID_PREFIX + api_user.get('userid', '')
            api_user['contact_email'] = api_user['email']
            api_user_name = api_user.get('name')

            #  determine the user exists
            if social_auth_queryset.filter(uid=uid).exists():
                email = social_auth_queryset.get(uid=uid).username
            else:
                # create user
                email = gen_user_virtual_id()
                create_user_success = _import_user_from_work_weixin(
                    email, api_user)
                if not create_user_success:
                    failed_msg = self._api_user_failed_msg(
                        '', api_user_name, department_id, '导入用户失败')
                    failed.append(failed_msg)
                    continue

            # bind user to department
            api_user_department_list = api_user.get('department')
            for department_obj_id in api_user_department_list:
                group_id = department_map_to_group_dict.get(department_obj_id)
                if group_id is None:
                    # the api_user also exist in the brother department which not import
                    continue

                if ccnet_api.is_group_user(group_id, email):
                    failed_msg = self._api_user_failed_msg(
                        email, api_user_name, department_obj_id, '部门成员已存在')
                    failed.append(failed_msg)
                    continue

                try:
                    ccnet_api.group_add_member(group_id, DEPARTMENT_OWNER,
                                               email)
                    success_msg = self._api_user_success_msg(
                        email, api_user_name, department_obj_id, group_id)
                    success.append(success_msg)
                except Exception as e:
                    logger.error(e)
                    failed_msg = self._api_user_failed_msg(
                        email, api_user_name, department_id, '导入部门成员失败')
                    failed.append(failed_msg)

        return Response({
            'success': success,
            'failed': failed,
        })
Esempio n. 8
0
def work_weixin_oauth_callback(request):
    if not work_weixin_oauth_check():
        return render_error(request, _('Feature is not enabled.'))

    code = request.GET.get('code', None)
    state = request.GET.get('state', None)
    if state != request.session.get('work_weixin_oauth_state',
                                    None) or not code:
        logger.error(
            'can not get right code or state from work weixin request')
        return render_error(request, _('Error, please contact administrator.'))

    access_token = get_work_weixin_access_token()
    if not access_token:
        logger.error('can not get work weixin access_token')
        return render_error(request, _('Error, please contact administrator.'))

    data = {
        'access_token': access_token,
        'code': code,
    }
    api_response = requests.get(WORK_WEIXIN_GET_USER_INFO_URL, params=data)
    api_response_dic = handler_work_weixin_api_response(api_response)
    if not api_response_dic:
        logger.error('can not get work weixin user info')
        return render_error(request, _('Error, please contact administrator.'))

    if not api_response_dic.get('UserId', None):
        logger.error('can not get UserId in work weixin user info response')
        return render_error(request, _('Error, please contact administrator.'))

    user_id = api_response_dic.get('UserId')
    uid = WORK_WEIXIN_UID_PREFIX + user_id

    work_weixin_user = SocialAuthUser.objects.get_by_provider_and_uid(
        WORK_WEIXIN_PROVIDER, uid)
    if work_weixin_user:
        email = work_weixin_user.username
        is_new_user = False
    else:
        email = gen_user_virtual_id()
        SocialAuthUser.objects.add(email, WORK_WEIXIN_PROVIDER, uid)
        is_new_user = True

    try:
        user = auth.authenticate(remote_user=email)
    except User.DoesNotExist:
        user = None

    if not user:
        return render_error(
            request,
            _('Error, new user registration is not allowed, please contact administrator.'
              ))

    # update user info
    if is_new_user or WORK_WEIXIN_USER_INFO_AUTO_UPDATE:
        user_info_data = {
            'access_token': access_token,
            'userid': user_id,
        }
        user_info_api_response = requests.get(WORK_WEIXIN_GET_USER_PROFILE_URL,
                                              params=user_info_data)
        user_info_api_response_dic = handler_work_weixin_api_response(
            user_info_api_response)
        if user_info_api_response_dic:
            api_user = user_info_api_response_dic
            api_user['username'] = email
            api_user['contact_email'] = api_user['email']
            update_work_weixin_user_info(api_user)

    if not user.is_active:
        return render_error(
            request,
            _('Your account is created successfully, please wait for administrator to activate your account.'
              ))

    # User is valid.  Set request.user and persist user in the session
    # by logging the user in.
    request.user = user
    auth.login(request, user)

    # generate auth token for Seafile client
    api_token = get_api_token(request)

    # redirect user to page
    response = HttpResponseRedirect(
        request.session.get('work_weixin_oauth_redirect', '/'))
    response.set_cookie('seahub_auth', user.username + '@' + api_token.key)
    return response
Esempio n. 9
0
def weixin_oauth_callback(request):

    if not ENABLE_WEIXIN:
        return render_error(request, _('Error, please contact administrator.'))

    state = request.GET.get('state', '')
    if not state or state != request.session.get('weixin_oauth_login_state', ''):
        logger.error('invalid state')
        return render_error(request, _('Error, please contact administrator.'))

    # get access_token and user openid
    parameters = {
        'appid': WEIXIN_OAUTH_APP_ID,
        'secret': WEIXIN_OAUTH_APP_SECRET,
        'code': request.GET.get('code'),
        'grant_type': WEIXIN_OAUTH_GRANT_TYPE,
    }

    access_token_url = WEIXIN_OAUTH_ACCESS_TOKEN_URL + '?' + urllib.parse.urlencode(parameters)
    access_token_json = requests.get(access_token_url).json()

    openid = access_token_json.get('openid', '')
    access_token = access_token_json.get('access_token', '')
    if not access_token or not openid:
        logger.error('invalid access_token or openid')
        logger.error(access_token_url)
        logger.error(access_token_json)
        return render_error(request, _('Error, please contact administrator.'))

    # login user in
    auth_user = SocialAuthUser.objects.get_by_provider_and_uid('weixin', openid)
    if auth_user:
        email = auth_user.username
    else:
        email = gen_user_virtual_id()
        SocialAuthUser.objects.add(email, 'weixin', openid)

    try:
        user = auth.authenticate(remote_user=email)
    except User.DoesNotExist:
        user = None
    except Exception as e:
        logger.error(e)
        return render_error(request, _('Error, please contact administrator.'))

    if not user or not user.is_active:
        return render_error(request, _('User %s not found or inactive.') % email)

    request.user = user
    auth.login(request, user)

    # get user profile info
    parameters = {
        'access_token': access_token,
        'openid': openid,
    }
    user_info_url = WEIXIN_OAUTH_USER_INFO_URL + '?' + urllib.parse.urlencode(parameters)
    user_info_resp = requests.get(user_info_url).json()

    name = user_info_resp['nickname'] if 'nickname' in user_info_resp else ''
    name = name.encode('raw_unicode_escape').decode('utf-8')
    if name:

        profile = Profile.objects.get_profile_by_user(email)
        if not profile:
            profile = Profile(user=email)

        profile.nickname = name.strip()
        profile.save()

    avatar_url = user_info_resp['headimgurl'] if 'headimgurl' in user_info_resp else ''
    try:
        image_name = 'dingtalk_avatar'
        image_file = requests.get(avatar_url).content
        avatar = Avatar.objects.filter(emailuser=email, primary=True).first()
        avatar = avatar or Avatar(emailuser=email, primary=True)
        avatar_file = ContentFile(image_file)
        avatar_file.name = image_name
        avatar.avatar = avatar_file
        avatar.save()
    except Exception as e:
        logger.error(e)

    # generate auth token for Seafile client
    api_token = get_api_token(request)

    # redirect user to home page
    response = HttpResponseRedirect(request.session['weixin_oauth_login_redirect'])
    response.set_cookie('seahub_auth', email + '@' + api_token.key)
    return response
Esempio n. 10
0
    def post(self, request):
        """import department from dingtalk
        """

        if not ENABLE_DINGTALK:
            error_msg = 'Feature is not enabled.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if not request.user.admin_permissions.can_manage_user():
            return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')

        # argument check
        department_id = request.data.get('department_id')
        try:
            department_id = int(department_id)
        except Exception as e:
            logger.error(e)
            error_msg = 'department_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        access_token = dingtalk_get_access_token()
        if not access_token:
            error_msg = '获取钉钉组织架构失败'
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # get department list
        # https://developers.dingtalk.com/document/app/obtain-the-department-list
        data = {'access_token': access_token, 'id': department_id}
        current_department_resp_json = requests.get(DINGTALK_DEPARTMENT_GET_DEPARTMENT_URL, params=data).json()
        current_department_list = [current_department_resp_json]
        sub_department_resp_json = requests.get(DINGTALK_DEPARTMENT_LIST_DEPARTMENT_URL, params=data).json()
        sub_department_list = sub_department_resp_json.get('department', [])
        department_list = current_department_list + sub_department_list
        department_list = sorted(department_list, key=lambda x:x['id'])

        # get department user list
        data = {
            'access_token': access_token,
            'department_id': department_id,
            'offset': 0,
            'size': DINGTALK_DEPARTMENT_USER_SIZE,
        }
        user_resp_json = requests.get(DINGTALK_DEPARTMENT_GET_DEPARTMENT_USER_LIST_URL, params=data).json()
        api_user_list = user_resp_json.get('userlist', [])

        # main
        success = list()
        failed = list()
        department_map_to_group_dict = dict()

        for index, department_obj in enumerate(department_list):
            # check department argument
            new_group_name = department_obj.get('name')
            department_obj_id = department_obj.get('id')
            parent_department_id = department_obj.get('parentid', 0)
            if department_obj_id is None or not new_group_name or not validate_group_name(new_group_name):
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门参数错误')
                failed.append(failed_msg)
                continue

            # check parent group
            if index == 0:
                parent_group_id = -1
            else:
                parent_group_id = department_map_to_group_dict.get(parent_department_id)

            if parent_group_id is None:
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '父级部门不存在')
                failed.append(failed_msg)
                continue

            # check department exist
            exist_department = ExternalDepartment.objects.get_by_provider_and_outer_id(
                DINGTALK_PROVIDER, department_obj_id)
            if exist_department:
                department_map_to_group_dict[department_obj_id] = exist_department.group_id
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门已存在')
                failed.append(failed_msg)
                continue

            # import department
            try:
                group_id = ccnet_api.create_group(
                    new_group_name, DEPARTMENT_OWNER, parent_group_id=parent_group_id)

                seafile_api.set_group_quota(group_id, -2)

                ExternalDepartment.objects.create(
                    group_id=group_id,
                    provider=DINGTALK_PROVIDER,
                    outer_id=department_obj_id,
                )

                department_map_to_group_dict[department_obj_id] = group_id
                success_msg = self._api_department_success_msg(
                    department_obj_id, new_group_name, group_id)
                success.append(success_msg)
            except Exception as e:
                logger.error(e)
                failed_msg = self._api_department_failed_msg(
                    department_obj_id, new_group_name, '部门导入失败')
                failed.append(failed_msg)

        # todo filter ccnet User database
        social_auth_queryset = SocialAuthUser.objects.filter(provider='dingtalk')

        # import api_user
        for api_user in api_user_list:
            uid = api_user.get('unionid', '')
            api_user['contact_email'] = api_user['email']
            api_user_name = api_user.get('name')

            #  determine the user exists
            if social_auth_queryset.filter(uid=uid).exists():
                email = social_auth_queryset.get(uid=uid).username
            else:
                # create user
                email = gen_user_virtual_id()
                try:
                    User.objects.create_user(email)
                    SocialAuthUser.objects.add(email, 'dingtalk', uid)
                except Exception as e:
                    logger.error(e)
                    failed_msg = self._api_user_failed_msg(
                        '', api_user_name, department_id, '导入用户失败')
                    failed.append(failed_msg)
                    continue

            # bind user to department
            api_user_department_list = api_user.get('department')
            for department_obj_id in api_user_department_list:
                group_id = department_map_to_group_dict.get(department_obj_id)
                if group_id is None:
                    # the api_user also exist in the brother department which not import
                    continue

                if ccnet_api.is_group_user(group_id, email, in_structure=False):
                    failed_msg = self._api_user_failed_msg(
                        email, api_user_name, department_obj_id, '部门成员已存在')
                    failed.append(failed_msg)
                    continue

                try:
                    ccnet_api.group_add_member(group_id, DEPARTMENT_OWNER, email)
                    success_msg = self._api_user_success_msg(
                        email, api_user_name, department_obj_id, group_id)
                    success.append(success_msg)
                except Exception as e:
                    logger.error(e)
                    failed_msg = self._api_user_failed_msg(
                        email, api_user_name, department_id, '导入部门成员失败')
                    failed.append(failed_msg)

                try:
                    update_dingtalk_user_info(email,
                                              api_user.get('name'),
                                              api_user.get('contact_email'),
                                              api_user.get('avatar'))
                except Exception as e:
                    logger.error(e)

        return Response({
            'success': success,
            'failed': failed,
        })
Esempio n. 11
0
def dingtalk_callback(request):

    if not ENABLE_DINGTALK:
        return render_error(request, _('Error, please contact administrator.'))

    state = request.GET.get('state', '')
    if not state or state != request.session.get('dingtalk_login_state', ''):
        logger.error('invalid state')
        return render_error(request, _('Error, please contact administrator.'))

    timestamp = str(int(time.time() * 1000)).encode('utf-8')
    appsecret = DINGTALK_QR_CONNECT_APP_SECRET.encode('utf-8')
    signature = base64.b64encode(
        hmac.new(appsecret, timestamp, digestmod=sha256).digest())
    parameters = {
        'accessKey': DINGTALK_QR_CONNECT_APP_ID,
        'timestamp': timestamp,
        'signature': signature,
    }

    code = request.GET.get('code')
    data = {"tmp_auth_code": code}

    full_user_info_url = DINGTALK_QR_CONNECT_USER_INFO_URL + '?' + urllib.parse.urlencode(
        parameters)
    user_info_resp = requests.post(full_user_info_url, data=json.dumps(data))
    user_info = user_info_resp.json()['user_info']

    # seahub authenticate user
    if 'unionid' not in user_info:
        logger.error('Required user info not found.')
        logger.error(user_info)
        return render_error(request, _('Error, please contact administrator.'))

    auth_user = SocialAuthUser.objects.get_by_provider_and_uid(
        'dingtalk', user_info['unionid'])
    if auth_user:
        email = auth_user.username
    else:
        email = gen_user_virtual_id()
        SocialAuthUser.objects.add(email, 'dingtalk', user_info['unionid'])

    try:
        user = auth.authenticate(remote_user=email)
    except User.DoesNotExist:
        user = None
    except Exception as e:
        logger.error(e)
        return render_error(request, _('Error, please contact administrator.'))

    if not user or not user.is_active:
        return render_error(request,
                            _('User %s not found or inactive.') % email)

    # User is valid.  Set request.user and persist user in the session
    # by logging the user in.
    request.user = user
    request.session['remember_me'] = DINGTALK_QR_CONNECT_LOGIN_REMEMBER_ME
    auth.login(request, user)

    # update user's profile
    name = user_info['nick'] if 'nick' in user_info else ''
    if name:

        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()

    # generate auth token for Seafile client
    api_token = get_api_token(request)

    # redirect user to home page
    response = HttpResponseRedirect(
        request.session.get('dingtalk_login_redirect', '/'))
    response.set_cookie('seahub_auth', email + '@' + api_token.key)
    return response