1# Copyright (c) 2012-2016 Seafile Ltd. 2import logging 3 4from rest_framework import serializers 5from seaserv import ccnet_api 6 7from seahub.auth import authenticate 8from seahub.api2.models import DESKTOP_PLATFORMS 9from seahub.api2.utils import get_token_v1, get_token_v2 10from seahub.profile.models import Profile 11from seahub.two_factor.models import default_device 12from seahub.two_factor.views.login import is_device_remembered 13from seahub.utils.two_factor_auth import has_two_factor_auth, \ 14 two_factor_auth_enabled, verify_two_factor_token 15 16logger = logging.getLogger(__name__) 17 18def all_none(values): 19 for value in values: 20 if value is not None: 21 return False 22 23 return True 24 25def all_not_none(values): 26 for value in values: 27 if value is None: 28 return False 29 30 return True 31 32class AuthTokenSerializer(serializers.Serializer): 33 username = serializers.CharField() 34 password = serializers.CharField() 35 36 # There fields are used by TokenV2 37 platform = serializers.CharField(required=False) 38 device_id = serializers.CharField(required=False) 39 device_name = serializers.CharField(required=False) 40 41 # These fields may be needed in the future 42 client_version = serializers.CharField(required=False, default='') 43 platform_version = serializers.CharField(required=False, default='') 44 45 def __init__(self, *a, **kw): 46 super(AuthTokenSerializer, self).__init__(*a, **kw) 47 self.two_factor_auth_failed = False 48 49 def validate(self, attrs): 50 login_id = attrs.get('username') 51 password = attrs.get('password') 52 53 platform = attrs.get('platform', None) 54 device_id = attrs.get('device_id', None) 55 device_name = attrs.get('device_name', None) 56 client_version = attrs.get('client_version', None) 57 platform_version = attrs.get('platform_version', None) 58 59 v2_fields = (platform, device_id, device_name) 60 61 # Decide the version of token we need 62 if all_none(v2_fields): 63 v2 = False 64 elif all_not_none(v2_fields): 65 v2 = True 66 else: 67 raise serializers.ValidationError('invalid params') 68 69 if login_id and password: 70 user = authenticate(username=login_id, password=password) 71 if user: 72 if not user.is_active: 73 raise serializers.ValidationError('User account is disabled.') 74 else: 75 """try login id/contact email/primary id""" 76 # convert login id or contact email to username if any 77 username = Profile.objects.convert_login_str_to_username(login_id) 78 # convert username to primary id if any 79 p_id = ccnet_api.get_primary_id(username) 80 if p_id is not None: 81 username = p_id 82 83 user = authenticate(username=username, password=password) 84 if user is None: 85 raise serializers.ValidationError('Unable to login with provided credentials.') 86 else: 87 raise serializers.ValidationError('Must include "username" and "password"') 88 89 self._two_factor_auth(self.context['request'], user) 90 91 # Now user is authenticated 92 if v2: 93 if platform in DESKTOP_PLATFORMS: 94 if not user.permissions.can_connect_with_desktop_clients(): 95 raise serializers.ValidationError('Not allowed to connect to desktop client.') 96 elif platform == 'android': 97 if not user.permissions.can_connect_with_android_clients(): 98 raise serializers.ValidationError('Not allowed to connect to android client.') 99 elif platform == 'ios': 100 if not user.permissions.can_connect_with_ios_clients(): 101 raise serializers.ValidationError('Not allowed to connect to ios client.') 102 else: 103 logger.info('%s: unrecognized device' % login_id) 104 105 token = get_token_v2(self.context['request'], user.username, platform, 106 device_id, device_name, client_version, platform_version) 107 else: 108 token = get_token_v1(user.username) 109 110 return token.key 111 112 def _two_factor_auth(self, request, user): 113 if not has_two_factor_auth() or not two_factor_auth_enabled(user): 114 return 115 116 if is_device_remembered(request.META.get('HTTP_X_SEAFILE_S2FA', ''), 117 user): 118 return 119 120 token = request.META.get('HTTP_X_SEAFILE_OTP', '') 121 if not token: 122 # Generate challenge(send sms/call/...) if token is not provided. 123 default_device(user).generate_challenge() 124 125 self.two_factor_auth_failed = True 126 msg = 'Two factor auth token is missing.' 127 raise serializers.ValidationError(msg) 128 if not verify_two_factor_token(user, token): 129 self.two_factor_auth_failed = True 130 msg = 'Two factor auth token is invalid.' 131 raise serializers.ValidationError(msg) 132 133 134class AccountSerializer(serializers.Serializer): 135 email = serializers.EmailField() 136 password = serializers.CharField() 137 is_staff = serializers.BooleanField(default=False) 138 is_active = serializers.BooleanField(default=True) 139