mirror of https://github.com/jumpserver/jumpserver
Merge branch 'v3' of github.com:jumpserver/jumpserver into v3
commit
3b1c8a2327
|
@ -154,6 +154,7 @@ class RDPFileClientProtocolURLMixin:
|
||||||
data = {
|
data = {
|
||||||
'id': str(token.id),
|
'id': str(token.id),
|
||||||
'value': token.value,
|
'value': token.value,
|
||||||
|
'protocol': token.protocol,
|
||||||
'command': '',
|
'command': '',
|
||||||
'file': {}
|
'file': {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,48 +13,121 @@ from rest_framework.response import Response
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
from assets.const import AllTypes
|
from assets.const import AllTypes
|
||||||
from terminal.models import Session
|
from terminal.models import Session, Command
|
||||||
from terminal.utils import ComponentsPrometheusMetricsUtil
|
from terminal.utils import ComponentsPrometheusMetricsUtil
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
from common.utils import lazyproperty
|
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 common.utils.timezone import local_now, local_zero_hour
|
||||||
from orgs.caches import OrgResourceStatisticsCache
|
from orgs.caches import OrgResourceStatisticsCache
|
||||||
|
|
||||||
__all__ = ['IndexApi']
|
__all__ = ['IndexApi']
|
||||||
|
|
||||||
|
|
||||||
class DatesLoginMetricMixin:
|
class DateTimeMixin:
|
||||||
request: Request
|
request: Request
|
||||||
|
|
||||||
|
@property
|
||||||
|
def org(self):
|
||||||
|
return current_org
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def days(self):
|
def days(self):
|
||||||
query_params = self.request.query_params
|
query_params = self.request.query_params
|
||||||
# monthly
|
|
||||||
count = query_params.get('days')
|
count = query_params.get('days')
|
||||||
count = int(count) if count else 0
|
count = int(count) if count else 0
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@lazyproperty
|
@property
|
||||||
def sessions_queryset(self):
|
def days_to_datetime(self):
|
||||||
days = self.days
|
days = self.days
|
||||||
if days == 0:
|
if days == 0:
|
||||||
t = local_zero_hour()
|
t = local_zero_hour()
|
||||||
else:
|
else:
|
||||||
t = local_now() - timezone.timedelta(days=days)
|
t = local_now() - timezone.timedelta(days=days)
|
||||||
sessions_queryset = Session.objects.filter(date_start__gte=t)
|
return t
|
||||||
return sessions_queryset
|
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def session_dates_list(self):
|
def dates_list(self):
|
||||||
now = local_now()
|
now = local_now()
|
||||||
dates = [(now - timezone.timedelta(days=i)).date() for i in range(self.days)]
|
dates = [(now - timezone.timedelta(days=i)).date() for i in range(self.days)]
|
||||||
dates.reverse()
|
dates.reverse()
|
||||||
return dates
|
return dates
|
||||||
|
|
||||||
def get_dates_metrics_date(self):
|
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
|
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
|
@staticmethod
|
||||||
def get_cache_key(date, tp):
|
def get_cache_key(date, tp):
|
||||||
date_str = date.strftime("%Y%m%d")
|
date_str = date.strftime("%Y%m%d")
|
||||||
|
@ -93,7 +166,7 @@ class DatesLoginMetricMixin:
|
||||||
|
|
||||||
def get_dates_metrics_total_count_login(self):
|
def get_dates_metrics_total_count_login(self):
|
||||||
data = []
|
data = []
|
||||||
for d in self.session_dates_list:
|
for d in self.dates_list:
|
||||||
count = self.get_date_login_count(d)
|
count = self.get_date_login_count(d)
|
||||||
data.append(count)
|
data.append(count)
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
|
@ -112,7 +185,7 @@ class DatesLoginMetricMixin:
|
||||||
|
|
||||||
def get_dates_metrics_total_count_active_users(self):
|
def get_dates_metrics_total_count_active_users(self):
|
||||||
data = []
|
data = []
|
||||||
for d in self.session_dates_list:
|
for d in self.dates_list:
|
||||||
count = self.get_date_user_count(d)
|
count = self.get_date_user_count(d)
|
||||||
data.append(count)
|
data.append(count)
|
||||||
return data
|
return data
|
||||||
|
@ -129,11 +202,28 @@ class DatesLoginMetricMixin:
|
||||||
|
|
||||||
def get_dates_metrics_total_count_active_assets(self):
|
def get_dates_metrics_total_count_active_assets(self):
|
||||||
data = []
|
data = []
|
||||||
for d in self.session_dates_list:
|
for d in self.dates_list:
|
||||||
count = self.get_date_asset_count(d)
|
count = self.get_date_asset_count(d)
|
||||||
data.append(count)
|
data.append(count)
|
||||||
return data
|
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
|
@lazyproperty
|
||||||
def get_type_to_assets(self):
|
def get_type_to_assets(self):
|
||||||
result = Asset.objects.annotate(type=F('platform__type')). \
|
result = Asset.objects.annotate(type=F('platform__type')). \
|
||||||
|
@ -181,8 +271,44 @@ class DatesLoginMetricMixin:
|
||||||
]
|
]
|
||||||
return sessions
|
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']
|
http_method_names = ['get']
|
||||||
|
|
||||||
def check_permissions(self, request):
|
def check_permissions(self, request):
|
||||||
|
@ -193,7 +319,7 @@ class IndexApi(DatesLoginMetricMixin, APIView):
|
||||||
|
|
||||||
query_params = self.request.query_params
|
query_params = self.request.query_params
|
||||||
|
|
||||||
caches = OrgResourceStatisticsCache(current_org)
|
caches = OrgResourceStatisticsCache(self.org)
|
||||||
|
|
||||||
_all = query_params.get('all')
|
_all = query_params.get('all')
|
||||||
|
|
||||||
|
@ -217,9 +343,9 @@ class IndexApi(DatesLoginMetricMixin, APIView):
|
||||||
'total_count_assets_this_week': caches.new_assets_amount_this_week,
|
'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({
|
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'):
|
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,
|
'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({
|
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'):
|
if _all or query_params.get('dates_metrics'):
|
||||||
|
|
|
@ -7,8 +7,6 @@ from common.cache import Cache, IntegerField
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.utils.timezone import local_zero_hour, local_monday
|
from common.utils.timezone import local_zero_hour, local_monday
|
||||||
from users.models import UserGroup, User
|
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 assets.models import Node, Domain, Asset, Account
|
||||||
from terminal.models import Session
|
from terminal.models import Session
|
||||||
from perms.models import AssetPermission
|
from perms.models import AssetPermission
|
||||||
|
@ -64,7 +62,6 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
|
||||||
asset_perms_amount = IntegerField(queryset=AssetPermission.objects)
|
asset_perms_amount = IntegerField(queryset=AssetPermission.objects)
|
||||||
total_count_online_users = IntegerField()
|
total_count_online_users = IntegerField()
|
||||||
total_count_online_sessions = IntegerField()
|
total_count_online_sessions = IntegerField()
|
||||||
total_count_today_login_users = IntegerField()
|
|
||||||
total_count_today_active_assets = IntegerField()
|
total_count_today_active_assets = IntegerField()
|
||||||
total_count_today_failed_sessions = IntegerField()
|
total_count_today_failed_sessions = IntegerField()
|
||||||
|
|
||||||
|
@ -113,16 +110,6 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
|
||||||
def compute_total_count_online_sessions():
|
def compute_total_count_online_sessions():
|
||||||
return Session.objects.filter(is_finished=False).count()
|
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
|
@staticmethod
|
||||||
def compute_total_count_today_active_assets():
|
def compute_total_count_today_active_assets():
|
||||||
t = local_zero_hour()
|
t = local_zero_hour()
|
||||||
|
|
|
@ -88,6 +88,9 @@ class AssetsSerializerFormatMixin:
|
||||||
serializer_class = serializers.AssetGrantedSerializer
|
serializer_class = serializers.AssetGrantedSerializer
|
||||||
filterset_fields = ['name', 'address', 'id', 'comment']
|
filterset_fields = ['name', 'address', 'id', 'comment']
|
||||||
search_fields = ['name', 'address', 'comment']
|
search_fields = ['name', 'address', 'comment']
|
||||||
|
filterset_class = AssetFilterSet
|
||||||
|
ordering_fields = ("name", "address")
|
||||||
|
ordering = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):
|
class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):
|
||||||
|
|
|
@ -5,8 +5,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from assets.const import Category, AllTypes
|
from assets.const import Category, AllTypes
|
||||||
from assets.serializers.asset.common import AssetProtocolsSerializer
|
|
||||||
from assets.models import Node, Asset, Platform, Account
|
from assets.models import Node, Asset, Platform, Account
|
||||||
|
from assets.serializers.asset.common import AssetProtocolsSerializer
|
||||||
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
|
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
|
||||||
from perms.serializers.permission import ActionChoicesField
|
from perms.serializers.permission import ActionChoicesField
|
||||||
|
|
||||||
|
@ -48,5 +48,6 @@ class AccountsPermedSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
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
|
read_only_fields = fields
|
||||||
|
|
|
@ -131,10 +131,11 @@ class NativeClient(TextChoices):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_launch_command(cls, name, token, endpoint, os='windows'):
|
def get_launch_command(cls, name, token, endpoint, os='windows'):
|
||||||
|
username = f'JMS-{token.id}'
|
||||||
commands = {
|
commands = {
|
||||||
cls.ssh: f'ssh {token.id}@{endpoint.host} -p {endpoint.ssh_port}',
|
cls.ssh: f'ssh {username}@{endpoint.host} -p {endpoint.ssh_port}',
|
||||||
cls.putty: f'putty -ssh {token.id}@{endpoint.host} -P {endpoint.ssh_port}',
|
cls.putty: f'putty.exe -ssh {username}@{endpoint.host} -P {endpoint.ssh_port}',
|
||||||
cls.xshell: f'xshell -url ssh://{token.id}:{token.value}@{endpoint.host}:{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.mysql: 'mysql -h {hostname} -P {port} -u {username} -p',
|
||||||
# cls.psql: {
|
# cls.psql: {
|
||||||
# 'default': 'psql -h {hostname} -p {port} -U {username} -W',
|
# 'default': 'psql -h {hostname} -p {port} -U {username} -W',
|
||||||
|
|
Loading…
Reference in New Issue