api.py 11.4 KB
Newer Older
baltery's avatar
baltery 已提交
1 2 3 4
# -*- coding: utf-8 -*-
#

import json
E
Eric 已提交
5
from collections.abc import Iterable
baltery's avatar
baltery 已提交
6
from smtplib import SMTPSenderRefused
7
from rest_framework import generics
八千流 已提交
8 9
from rest_framework.views import Response, APIView
from django.conf import settings
10
from django.core.mail import send_mail, get_connection
baltery's avatar
baltery 已提交
11
from django.utils.translation import ugettext_lazy as _
12
from rest_framework import serializers
baltery's avatar
baltery 已提交
13

14 15
from .utils import (
    LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil,
E
Eric 已提交
16
    LDAP_USE_CACHE_FLAGS, LDAPTestUtil, ObjectDict
17 18
)
from .tasks import sync_ldap_user_task
八千流 已提交
19
from common.permissions import IsOrgAdmin, IsSuperUser
20
from common.utils import get_logger
baltery's avatar
baltery 已提交
21
from .serializers import (
baltery's avatar
baltery 已提交
22
    MailTestSerializer, LDAPTestConfigSerializer, LDAPUserSerializer,
E
Eric 已提交
23
    PublicSettingSerializer, LDAPTestLoginSerializer, SettingsSerializer
baltery's avatar
baltery 已提交
24
)
25
from users.models import User
baltery's avatar
baltery 已提交
26

27 28 29
logger = get_logger(__file__)


baltery's avatar
baltery 已提交
30
class MailTestingAPI(APIView):
31
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
32 33 34 35 36 37
    serializer_class = MailTestSerializer
    success_message = _("Test mail sent to {}, please check")

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
38 39 40 41
            email_host = serializer.validated_data['EMAIL_HOST']
            email_port = serializer.validated_data['EMAIL_PORT']
            email_host_user = serializer.validated_data["EMAIL_HOST_USER"]
            email_host_password = serializer.validated_data['EMAIL_HOST_PASSWORD']
42
            email_from = serializer.validated_data["EMAIL_FROM"]
43
            email_recipient = serializer.validated_data["EMAIL_RECIPIENT"]
44 45 46 47 48 49 50
            email_use_ssl = serializer.validated_data['EMAIL_USE_SSL']
            email_use_tls = serializer.validated_data['EMAIL_USE_TLS']

            # 设置 settings 的值,会导致动态配置在当前进程失效
            # for k, v in serializer.validated_data.items():
            #     if k.startswith('EMAIL'):
            #         setattr(settings, k, v)
baltery's avatar
baltery 已提交
51 52 53
            try:
                subject = "Test"
                message = "Test smtp setting"
54
                email_from = email_from or email_host_user
55
                email_recipient = email_recipient or email_from
56 57 58 59 60 61
                connection = get_connection(
                    host=email_host, port=email_port,
                    uesrname=email_host_user, password=email_host_password,
                    use_tls=email_use_tls, use_ssl=email_use_ssl,
                )
                send_mail(
E
Eric 已提交
62
                    subject, message, email_from, [email_recipient],
63 64
                    connection=connection
                )
baltery's avatar
baltery 已提交
65 66 67 68 69 70 71 72 73 74
            except SMTPSenderRefused as e:
                resp = e.smtp_error
                if isinstance(resp, bytes):
                    for coding in ('gbk', 'utf8'):
                        try:
                            resp = resp.decode(coding)
                        except UnicodeDecodeError:
                            continue
                        else:
                            break
75
                return Response({"error": str(resp)}, status=400)
baltery's avatar
baltery 已提交
76
            except Exception as e:
baltery's avatar
baltery 已提交
77
                print(e)
78
                return Response({"error": str(e)}, status=400)
79
            return Response({"msg": self.success_message.format(email_recipient)})
baltery's avatar
baltery 已提交
80
        else:
81
            return Response({"error": str(serializer.errors)}, status=400)
baltery's avatar
baltery 已提交
82 83


baltery's avatar
baltery 已提交
84
class LDAPTestingConfigAPI(APIView):
85
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
86 87 88 89 90
    serializer_class = LDAPTestConfigSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if not serializer.is_valid():
91
            return Response({"error": str(serializer.errors)}, status=400)
baltery's avatar
baltery 已提交
92 93
        config = self.get_ldap_config(serializer)
        ok, msg = LDAPTestUtil(config).test_config()
94
        status = 200 if ok else 400
baltery's avatar
baltery 已提交
95
        return Response(msg, status=status)
baltery's avatar
baltery 已提交
96

97
    @staticmethod
98 99
    def get_ldap_config(serializer):
        server_uri = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
100 101 102
        bind_dn = serializer.validated_data["AUTH_LDAP_BIND_DN"]
        password = serializer.validated_data["AUTH_LDAP_BIND_PASSWORD"]
        use_ssl = serializer.validated_data.get("AUTH_LDAP_START_TLS", False)
baltery's avatar
baltery 已提交
103
        search_ou = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
104 105
        search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
        attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
baltery's avatar
baltery 已提交
106
        auth_ldap = serializer.validated_data.get('AUTH_LDAP', False)
107 108 109 110 111
        config = {
            'server_uri': server_uri,
            'bind_dn': bind_dn,
            'password': password,
            'use_ssl': use_ssl,
baltery's avatar
baltery 已提交
112
            'search_ou': search_ou,
113
            'search_filter': search_filter,
baltery's avatar
baltery 已提交
114 115
            'attr_map': attr_map,
            'auth_ldap': auth_ldap
116 117
        }
        return config
118

baltery's avatar
baltery 已提交
119 120 121 122 123

class LDAPTestingLoginAPI(APIView):
    permission_classes = (IsSuperUser,)
    serializer_class = LDAPTestLoginSerializer

baltery's avatar
baltery 已提交
124 125
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
126
        if not serializer.is_valid():
127
            return Response({"error": str(serializer.errors)}, status=400)
baltery's avatar
baltery 已提交
128 129 130
        username = serializer.validated_data['username']
        password = serializer.validated_data['password']
        ok, msg = LDAPTestUtil().test_login(username, password)
131
        status = 200 if ok else 400
baltery's avatar
baltery 已提交
132
        return Response(msg, status=status)
baltery's avatar
baltery 已提交
133 134


135
class LDAPUserListApi(generics.ListAPIView):
136
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
137
    serializer_class = LDAPUserSerializer
八千流 已提交
138

139 140 141 142 143 144 145 146 147 148
    def get_queryset_from_cache(self):
        search_value = self.request.query_params.get('search')
        users = LDAPCacheUtil().search(search_value=search_value)
        return users

    def get_queryset_from_server(self):
        search_value = self.request.query_params.get('search')
        users = LDAPServerUtil().search(search_value=search_value)
        return users

149
    def get_queryset(self):
baltery's avatar
baltery 已提交
150 151
        if hasattr(self, 'swagger_fake_view'):
            return []
152 153 154 155 156
        cache_police = self.request.query_params.get('cache_police', True)
        if cache_police in LDAP_USE_CACHE_FLAGS:
            users = self.get_queryset_from_cache()
        else:
            users = self.get_queryset_from_server()
157 158
        return users

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    @staticmethod
    def processing_queryset(queryset):
        db_username_list = User.objects.all().values_list('username', flat=True)
        for q in queryset:
            q['id'] = q['username']
            q['existing'] = q['username'] in db_username_list
        return queryset

    def sort_queryset(self, queryset):
        order_by = self.request.query_params.get('order')
        if not order_by:
            order_by = 'existing'
        if order_by.startswith('-'):
            order_by = order_by.lstrip('-')
            reverse = True
        else:
            reverse = False
        queryset = sorted(queryset, key=lambda x: x[order_by], reverse=reverse)
        return queryset

    def filter_queryset(self, queryset):
        if queryset is None:
            return queryset
        queryset = self.processing_queryset(queryset)
        queryset = self.sort_queryset(queryset)
        return queryset

186 187 188 189 190 191
    def list(self, request, *args, **kwargs):
        cache_police = self.request.query_params.get('cache_police', True)
        # 不是用缓存
        if cache_police not in LDAP_USE_CACHE_FLAGS:
            return super().list(request, *args, **kwargs)

192 193 194 195 196 197
        try:
            queryset = self.get_queryset()
        except Exception as e:
            data = {'error': str(e)}
            return Response(data=data, status=400)

198 199 200 201 202 203 204
        # 缓存有数据
        if queryset is not None:
            return super().list(request, *args, **kwargs)

        sync_util = LDAPSyncUtil()
        # 还没有同步任务
        if sync_util.task_no_start:
205 206
            # 任务外部设置 task running 状态
            sync_util.set_task_status(sync_util.TASK_STATUS_IS_RUNNING)
207 208 209 210 211 212 213 214 215 216
            task = sync_ldap_user_task.delay()
            data = {'msg': 'Cache no data, sync task {} started.'.format(task.id)}
            return Response(data=data, status=409)
        # 同步任务正在执行
        if sync_util.task_is_running:
            data = {'msg': 'synchronization is running.'}
            return Response(data=data, status=409)
        # 同步任务执行结束
        if sync_util.task_is_over:
            msg = sync_util.get_task_error_msg()
217
            data = {'error': 'Synchronization task report error: {}'.format(msg)}
218 219 220 221
            return Response(data=data, status=400)

        return super().list(request, *args, **kwargs)

八千流 已提交
222

223
class LDAPUserImportAPI(APIView):
224
    permission_classes = (IsSuperUser,)
八千流 已提交
225

226 227 228 229 230 231 232 233 234
    def get_ldap_users(self):
        username_list = self.request.data.get('username_list', [])
        cache_police = self.request.query_params.get('cache_police', True)
        if cache_police in LDAP_USE_CACHE_FLAGS:
            users = LDAPCacheUtil().search(search_users=username_list)
        else:
            users = LDAPServerUtil().search(search_users=username_list)
        return users

八千流 已提交
235
    def post(self, request):
236 237 238
        try:
            users = self.get_ldap_users()
        except Exception as e:
239
            return Response({'error': str(e)}, status=400)
240 241

        if users is None:
242
            return Response({'msg': _('Get ldap users is None')}, status=400)
243

244 245
        errors = LDAPImportUtil().perform_import(users)
        if errors:
246
            return Response({'errors': errors}, status=400)
247 248

        count = users if users is None else len(users)
B
BaiJiangJie 已提交
249
        return Response({'msg': _('Imported {} users successfully').format(count)})
250

251

252
class LDAPCacheRefreshAPI(generics.RetrieveAPIView):
253
    permission_classes = (IsSuperUser,)
254 255

    def retrieve(self, request, *args, **kwargs):
256
        try:
257
            LDAPSyncUtil().clear_cache()
258
        except Exception as e:
259 260 261
            logger.error(str(e))
            return Response(data={'msg': str(e)}, status=400)
        return Response(data={'msg': 'success'})
八千流 已提交
262 263


baltery's avatar
baltery 已提交
264 265 266 267 268 269 270
class PublicSettingApi(generics.RetrieveAPIView):
    permission_classes = ()
    serializer_class = PublicSettingSerializer

    def get_object(self):
        instance = {
            "data": {
271 272
                "WINDOWS_SKIP_ALL_MANUAL_PASSWORD": settings.WINDOWS_SKIP_ALL_MANUAL_PASSWORD,
                "SECURITY_MAX_IDLE_TIME": settings.SECURITY_MAX_IDLE_TIME,
baltery's avatar
baltery 已提交
273 274
                "XPACK_ENABLED": settings.XPACK_ENABLED,
                "XPACK_LICENSE_IS_VALID": settings.XPACK_LICENSE_IS_VALID
baltery's avatar
baltery 已提交
275 276 277 278 279
            }
        }
        return instance


E
Eric 已提交
280
class SettingsApi(generics.RetrieveUpdateAPIView):
281
    permission_classes = (IsSuperUser,)
E
Eric 已提交
282
    serializer_class = SettingsSerializer
E
Eric 已提交
283

E
Eric 已提交
284
    def get_object(self):
285 286 287
        instance = {category: self._get_setting_fields_obj(list(category_serializer.get_fields()))
                    for category, category_serializer in self.serializer_class().get_fields().items()
                    if isinstance(category_serializer, serializers.Serializer)}
E
Eric 已提交
288
        return ObjectDict(instance)
E
Eric 已提交
289

E
Eric 已提交
290 291
    def perform_update(self, serializer):
        serializer.save()
E
Eric 已提交
292

E
Eric 已提交
293 294 295 296 297
    def _get_setting_fields_obj(self, category_fields):
        if isinstance(category_fields, Iterable):
            fields_data = {field_name: getattr(settings, field_name)
                           for field_name in category_fields}
            return ObjectDict(fields_data)
E
Eric 已提交
298

E
Eric 已提交
299 300 301
        if isinstance(category_fields, str):
            fields_data = {category_fields: getattr(settings, category_fields)}
            return ObjectDict(fields_data)
E
Eric 已提交
302

E
Eric 已提交
303
        return ObjectDict()