Merge branch 'v3' of github.com:jumpserver/jumpserver into v3

pull/9136/head
Bai 2022-11-30 21:13:56 +08:00
commit 3b1c8a2327
6 changed files with 196 additions and 36 deletions

View File

@ -154,6 +154,7 @@ class RDPFileClientProtocolURLMixin:
data = {
'id': str(token.id),
'value': token.value,
'protocol': token.protocol,
'command': '',
'file': {}
}

View File

@ -13,48 +13,121 @@ from rest_framework.response import Response
from users.models import User
from assets.models import Asset
from assets.const import AllTypes
from terminal.models import Session
from terminal.models import Session, Command
from terminal.utils import ComponentsPrometheusMetricsUtil
from orgs.utils import current_org
from common.utils import lazyproperty
from audits.models import UserLoginLog, PasswordChangeLog, OperateLog
from audits.const import LoginStatusChoices
from common.utils.timezone import local_now, local_zero_hour
from orgs.caches import OrgResourceStatisticsCache
__all__ = ['IndexApi']
class DatesLoginMetricMixin:
class DateTimeMixin:
request: Request
@property
def org(self):
return current_org
@lazyproperty
def days(self):
query_params = self.request.query_params
# monthly
count = query_params.get('days')
count = int(count) if count else 0
return count
@lazyproperty
def sessions_queryset(self):
@property
def days_to_datetime(self):
days = self.days
if days == 0:
t = local_zero_hour()
else:
t = local_now() - timezone.timedelta(days=days)
sessions_queryset = Session.objects.filter(date_start__gte=t)
return sessions_queryset
return t
@lazyproperty
def session_dates_list(self):
def dates_list(self):
now = local_now()
dates = [(now - timezone.timedelta(days=i)).date() for i in range(self.days)]
dates.reverse()
return dates
def get_dates_metrics_date(self):
dates_metrics_date = [d.strftime('%m-%d') for d in self.session_dates_list] or ['0']
dates_metrics_date = [d.strftime('%m-%d') for d in self.dates_list] or ['0']
return dates_metrics_date
@lazyproperty
def users(self):
return self.org.get_members()
@lazyproperty
def sessions_queryset(self):
t = self.days_to_datetime
sessions_queryset = Session.objects.filter(date_start__gte=t)
return sessions_queryset
def get_logs_queryset(self, queryset, query_params):
query = {}
if not self.org.is_root():
if query_params == 'username':
query = {
f'{query_params}__in': self.users.values_list('username', flat=True)
}
else:
query = {
f'{query_params}__in': [str(user) for user in self.users]
}
queryset = queryset.filter(**query)
return queryset
@lazyproperty
def login_logs_queryset(self):
t = self.days_to_datetime
queryset = UserLoginLog.objects.filter(datetime__gte=t)
queryset = self.get_logs_queryset(queryset, 'username')
return queryset
@lazyproperty
def password_change_logs_queryset(self):
t = self.days_to_datetime
queryset = PasswordChangeLog.objects.filter(datetime__gte=t)
queryset = self.get_logs_queryset(queryset, 'user')
return queryset
@lazyproperty
def operate_logs_queryset(self):
t = self.days_to_datetime
queryset = OperateLog.objects.filter(datetime__gte=t)
queryset = self.get_logs_queryset(queryset, 'user')
return queryset
@lazyproperty
def ftp_logs_queryset(self):
t = self.days_to_datetime
queryset = OperateLog.objects.filter(datetime__gte=t)
queryset = self.get_logs_queryset(queryset, 'user')
return queryset
@lazyproperty
def command_queryset(self):
t = self.days_to_datetime
t = t.timestamp()
queryset = Command.objects.filter(timestamp__gte=t)
return queryset
class DatesLoginMetricMixin:
dates_list: list
command_queryset: Command.objects
sessions_queryset: Session.objects
ftp_logs_queryset: OperateLog.objects
login_logs_queryset: UserLoginLog.objects
operate_logs_queryset: OperateLog.objects
password_change_logs_queryset: PasswordChangeLog.objects
@staticmethod
def get_cache_key(date, tp):
date_str = date.strftime("%Y%m%d")
@ -93,7 +166,7 @@ class DatesLoginMetricMixin:
def get_dates_metrics_total_count_login(self):
data = []
for d in self.session_dates_list:
for d in self.dates_list:
count = self.get_date_login_count(d)
data.append(count)
if len(data) == 0:
@ -112,7 +185,7 @@ class DatesLoginMetricMixin:
def get_dates_metrics_total_count_active_users(self):
data = []
for d in self.session_dates_list:
for d in self.dates_list:
count = self.get_date_user_count(d)
data.append(count)
return data
@ -129,11 +202,28 @@ class DatesLoginMetricMixin:
def get_dates_metrics_total_count_active_assets(self):
data = []
for d in self.session_dates_list:
for d in self.dates_list:
count = self.get_date_asset_count(d)
data.append(count)
return data
def get_date_session_count(self, date):
tp = "SESSION"
count = self.__get_data_from_cache(date, tp)
if count is not None:
return count
ds, de = self.get_date_start_2_end(date)
count = Session.objects.filter(date_start__range=(ds, de)).count()
self.__set_data_to_cache(date, tp, count)
return count
def get_dates_metrics_total_count_sessions(self):
data = []
for d in self.dates_list:
count = self.get_date_session_count(d)
data.append(count)
return data
@lazyproperty
def get_type_to_assets(self):
result = Asset.objects.annotate(type=F('platform__type')). \
@ -181,8 +271,44 @@ class DatesLoginMetricMixin:
]
return sessions
@lazyproperty
def user_login_logs_amount(self):
return self.login_logs_queryset.count()
class IndexApi(DatesLoginMetricMixin, APIView):
@lazyproperty
def user_login_success_logs_amount(self):
return self.login_logs_queryset.filter(status=LoginStatusChoices.success).count()
@lazyproperty
def user_login_amount(self):
return self.login_logs_queryset.values('username').distinct().count()
@lazyproperty
def operate_logs_amount(self):
return self.operate_logs_queryset.count()
@lazyproperty
def change_password_logs_amount(self):
return self.password_change_logs_queryset.count()
@lazyproperty
def commands_amount(self):
return self.command_queryset.count()
@lazyproperty
def commands_danger_amount(self):
return self.command_queryset.filter(risk_level=Command.RISK_LEVEL_DANGEROUS).count()
@lazyproperty
def sessions_amount(self):
return self.sessions_queryset.count()
@lazyproperty
def ftp_logs_amount(self):
return self.ftp_logs_queryset.count()
class IndexApi(DateTimeMixin, DatesLoginMetricMixin, APIView):
http_method_names = ['get']
def check_permissions(self, request):
@ -193,7 +319,7 @@ class IndexApi(DatesLoginMetricMixin, APIView):
query_params = self.request.query_params
caches = OrgResourceStatisticsCache(current_org)
caches = OrgResourceStatisticsCache(self.org)
_all = query_params.get('all')
@ -217,9 +343,9 @@ class IndexApi(DatesLoginMetricMixin, APIView):
'total_count_assets_this_week': caches.new_assets_amount_this_week,
})
if _all or query_params.get('total_count') or query_params.get('total_count_today_login_users'):
if _all or query_params.get('total_count') or query_params.get('total_count_login_users'):
data.update({
'total_count_today_login_users': caches.total_count_today_login_users,
'total_count_login_users': self.user_login_amount
})
if _all or query_params.get('total_count') or query_params.get('total_count_today_active_assets'):
@ -242,9 +368,50 @@ class IndexApi(DatesLoginMetricMixin, APIView):
'total_count_today_failed_sessions': caches.total_count_today_failed_sessions,
})
if _all or query_params.get('total_count') or query_params.get('total_count_type_to_assets_amount'):
if _all or query_params.get('total_count') or query_params.get('total_count_user_login_logs'):
data.update({
'total_count_type_to_assets_amount': self.get_type_to_assets,
'total_count_user_login_logs': self.user_login_logs_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_user_login_success_logs'):
data.update({
'total_count_user_login_success_logs': self.user_login_success_logs_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_operate_logs'):
data.update({
'total_count_operate_logs': self.operate_logs_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_change_password_logs'):
data.update({
'total_count_change_password_logs': self.change_password_logs_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_commands'):
data.update({
'total_count_commands': self.commands_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_commands_danger'):
data.update({
'total_count_commands_danger': self.commands_danger_amount,
})
if _all or query_params.get('total_count') or query_params.get('total_count_history_sessions'):
data.update({
'total_count_history_sessions': self.sessions_amount - caches.total_count_online_sessions,
})
if _all or query_params.get('total_count') or query_params.get('total_count_ftp_logs'):
data.update({
'total_count_ftp_logs': self.ftp_logs_amount,
})
if _all or query_params.get('session_dates_metrics'):
data.update({
'dates_metrics_date': self.get_dates_metrics_date(),
'dates_metrics_total_count_session': self.get_dates_metrics_total_count_sessions(),
})
if _all or query_params.get('dates_metrics'):

View File

@ -7,8 +7,6 @@ from common.cache import Cache, IntegerField
from common.utils import get_logger
from common.utils.timezone import local_zero_hour, local_monday
from users.models import UserGroup, User
from audits.models import UserLoginLog
from audits.const import LoginStatusChoices
from assets.models import Node, Domain, Asset, Account
from terminal.models import Session
from perms.models import AssetPermission
@ -64,7 +62,6 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
asset_perms_amount = IntegerField(queryset=AssetPermission.objects)
total_count_online_users = IntegerField()
total_count_online_sessions = IntegerField()
total_count_today_login_users = IntegerField()
total_count_today_active_assets = IntegerField()
total_count_today_failed_sessions = IntegerField()
@ -113,16 +110,6 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
def compute_total_count_online_sessions():
return Session.objects.filter(is_finished=False).count()
def compute_total_count_today_login_users(self):
t = local_zero_hour()
user_login_logs = UserLoginLog.objects.filter(
datetime__gte=t, status=LoginStatusChoices.success
)
if not self.org.is_root():
usernames = self.org.get_members().values('username')
user_login_logs = user_login_logs.filter(username__in=usernames)
return user_login_logs.values('username').distinct().count()
@staticmethod
def compute_total_count_today_active_assets():
t = local_zero_hour()

View File

@ -88,6 +88,9 @@ class AssetsSerializerFormatMixin:
serializer_class = serializers.AssetGrantedSerializer
filterset_fields = ['name', 'address', 'id', 'comment']
search_fields = ['name', 'address', 'comment']
filterset_class = AssetFilterSet
ordering_fields = ("name", "address")
ordering = ('name',)
class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):

View File

@ -5,8 +5,8 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from assets.const import Category, AllTypes
from assets.serializers.asset.common import AssetProtocolsSerializer
from assets.models import Node, Asset, Platform, Account
from assets.serializers.asset.common import AssetProtocolsSerializer
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
from perms.serializers.permission import ActionChoicesField
@ -48,5 +48,6 @@ class AccountsPermedSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'name', 'has_username', 'username', 'has_secret', 'secret_type', 'actions']
fields = ['id', 'name', 'has_username', 'username',
'has_secret', 'secret_type', 'actions']
read_only_fields = fields

View File

@ -131,10 +131,11 @@ class NativeClient(TextChoices):
@classmethod
def get_launch_command(cls, name, token, endpoint, os='windows'):
username = f'JMS-{token.id}'
commands = {
cls.ssh: f'ssh {token.id}@{endpoint.host} -p {endpoint.ssh_port}',
cls.putty: f'putty -ssh {token.id}@{endpoint.host} -P {endpoint.ssh_port}',
cls.xshell: f'xshell -url ssh://{token.id}:{token.value}@{endpoint.host}:{endpoint.ssh_port}',
cls.ssh: f'ssh {username}@{endpoint.host} -p {endpoint.ssh_port}',
cls.putty: f'putty.exe -ssh {username}@{endpoint.host} -P {endpoint.ssh_port}',
cls.xshell: f'xshell.exe -url ssh://{username}:{token.value}@{endpoint.host}:{endpoint.ssh_port}',
# cls.mysql: 'mysql -h {hostname} -P {port} -u {username} -p',
# cls.psql: {
# 'default': 'psql -h {hostname} -p {port} -U {username} -W',