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

import os
import json
import jms_storage

baltery's avatar
baltery 已提交
8
from smtplib import SMTPSenderRefused
9
from rest_framework import generics
八千流 已提交
10 11
from rest_framework.views import Response, APIView
from django.conf import settings
baltery's avatar
baltery 已提交
12 13 14 15
from django.core.mail import send_mail
from django.utils.translation import ugettext_lazy as _

from .models import Setting
16 17 18 19 20 21
from .utils import (
    LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil,
    LDAP_USE_CACHE_FLAGS

)
from .tasks import sync_ldap_user_task
八千流 已提交
22
from common.permissions import IsOrgAdmin, IsSuperUser
23
from common.utils import get_logger
baltery's avatar
baltery 已提交
24 25 26 27
from .serializers import (
    MailTestSerializer, LDAPTestSerializer, LDAPUserSerializer,
    PublicSettingSerializer,
)
28
from users.models import User
baltery's avatar
baltery 已提交
29 30


31 32 33
logger = get_logger(__file__)


baltery's avatar
baltery 已提交
34
class MailTestingAPI(APIView):
35
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
36 37 38 39 40 41
    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():
42
            email_from = serializer.validated_data["EMAIL_FROM"]
43
            email_recipient = serializer.validated_data["EMAIL_RECIPIENT"]
baltery's avatar
baltery 已提交
44 45 46 47 48 49 50
            email_host_user = serializer.validated_data["EMAIL_HOST_USER"]
            for k, v in serializer.validated_data.items():
                if k.startswith('EMAIL'):
                    setattr(settings, k, v)
            try:
                subject = "Test"
                message = "Test smtp setting"
51
                email_from = email_from or email_host_user
52 53
                email_recipient = email_recipient or email_from
                send_mail(subject, message,  email_from, [email_recipient])
baltery's avatar
baltery 已提交
54 55 56 57 58 59 60 61 62 63 64
            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
                return Response({"error": str(resp)}, status=401)
baltery's avatar
baltery 已提交
65
            except Exception as e:
baltery's avatar
baltery 已提交
66
                print(e)
baltery's avatar
baltery 已提交
67
                return Response({"error": str(e)}, status=401)
68
            return Response({"msg": self.success_message.format(email_recipient)})
baltery's avatar
baltery 已提交
69 70 71 72 73
        else:
            return Response({"error": str(serializer.errors)}, status=401)


class LDAPTestingAPI(APIView):
74
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
75 76 77
    serializer_class = LDAPTestSerializer
    success_message = _("Test ldap success")

78
    @staticmethod
79 80
    def get_ldap_config(serializer):
        server_uri = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
81 82 83 84 85 86
        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)
        search_ougroup = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
        search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
        attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
87 88 89 90 91 92 93 94 95 96
        config = {
            'server_uri': server_uri,
            'bind_dn': bind_dn,
            'password': password,
            'use_ssl': use_ssl,
            'search_ougroup': search_ougroup,
            'search_filter': search_filter,
            'attr_map': json.loads(attr_map),
        }
        return config
97

baltery's avatar
baltery 已提交
98 99
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
100 101
        if not serializer.is_valid():
            return Response({"error": str(serializer.errors)}, status=401)
baltery's avatar
baltery 已提交
102

103 104 105 106
        attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
        try:
            json.loads(attr_map)
        except json.JSONDecodeError:
B
BaiJiangJie 已提交
107
            return Response({"error": _("LDAP attr map not valid")}, status=401)
baltery's avatar
baltery 已提交
108

109 110
        config = self.get_ldap_config(serializer)
        util = LDAPServerUtil(config=config)
111
        try:
112
            users = util.search()
113 114
        except Exception as e:
            return Response({"error": str(e)}, status=401)
baltery's avatar
baltery 已提交
115

116
        return Response({"msg": _("Match {} s users").format(len(users))})
baltery's avatar
baltery 已提交
117 118


119
class LDAPUserListApi(generics.ListAPIView):
120
    permission_classes = (IsSuperUser,)
baltery's avatar
baltery 已提交
121
    serializer_class = LDAPUserSerializer
八千流 已提交
122

123 124 125 126 127 128 129 130 131 132
    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

133
    def get_queryset(self):
baltery's avatar
baltery 已提交
134 135
        if hasattr(self, 'swagger_fake_view'):
            return []
136 137 138 139 140
        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()
141 142
        return users

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    @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

170 171 172 173 174 175
    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)

176 177 178 179 180 181
        try:
            queryset = self.get_queryset()
        except Exception as e:
            data = {'error': str(e)}
            return Response(data=data, status=400)

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
        # 缓存有数据
        if queryset is not None:
            return super().list(request, *args, **kwargs)

        sync_util = LDAPSyncUtil()
        # 还没有同步任务
        if sync_util.task_no_start:
            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()
199
            data = {'error': 'Synchronization task report error: {}'.format(msg)}
200 201 202 203
            return Response(data=data, status=400)

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

八千流 已提交
204

205
class LDAPUserImportAPI(APIView):
206
    permission_classes = (IsSuperUser,)
八千流 已提交
207

208 209 210 211 212 213 214 215 216
    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

八千流 已提交
217
    def post(self, request):
218 219 220 221 222 223
        try:
            users = self.get_ldap_users()
        except Exception as e:
            return Response({'error': str(e)}, status=401)

        if users is None:
B
BaiJiangJie 已提交
224
            return Response({'msg': _('Get ldap users is None')}, status=401)
225

226 227
        errors = LDAPImportUtil().perform_import(users)
        if errors:
228 229 230
            return Response({'errors': errors}, status=401)

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

233

234
class LDAPCacheRefreshAPI(generics.RetrieveAPIView):
235
    permission_classes = (IsSuperUser,)
236 237

    def retrieve(self, request, *args, **kwargs):
238
        try:
239
            LDAPSyncUtil().clear_cache()
240
        except Exception as e:
241 242 243
            logger.error(str(e))
            return Response(data={'msg': str(e)}, status=400)
        return Response(data={'msg': 'success'})
八千流 已提交
244 245


baltery's avatar
baltery 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
class ReplayStorageCreateAPI(APIView):
    permission_classes = (IsSuperUser,)

    def post(self, request):
        storage_data = request.data

        if storage_data.get('TYPE') == 'ceph':
            port = storage_data.get('PORT')
            if port.isdigit():
                storage_data['PORT'] = int(storage_data.get('PORT'))

        storage_name = storage_data.pop('NAME')
        data = {storage_name: storage_data}

        if not self.is_valid(storage_data):
            return Response({
                "error": _("Error: Account invalid (Please make sure the "
                           "information such as Access key or Secret key is correct)")},
                status=401
            )

        Setting.save_storage('TERMINAL_REPLAY_STORAGE', data)
        return Response({"msg": _('Create succeed')}, status=200)

    @staticmethod
    def is_valid(storage_data):
        if storage_data.get('TYPE') == 'server':
            return True
        storage = jms_storage.get_object_storage(storage_data)
        target = 'tests.py'
        src = os.path.join(settings.BASE_DIR, 'common', target)
        return storage.is_valid(src, target)


class ReplayStorageDeleteAPI(APIView):
    permission_classes = (IsSuperUser,)

    def post(self, request):
        storage_name = str(request.data.get('name'))
        Setting.delete_storage('TERMINAL_REPLAY_STORAGE', storage_name)
        return Response({"msg": _('Delete succeed')}, status=200)


class CommandStorageCreateAPI(APIView):
    permission_classes = (IsSuperUser,)

    def post(self, request):
        storage_data = request.data
        storage_name = storage_data.pop('NAME')
        data = {storage_name: storage_data}
        if not self.is_valid(storage_data):
            return Response(
                {"error": _("Error: Account invalid (Please make sure the "
                            "information such as Access key or Secret key is correct)")},
                status=401
            )

        Setting.save_storage('TERMINAL_COMMAND_STORAGE', data)
        return Response({"msg": _('Create succeed')}, status=200)

    @staticmethod
    def is_valid(storage_data):
        if storage_data.get('TYPE') == 'server':
            return True
        try:
            storage = jms_storage.get_log_storage(storage_data)
        except Exception:
            return False

        return storage.ping()


class CommandStorageDeleteAPI(APIView):
    permission_classes = (IsSuperUser,)

    def post(self, request):
        storage_name = str(request.data.get('name'))
        Setting.delete_storage('TERMINAL_COMMAND_STORAGE', storage_name)
        return Response({"msg": _('Delete succeed')}, status=200)
baltery's avatar
baltery 已提交
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340


class PublicSettingApi(generics.RetrieveAPIView):
    permission_classes = ()
    serializer_class = PublicSettingSerializer

    def get_object(self):
        c = settings.CONFIG
        instance = {
            "data": {
                "WINDOWS_SKIP_ALL_MANUAL_PASSWORD": c.WINDOWS_SKIP_ALL_MANUAL_PASSWORD
            }
        }
        return instance