diff --git a/apps/i18n/lina/en.json b/apps/i18n/lina/en.json index 106ffafec..aa852c53f 100644 --- a/apps/i18n/lina/en.json +++ b/apps/i18n/lina/en.json @@ -509,9 +509,12 @@ "ExistError": "This element already exists", "Existing": "Already exists", "ExpirationTimeout": "Expiration timeout (seconds)", - "Expire": "Expired", - "Expired": "Expiration date", + "Expire": "Expire", + "Expired": "Expired", "Export": "Export", + "NeverLogin": "Never login", + "NoMFA": "MFA not enabled", + "LoginBlocked": "Login blocked", "ExportAll": "Export all", "ExportOnlyFiltered": "Export filtered items", "ExportOnlySelectedItems": "Export selected items", diff --git a/apps/i18n/lina/zh.json b/apps/i18n/lina/zh.json index caf55e2bb..4718a9731 100644 --- a/apps/i18n/lina/zh.json +++ b/apps/i18n/lina/zh.json @@ -1003,6 +1003,9 @@ "RestoreDialogTitle": "你确认吗", "Result": "结果", "Resume": "恢复", + "NeverLogin": "从未登录", + "NoMFA": "未启用 MFA", + "LoginBlocked": "登录被阻止", "ResumeTaskSendSuccessMsg": "恢复任务已下发,请稍后刷新查看", "Retry": "重试", "RetrySelected": "重试所选", diff --git a/apps/users/filters.py b/apps/users/filters.py index dec174d16..6c8648e08 100644 --- a/apps/users/filters.py +++ b/apps/users/filters.py @@ -1,11 +1,13 @@ +from django.db.models import Q +from django.utils import timezone from django.utils.translation import gettext as _ from django_filters import rest_framework as filters from common.drf.filters import BaseFilterSet from common.utils import is_uuid +from jumpserver import settings from rbac.models import Role, OrgRoleBinding, SystemRoleBinding from users.models.user import User -from orgs.utils import current_org class UserFilter(BaseFilterSet): @@ -16,15 +18,69 @@ class UserFilter(BaseFilterSet): exclude_group_id = filters.CharFilter( field_name="groups__id", lookup_expr='exact', exclude=True ) + is_expired = filters.BooleanFilter(method='filter_is_expired') + is_valid = filters.BooleanFilter(method='filter_is_valid') + is_password_expired = filters.BooleanFilter(method='filter_long_time') + is_long_time_no_login = filters.BooleanFilter(method='filter_long_time') + is_login_blocked = filters.BooleanFilter(method='filter_is_blocked') class Meta: model = User fields = ( 'id', 'username', 'email', 'name', 'groups', 'group_id', 'exclude_group_id', - 'source', 'org_roles', 'system_roles', 'is_active', + 'source', 'org_roles', 'system_roles', + 'is_active', 'is_first_login', ) + def filter_is_blocked(self, queryset, name, value): + from users.utils import LoginBlockUtil + usernames = LoginBlockUtil.get_blocked_usernames() + if value: + queryset = queryset.filter(username__in=usernames) + else: + queryset = queryset.exclude(username__in=usernames) + return queryset + + def filter_long_time(self, queryset, name, value): + now = timezone.now() + if name == 'is_password_expired': + interval = settings.SECURITY_PASSWORD_EXPIRATION_TIME + else: + interval = 30 + date_expired = now - timezone.timedelta(days=int(interval)) + + if name == 'is_password_expired': + key = 'date_password_last_updated' + elif name == 'long_time_no_login': + key = 'last_login' + else: + raise ValueError('Invalid filter name') + + if value: + kwargs = {f'{key}__lt': date_expired} + else: + kwargs = {f'{key}__gt': date_expired} + q = Q(**kwargs) | Q(**{f'{key}__isnull': True}) + return queryset.filter(q) + + def filter_is_valid(self, queryset, name, value): + if value: + queryset = self.filter_is_expired(queryset, name, False).filter(is_active=True) + else: + q = Q(date_expired__lt=timezone.now()) | Q(is_active=False) + queryset = queryset.filter(q) + return queryset + + @staticmethod + def filter_is_expired(queryset, name, value): + now = timezone.now() + if value: + queryset = queryset.filter(date_expired__lt=now) + else: + queryset = queryset.filter(date_expired__gte=now) + return queryset + @staticmethod def _get_role(value): from rbac.builtin import BuiltinRole @@ -42,7 +98,7 @@ class UserFilter(BaseFilterSet): role = self._get_role(value) if not role: return queryset.none() - + rb_model = SystemRoleBinding if scope == Role.Scope.system.value else OrgRoleBinding user_ids = rb_model.objects.filter(role_id=role.id).values_list('user_id', flat=True) queryset = queryset.filter(id__in=user_ids).distinct() diff --git a/apps/users/utils.py b/apps/users/utils.py index cdb15eb23..cd7a35dec 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -172,6 +172,12 @@ class BlockUtilBase: def is_block(self): return bool(cache.get(self.block_key)) + @classmethod + def get_blocked_usernames(cls): + key = cls.BLOCK_KEY_TMPL.format('*') + keys = cache.keys(key) + return [k.split('_')[-1] for k in keys] + class BlockGlobalIpUtilBase: LIMIT_KEY_TMPL: str