2018-01-11 12:10:27 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
2019-05-20 04:30:55 +00:00
|
|
|
import time
|
2022-07-04 03:29:39 +00:00
|
|
|
|
2018-11-23 02:25:35 +00:00
|
|
|
from django.conf import settings
|
2022-07-04 03:29:39 +00:00
|
|
|
from rest_framework import permissions
|
|
|
|
|
|
|
|
from authentication.const import ConfirmType
|
2022-07-15 06:56:51 +00:00
|
|
|
from authentication.models import ConnectionToken
|
2023-02-16 06:27:54 +00:00
|
|
|
from common.exceptions import UserConfirmRequired
|
2022-07-15 06:56:51 +00:00
|
|
|
from common.utils import get_object_or_none
|
2023-02-16 06:27:54 +00:00
|
|
|
from orgs.utils import tmp_to_root_org
|
2018-07-20 10:42:01 +00:00
|
|
|
|
2018-01-11 12:10:27 +00:00
|
|
|
|
2023-09-11 03:13:34 +00:00
|
|
|
class IsValidUser(permissions.IsAuthenticated):
|
2018-01-11 12:10:27 +00:00
|
|
|
"""Allows access to valid user, is active and not expired"""
|
|
|
|
|
|
|
|
def has_permission(self, request, view):
|
2022-11-07 12:41:18 +00:00
|
|
|
return super().has_permission(request, view) \
|
2023-02-16 06:27:54 +00:00
|
|
|
and request.user.is_valid
|
2018-01-11 12:10:27 +00:00
|
|
|
|
|
|
|
|
2022-07-15 06:56:51 +00:00
|
|
|
class IsValidUserOrConnectionToken(IsValidUser):
|
|
|
|
def has_permission(self, request, view):
|
2022-11-07 12:41:18 +00:00
|
|
|
return super().has_permission(request, view) \
|
2023-02-16 06:27:54 +00:00
|
|
|
or self.is_valid_connection_token(request)
|
2022-07-15 06:56:51 +00:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def is_valid_connection_token(request):
|
|
|
|
token_id = request.query_params.get('token')
|
|
|
|
if not token_id:
|
|
|
|
return False
|
|
|
|
with tmp_to_root_org():
|
|
|
|
token = get_object_or_none(ConnectionToken, id=token_id)
|
|
|
|
return token and token.is_valid
|
|
|
|
|
|
|
|
|
2022-02-17 12:13:31 +00:00
|
|
|
class OnlySuperUser(IsValidUser):
|
2018-07-25 03:21:12 +00:00
|
|
|
def has_permission(self, request, view):
|
2022-02-17 12:13:31 +00:00
|
|
|
return super().has_permission(request, view) \
|
2023-02-16 06:27:54 +00:00
|
|
|
and request.user.is_superuser
|
2018-07-25 03:21:12 +00:00
|
|
|
|
|
|
|
|
2022-11-07 12:41:18 +00:00
|
|
|
class IsServiceAccount(IsValidUser):
|
|
|
|
def has_permission(self, request, view):
|
|
|
|
return super().has_permission(request, view) \
|
2023-02-16 06:27:54 +00:00
|
|
|
and request.user.is_service_account
|
2022-11-07 12:41:18 +00:00
|
|
|
|
|
|
|
|
2018-11-23 02:25:35 +00:00
|
|
|
class WithBootstrapToken(permissions.BasePermission):
|
|
|
|
def has_permission(self, request, view):
|
|
|
|
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
|
|
|
if not authorization:
|
|
|
|
return False
|
|
|
|
request_bootstrap_token = authorization.split()[-1]
|
|
|
|
return settings.BOOTSTRAP_TOKEN == request_bootstrap_token
|
2019-06-19 02:47:26 +00:00
|
|
|
|
|
|
|
|
2022-07-04 03:29:39 +00:00
|
|
|
class UserConfirmation(permissions.BasePermission):
|
2022-07-07 09:07:57 +00:00
|
|
|
ttl = 60 * 5
|
2022-07-04 03:29:39 +00:00
|
|
|
min_level = 1
|
2023-10-10 09:52:52 +00:00
|
|
|
confirm_type = ConfirmType.RELOGIN
|
2019-07-02 06:17:56 +00:00
|
|
|
|
2022-07-04 03:29:39 +00:00
|
|
|
def has_permission(self, request, view):
|
2022-07-19 08:22:49 +00:00
|
|
|
if not settings.SECURITY_VIEW_AUTH_NEED_MFA:
|
|
|
|
return True
|
|
|
|
|
2022-07-04 03:29:39 +00:00
|
|
|
confirm_level = request.session.get('CONFIRM_LEVEL')
|
|
|
|
confirm_time = request.session.get('CONFIRM_TIME')
|
2022-09-14 08:17:51 +00:00
|
|
|
ttl = self.get_ttl()
|
2022-07-04 03:29:39 +00:00
|
|
|
if not confirm_level or not confirm_time or \
|
|
|
|
confirm_level < self.min_level or \
|
2022-09-14 08:17:51 +00:00
|
|
|
confirm_time < time.time() - ttl:
|
2022-07-04 03:29:39 +00:00
|
|
|
raise UserConfirmRequired(code=self.confirm_type)
|
|
|
|
return True
|
|
|
|
|
2022-09-14 08:17:51 +00:00
|
|
|
def get_ttl(self):
|
|
|
|
if self.confirm_type == ConfirmType.MFA:
|
|
|
|
ttl = settings.SECURITY_MFA_VERIFY_TTL
|
|
|
|
else:
|
|
|
|
ttl = self.ttl
|
|
|
|
return ttl
|
|
|
|
|
2022-07-04 03:29:39 +00:00
|
|
|
@classmethod
|
2023-10-10 09:52:52 +00:00
|
|
|
def require(cls, confirm_type=ConfirmType.RELOGIN, ttl=60 * 5):
|
2022-07-04 03:29:39 +00:00
|
|
|
min_level = ConfirmType.values.index(confirm_type) + 1
|
|
|
|
name = 'UserConfirmationLevel{}TTL{}'.format(min_level, ttl)
|
|
|
|
return type(name, (cls,), {'min_level': min_level, 'ttl': ttl, 'confirm_type': confirm_type})
|
2023-09-25 14:58:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ServiceAccountSignaturePermission(permissions.BasePermission):
|
|
|
|
def has_permission(self, request, view):
|
|
|
|
from authentication.models import AccessKey
|
|
|
|
from common.utils.crypto import get_aes_crypto
|
|
|
|
signature = request.META.get('HTTP_X_JMS_SVC', '')
|
|
|
|
if not signature or not signature.startswith('Sign'):
|
|
|
|
return False
|
|
|
|
data = signature[4:].strip()
|
|
|
|
if not data or ':' not in data:
|
|
|
|
return False
|
|
|
|
ak_id, time_sign = data.split(':', 1)
|
|
|
|
if not ak_id or not time_sign:
|
|
|
|
return False
|
|
|
|
ak = AccessKey.objects.filter(id=ak_id).first()
|
|
|
|
if not ak or not ak.is_active:
|
|
|
|
return False
|
|
|
|
if not ak.user or not ak.user.is_active or not ak.user.is_service_account:
|
|
|
|
return False
|
|
|
|
aes = get_aes_crypto(str(ak.secret).replace('-', ''), mode='ECB')
|
|
|
|
try:
|
|
|
|
timestamp = aes.decrypt(time_sign)
|
|
|
|
if not timestamp or not timestamp.isdigit():
|
|
|
|
return False
|
|
|
|
timestamp = int(timestamp)
|
|
|
|
interval = abs(int(time.time()) - timestamp)
|
|
|
|
if interval > 30:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
except Exception:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def has_object_permission(self, request, view, obj):
|
|
|
|
return False
|