mirror of https://github.com/jumpserver/jumpserver
perf: Pam dashboard
parent
afc1d6610f
commit
83dc15d441
|
@ -1,5 +1,6 @@
|
||||||
from .account import *
|
from .account import *
|
||||||
|
from .application import *
|
||||||
|
from .pam_dashboard import *
|
||||||
from .task import *
|
from .task import *
|
||||||
from .template import *
|
from .template import *
|
||||||
from .virtual import *
|
from .virtual import *
|
||||||
from .application import *
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from django.http.response import JsonResponse
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from accounts.models import Account, RiskChoice
|
||||||
|
|
||||||
|
__all__ = ['PamDashboardApi']
|
||||||
|
|
||||||
|
|
||||||
|
class PamDashboardApi(APIView):
|
||||||
|
http_method_names = ['get']
|
||||||
|
rbac_perms = {
|
||||||
|
'GET': 'accounts.view_account',
|
||||||
|
}
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
query_params = self.request.query_params
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
account_count = Account.objects.count()
|
||||||
|
privileged_account_count = Account.objects.filter(privileged=True).count()
|
||||||
|
|
||||||
|
if query_params.get('total_privileged_accounts'):
|
||||||
|
data['total_privileged_accounts'] = privileged_account_count
|
||||||
|
|
||||||
|
if query_params.get('total_ordinary_accounts'):
|
||||||
|
data['total_ordinary_accounts'] = account_count - privileged_account_count
|
||||||
|
|
||||||
|
if query_params.get('total_unmanaged_accounts'):
|
||||||
|
data['total_unmanaged_accounts'] = Account.get_risks(RiskChoice.new_found).count()
|
||||||
|
|
||||||
|
if query_params.get('total_unavailable_accounts'):
|
||||||
|
data['total_unavailable_accounts'] = Account.objects.filter(is_active=False).count()
|
||||||
|
|
||||||
|
if query_params.get('total_weak_password_accounts'):
|
||||||
|
data['total_weak_password_accounts'] = Account.get_risks(RiskChoice.weak_password)
|
||||||
|
|
||||||
|
if query_params.get('total_long_time_change_password_accounts'):
|
||||||
|
data['total_long_time_change_password_accounts'] = Account.get_risks(RiskChoice.long_time_password)
|
||||||
|
|
||||||
|
return JsonResponse(data, status=200)
|
|
@ -3,7 +3,7 @@ from collections import defaultdict
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from accounts.models import Account, AccountRisk
|
from accounts.models import Account, AccountRisk, RiskChoice
|
||||||
from assets.automations.base.manager import BaseManager
|
from assets.automations.base.manager import BaseManager
|
||||||
from common.decorators import bulk_create_decorator, bulk_update_decorator
|
from common.decorators import bulk_create_decorator, bulk_update_decorator
|
||||||
from common.utils.strings import color_fmt
|
from common.utils.strings import color_fmt
|
||||||
|
@ -69,12 +69,12 @@ def check_account_secrets(accounts, assets):
|
||||||
|
|
||||||
if is_weak_password(account.secret):
|
if is_weak_password(account.secret):
|
||||||
print(tmpl % (account, color_fmt("weak", "red")))
|
print(tmpl % (account, color_fmt("weak", "red")))
|
||||||
summary["weak_password"] += 1
|
summary[RiskChoice.weak_password] += 1
|
||||||
result["weak_password"].append(result_item)
|
result[RiskChoice.weak_password].append(result_item)
|
||||||
risks.append(
|
risks.append(
|
||||||
{
|
{
|
||||||
"account": account,
|
"account": account,
|
||||||
"risk": "weak_password",
|
"risk": RiskChoice.weak_password,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -143,7 +143,7 @@ class CheckAccountManager(BaseManager):
|
||||||
"\n---\nSummary: \nok: %s, weak password: %s, no secret: %s, using time: %ss"
|
"\n---\nSummary: \nok: %s, weak password: %s, no secret: %s, using time: %ss"
|
||||||
% (
|
% (
|
||||||
self.summary["ok"],
|
self.summary["ok"],
|
||||||
self.summary["weak_password"],
|
self.summary[RiskChoice.weak_password],
|
||||||
self.summary["no_secret"],
|
self.summary["no_secret"],
|
||||||
int(self.duration),
|
int(self.duration),
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from collections import defaultdict
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from accounts.const import AutomationTypes
|
from accounts.const import AutomationTypes
|
||||||
from accounts.models import GatheredAccount, Account, AccountRisk
|
from accounts.models import GatheredAccount, Account, AccountRisk, RiskChoice
|
||||||
from common.const import ConfirmOrIgnore
|
from common.const import ConfirmOrIgnore
|
||||||
from common.decorators import bulk_create_decorator, bulk_update_decorator
|
from common.decorators import bulk_create_decorator, bulk_update_decorator
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
@ -68,7 +68,7 @@ class AnalyseAccountRisk:
|
||||||
{"field": "date_last_login", "risk": "long_time_no_login", "delta": long_time},
|
{"field": "date_last_login", "risk": "long_time_no_login", "delta": long_time},
|
||||||
{
|
{
|
||||||
"field": "date_password_change",
|
"field": "date_password_change",
|
||||||
"risk": "long_time_password",
|
"risk": RiskChoice.long_time_password,
|
||||||
"delta": long_time,
|
"delta": long_time,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -164,7 +164,7 @@ class AnalyseAccountRisk:
|
||||||
self._create_risk(
|
self._create_risk(
|
||||||
dict(
|
dict(
|
||||||
**basic,
|
**basic,
|
||||||
risk="new_found",
|
risk=RiskChoice.new_found,
|
||||||
details=[{"datetime": self.now.isoformat()}],
|
details=[{"datetime": self.now.isoformat()}],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from django.db.models import Q, Exists, OuterRef
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django_filters import rest_framework as drf_filters
|
from django_filters import rest_framework as drf_filters
|
||||||
|
|
||||||
from assets.models import Node
|
from assets.models import Node
|
||||||
from common.drf.filters import BaseFilterSet
|
from common.drf.filters import BaseFilterSet
|
||||||
from common.utils.timezone import local_zero_hour, local_now
|
from common.utils.timezone import local_zero_hour, local_now
|
||||||
from .models import Account, GatheredAccount, ChangeSecretRecord, AccountRisk
|
from .models import Account, GatheredAccount, ChangeSecretRecord
|
||||||
|
|
||||||
|
|
||||||
class AccountFilterSet(BaseFilterSet):
|
class AccountFilterSet(BaseFilterSet):
|
||||||
|
@ -62,16 +62,7 @@ class AccountFilterSet(BaseFilterSet):
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
queryset = queryset.filter(
|
return Account.get_risks(queryset, value)
|
||||||
Exists(
|
|
||||||
AccountRisk.objects.filter(
|
|
||||||
risk=value,
|
|
||||||
asset_id=OuterRef('asset_id'),
|
|
||||||
username=OuterRef('username')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_latest(queryset, name, value):
|
def filter_latest(queryset, name, value):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Exists, OuterRef
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
|
@ -165,6 +166,22 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount):
|
||||||
|
|
||||||
return escape(value)
|
return escape(value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_risks(cls, queryset=None, risk_type=None):
|
||||||
|
from accounts.models import AccountRisk
|
||||||
|
subquery = AccountRisk.objects.filter(
|
||||||
|
asset_id=OuterRef('asset_id'),
|
||||||
|
username=OuterRef('username')
|
||||||
|
)
|
||||||
|
|
||||||
|
if risk_type:
|
||||||
|
subquery = subquery.filter(risk=risk_type)
|
||||||
|
|
||||||
|
if queryset is None:
|
||||||
|
queryset = cls.objects.all()
|
||||||
|
|
||||||
|
return queryset.filter(Exists(subquery))
|
||||||
|
|
||||||
|
|
||||||
def replace_history_model_with_mixin():
|
def replace_history_model_with_mixin():
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from accounts.const import AutomationTypes
|
from accounts.const import AutomationTypes
|
||||||
from common.const import ConfirmOrIgnore
|
|
||||||
from accounts.models import (
|
from accounts.models import (
|
||||||
GatheredAccount,
|
GatheredAccount,
|
||||||
AccountRisk,
|
AccountRisk,
|
||||||
SecretType,
|
SecretType,
|
||||||
AutomationExecution,
|
AutomationExecution, RiskChoice,
|
||||||
)
|
)
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from common.const import ConfirmOrIgnore
|
from common.const import ConfirmOrIgnore
|
||||||
|
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [
|
||||||
|
@ -83,7 +81,7 @@ class RiskHandler:
|
||||||
GatheredAccount.objects.filter(asset=self.asset, username=self.username).update(
|
GatheredAccount.objects.filter(asset=self.asset, username=self.username).update(
|
||||||
present=True, status=ConfirmOrIgnore.confirmed
|
present=True, status=ConfirmOrIgnore.confirmed
|
||||||
)
|
)
|
||||||
self.risk = "new_found"
|
self.risk = RiskChoice.new_found
|
||||||
|
|
||||||
def handle_disable_remote(self):
|
def handle_disable_remote(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -49,6 +49,7 @@ urlpatterns = [
|
||||||
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(),
|
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(),
|
||||||
name='push-account-add-or-remove-node'),
|
name='push-account-add-or-remove-node'),
|
||||||
path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'),
|
path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'),
|
||||||
|
path('pam-dashboard/', api.PamDashboardApi.as_view(), name='pam-dashboard'),
|
||||||
path('change-secret-dashboard/', api.ChangeSecretDashboardApi.as_view(), name='change-secret-dashboard'),
|
path('change-secret-dashboard/', api.ChangeSecretDashboardApi.as_view(), name='change-secret-dashboard'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue