diff --git a/apps/acls/migrations/0005_auto_20221201_1846.py b/apps/acls/migrations/0005_auto_20221201_1846.py index b69216896..4885ea97e 100644 --- a/apps/acls/migrations/0005_auto_20221201_1846.py +++ b/apps/acls/migrations/0005_auto_20221201_1846.py @@ -5,7 +5,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('acls', '0004_auto_20220831_1658'), @@ -15,7 +14,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='loginacl', name='action', - field=models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow'), ('confirm', 'Confirm')], default='reject', max_length=64, verbose_name='Action'), + field=models.CharField(default='reject', max_length=64, verbose_name='Action'), ), migrations.AlterField( model_name='loginacl', @@ -25,7 +24,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='loginassetacl', name='action', - field=models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow'), ('confirm', 'Confirm')], default='reject', max_length=64, verbose_name='Action'), + field=models.CharField(default='reject', max_length=64, verbose_name='Action'), ), migrations.AlterField( model_name='loginassetacl', diff --git a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py index 05122b733..95b12e9f0 100644 --- a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py +++ b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py @@ -1,13 +1,13 @@ # Generated by Django 3.2.14 on 2022-12-01 11:39 -from django.conf import settings +import uuid + import django.core.validators +from django.conf import settings from django.db import migrations, models -import uuid class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('acls', '0005_auto_20221201_1846'), @@ -22,9 +22,11 @@ class Migration(migrations.Migration): ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), - ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('org_id', + models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), ('name', models.CharField(max_length=128, verbose_name='Name')), - ('type', models.CharField(choices=[('command', 'Command'), ('regex', 'Regex')], default='command', max_length=16, verbose_name='Type')), + ('type', models.CharField(choices=[('command', 'Command'), ('regex', 'Regex')], default='command', + max_length=16, verbose_name='Type')), ('content', models.TextField(help_text='One line one command', verbose_name='Content')), ('ignore_case', models.BooleanField(default=True, verbose_name='Ignore case')), ], @@ -36,21 +38,26 @@ class Migration(migrations.Migration): migrations.CreateModel( name='CommandFilterACL', fields=[ - ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('org_id', + models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('name', models.CharField(max_length=128, verbose_name='Name')), - ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')), - ('action', models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow'), ('confirm', 'Confirm')], default='reject', max_length=64, verbose_name='Action')), + ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', + validators=[django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100)], + verbose_name='Priority')), + ('action', models.CharField(default='reject', max_length=64, verbose_name='Action')), ('is_active', models.BooleanField(default=True, verbose_name='Active')), ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), ('users', models.JSONField(verbose_name='User')), ('accounts', models.JSONField(verbose_name='Account')), ('assets', models.JSONField(verbose_name='Asset')), ('commands', models.ManyToManyField(to='acls.CommandGroup', verbose_name='Commands')), - ('reviewers', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), + ( + 'reviewers', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), ], options={ 'verbose_name': 'Command acl', diff --git a/apps/acls/migrations/0007_auto_20221202_1048.py b/apps/acls/migrations/0007_auto_20221202_1048.py new file mode 100644 index 000000000..1a61a4ff4 --- /dev/null +++ b/apps/acls/migrations/0007_auto_20221202_1048.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.14 on 2022-12-02 02:48 + +from django.db import migrations + + +def migrate_login_type(apps, schema_editor): + login_asset_model = apps.get_model('acls', 'LoginAssetACL') + login_asset_model.objects.filter(action='login_confirm').update(action='review') + + login_system_model = apps.get_model('acls', 'LoginACL') + login_system_model.objects.filter(action='confirm').update(action='review') + + +class Migration(migrations.Migration): + dependencies = [ + ('acls', '0006_commandfilteracl_commandgroup'), + ] + + operations = [ + migrations.RunPython(migrate_login_type), + ] diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 6bda02df8..33e1fbc2a 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -1,16 +1,18 @@ +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models +from django.db.models import Q from django.utils.translation import ugettext_lazy as _ -from django.core.validators import MinValueValidator, MaxValueValidator -from common.mixins import CommonModelMixin +from common.mixins import CommonModelMixin +from common.utils import contains_ip -__all__ = ['BaseACL', 'BaseACLQuerySet', 'ACLManager'] +__all__ = ['BaseACL', 'BaseACLQuerySet', 'ACLManager', 'AssetAccountUserACLQuerySet'] class ActionChoices(models.TextChoices): reject = 'reject', _('Reject') - allow = 'allow', _('Allow') - confirm = 'confirm', _('Confirm') + accept = 'allow', _('Allow') + review = 'review', _('Review') class BaseACLQuerySet(models.QuerySet): @@ -27,6 +29,32 @@ class BaseACLQuerySet(models.QuerySet): return self.inactive() +class AssetAccountUserACLQuerySet(BaseACLQuerySet): + def filter_user(self, user): + return self.filter( + Q(users__username_group__contains=user.username) | + Q(users__username_group__contains='*') + ) + + def filter_asset(self, asset): + queryset = self.filter( + Q(assets__name_group__contains=asset.name) | + Q(assets__name_group__contains='*') + ) + ids = [ + q.id for q in queryset + if contains_ip(asset.address, q.assets.get('address_group', [])) + ] + queryset = self.filter(id__in=ids) + return queryset + + def filter_account(self, account_username): + return self.filter( + Q(accounts__username_group__contains=account_username) | + Q(accounts__username_group__contains='*') + ) + + class ACLManager(models.Manager): def valid(self): return self.get_queryset().valid() @@ -39,10 +67,7 @@ class BaseACL(CommonModelMixin): help_text=_("1-100, the lower the value will be match first"), validators=[MinValueValidator(1), MaxValueValidator(100)] ) - action = models.CharField( - max_length=64, verbose_name=_('Action'), - choices=ActionChoices.choices, default=ActionChoices.reject - ) + action = models.CharField(max_length=64, default=ActionChoices.reject, verbose_name=_('Action')) reviewers = models.ManyToManyField('users.User', blank=True, verbose_name=_("Reviewers")) is_active = models.BooleanField(default=True, verbose_name=_("Active")) comment = models.TextField(default='', blank=True, verbose_name=_('Comment')) diff --git a/apps/acls/models/command_acl.py b/apps/acls/models/command_acl.py index 4fba67a3d..056d9b4f6 100644 --- a/apps/acls/models/command_acl.py +++ b/apps/acls/models/command_acl.py @@ -6,11 +6,11 @@ from django.db import models from django.db.models import Q from django.utils.translation import ugettext_lazy as _ -from users.models import User, UserGroup -from orgs.mixins.models import JMSOrgBaseModel from common.utils import lazyproperty, get_logger, get_object_or_none +from orgs.mixins.models import JMSOrgBaseModel from orgs.mixins.models import OrgModelMixin -from .base import BaseACL +from users.models import User, UserGroup +from .base import BaseACL, AssetAccountUserACLQuerySet, ACLManager logger = get_logger(__file__) @@ -50,7 +50,6 @@ class CommandGroup(JMSOrgBaseModel): if ' ' in _cmd: regex.append(cmd) continue - if not cmd: continue @@ -89,6 +88,19 @@ class CommandGroup(JMSOrgBaseModel): def __str__(self): return '{} % {}'.format(self.type, self.content) + +class CommandFilterACL(OrgModelMixin, BaseACL): + users = models.JSONField(verbose_name=_('User')) + assets = models.JSONField(verbose_name=_('Asset')) + accounts = models.JSONField(verbose_name=_('Account')) + commands = models.ManyToManyField(CommandGroup, verbose_name=_('Commands')) + objects = ACLManager.from_queryset(AssetAccountUserACLQuerySet)() + + class Meta: + unique_together = ('name', 'org_id') + ordering = ('priority', '-date_updated', 'name') + verbose_name = _('Command acl') + def create_command_confirm_ticket(self, run_command, session, cmd_filter_rule, org_id): from tickets.const import TicketType from tickets.models import ApplyCommandTicket @@ -147,16 +159,3 @@ class CommandGroup(JMSOrgBaseModel): else: rules = cls.objects.none() return rules - - -class CommandFilterACL(OrgModelMixin, BaseACL): - # 条件 - users = models.JSONField(verbose_name=_('User')) - accounts = models.JSONField(verbose_name=_('Account')) - assets = models.JSONField(verbose_name=_('Asset')) - commands = models.ManyToManyField(CommandGroup, verbose_name=_('Commands')) - - class Meta: - unique_together = ('name', 'org_id') - ordering = ('priority', '-date_updated', 'name') - verbose_name = _('Command acl') diff --git a/apps/acls/models/login_asset_acl.py b/apps/acls/models/login_asset_acl.py index de9897c7b..6af48faab 100644 --- a/apps/acls/models/login_asset_acl.py +++ b/apps/acls/models/login_asset_acl.py @@ -1,35 +1,8 @@ from django.db import models -from django.db.models import Q from django.utils.translation import ugettext_lazy as _ -from orgs.mixins.models import OrgModelMixin, OrgManager -from .base import BaseACL, BaseACLQuerySet, ACLManager -from common.utils.ip import contains_ip - -class ACLQuerySet(BaseACLQuerySet): - def filter_user(self, user): - return self.filter( - Q(users__username_group__contains=user.username) | - Q(users__username_group__contains='*') - ) - - def filter_asset(self, asset): - queryset = self.filter( - Q(assets__name_group__contains=asset.name) | - Q(assets__name_group__contains='*') - ) - ids = [ - q.id for q in queryset - if contains_ip(asset.address, q.assets.get('address_group', [])) - ] - queryset = LoginAssetACL.objects.filter(id__in=ids) - return queryset - - def filter_account(self, account_username): - return self.filter( - Q(accounts__username_group__contains=account_username) | - Q(accounts__username_group__contains='*') - ) +from orgs.mixins.models import OrgModelMixin +from .base import BaseACL, ACLManager, AssetAccountUserACLQuerySet class LoginAssetACL(BaseACL, OrgModelMixin): @@ -38,7 +11,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin): accounts = models.JSONField(verbose_name=_('Account')) assets = models.JSONField(verbose_name=_('Asset')) - objects = ACLManager.from_queryset(ACLQuerySet)() + objects = ACLManager.from_queryset(AssetAccountUserACLQuerySet)() class Meta: unique_together = ('name', 'org_id') @@ -65,4 +38,3 @@ class LoginAssetACL(BaseACL, OrgModelMixin): ticket = ApplyLoginAssetTicket.objects.create(**data) ticket.open_by_system(assignees) return ticket - diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py new file mode 100644 index 000000000..9f511cd06 --- /dev/null +++ b/apps/acls/serializers/base.py @@ -0,0 +1,94 @@ +from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers + +from acls.models.base import ActionChoices +from common.drf.fields import LabeledChoiceField, ObjectRelatedField +from orgs.models import Organization +from users.models import User + +common_help_text = _( + "Format for comma-delimited string, with * indicating a match all. " +) + + +class ACLUsersSerializer(serializers.Serializer): + username_group = serializers.ListField( + default=["*"], + child=serializers.CharField(max_length=128), + label=_("Username"), + help_text=common_help_text, + ) + + +class ACLAssestsSerializer(serializers.Serializer): + address_group_help_text = _( + "Format for comma-delimited string, with * indicating a match all. " + "Such as: " + "192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64" + " (Domain name support)" + ) + + name_group = serializers.ListField( + default=["*"], + child=serializers.CharField(max_length=128), + label=_("Name"), + help_text=common_help_text, + ) + address_group = serializers.ListField( + default=["*"], + child=serializers.CharField(max_length=1024), + label=_("IP/Host"), + help_text=address_group_help_text, + ) + + +class ACLAccountsSerializer(serializers.Serializer): + username_group = serializers.ListField( + default=["*"], + child=serializers.CharField(max_length=128), + label=_("Username"), + help_text=common_help_text, + ) + + +class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): + users = ACLUsersSerializer() + assets = ACLAssestsSerializer() + accounts = ACLAccountsSerializer() + reviewers = ObjectRelatedField( + queryset=User.objects, many=True, required=False, label=_('Reviewers') + ) + reviewers_amount = serializers.IntegerField(read_only=True, source="reviewers.count") + action = LabeledChoiceField( + choices=ActionChoices.choices, label=_("Action") + ) + + class Meta: + fields_mini = ["id", "name"] + fields_small = fields_mini + [ + "users", "accounts", "assets", "is_active", + "date_created", "date_updated", "priority", + "action", "comment", "created_by", "org_id", + ] + fields_m2m = ["reviewers", "reviewers_amount"] + fields = fields_small + fields_m2m + extra_kwargs = { + "reviewers": {"allow_null": False, "required": True}, + "priority": {"default": 50}, + "is_active": {"default": True}, + } + + def validate_reviewers(self, reviewers): + org_id = self.fields["org_id"].default() + org = Organization.get_instance(org_id) + if not org: + error = _("The organization `{}` does not exist".format(org_id)) + raise serializers.ValidationError(error) + users = org.get_members() + valid_reviewers = list(set(reviewers) & set(users)) + if not valid_reviewers: + error = _( + "None of the reviewers belong to Organization `{}`".format(org.name) + ) + raise serializers.ValidationError(error) + return valid_reviewers diff --git a/apps/acls/serializers/command_filter.py b/apps/acls/serializers/command_filter.py index e69de29bb..a6b090c42 100644 --- a/apps/acls/serializers/command_filter.py +++ b/apps/acls/serializers/command_filter.py @@ -0,0 +1,16 @@ +from django.utils.translation import ugettext_lazy as _ + +from acls.models import CommandGroup, CommandFilterACL +from common.drf.fields import ObjectRelatedField +from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from .base import BaseUserAssetAccountACLSerializerMixin + +__all__ = ["CommandFilterACLSerializer"] + + +class CommandFilterACLSerializer(BaseUserAssetAccountACLSerializerMixin, BulkOrgResourceModelSerializer): + commands = ObjectRelatedField(queryset=CommandGroup.objects, many=True, required=False, label=_('Commands')) + + class Meta(BaseUserAssetAccountACLSerializerMixin.Meta): + model = CommandFilterACL + fields = BaseUserAssetAccountACLSerializerMixin.Meta.fields + ['commands'] diff --git a/apps/acls/serializers/login_asset_acl.py b/apps/acls/serializers/login_asset_acl.py index 6e3e6bc50..b360bb55f 100644 --- a/apps/acls/serializers/login_asset_acl.py +++ b/apps/acls/serializers/login_asset_acl.py @@ -1,109 +1,11 @@ -from rest_framework import serializers -from django.utils.translation import ugettext_lazy as _ - -from common.drf.fields import LabeledChoiceField -from common.drf.fields import ObjectRelatedField from orgs.mixins.serializers import BulkOrgResourceModelSerializer -from orgs.models import Organization -from users.models import User -from acls import models +from .base import BaseUserAssetAccountACLSerializerMixin +from ..models import LoginAssetACL __all__ = ["LoginAssetACLSerializer"] -common_help_text = _( - "Format for comma-delimited string, with * indicating a match all. " -) - - -class LoginAssetACLUsersSerializer(serializers.Serializer): - username_group = serializers.ListField( - default=["*"], - child=serializers.CharField(max_length=128), - label=_("Username"), - help_text=common_help_text, - ) - - -class LoginAssetACLAssestsSerializer(serializers.Serializer): - address_group_help_text = _( - "Format for comma-delimited string, with * indicating a match all. " - "Such as: " - "192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64" - " (Domain name support)" - ) - - name_group = serializers.ListField( - default=["*"], - child=serializers.CharField(max_length=128), - label=_("Name"), - help_text=common_help_text, - ) - address_group = serializers.ListField( - default=["*"], - child=serializers.CharField(max_length=1024), - label=_("IP/Host"), - help_text=address_group_help_text, - ) - - -class LoginAssetACLAccountsSerializer(serializers.Serializer): - username_group = serializers.ListField( - default=["*"], - child=serializers.CharField(max_length=128), - label=_("Username"), - help_text=common_help_text, - ) - - -class LoginAssetACLSerializer(BulkOrgResourceModelSerializer): - users = LoginAssetACLUsersSerializer() - assets = LoginAssetACLAssestsSerializer() - accounts = LoginAssetACLAccountsSerializer() - reviewers = ObjectRelatedField( - queryset=User.objects, many=True, required=False, label=_('Reviewers') - ) - reviewers_amount = serializers.IntegerField(read_only=True, source="reviewers.count") - action = LabeledChoiceField( - choices=models.LoginAssetACL.ActionChoices.choices, label=_("Action") - ) - - class Meta: - model = models.LoginAssetACL - fields_mini = ["id", "name"] - fields_small = fields_mini + [ - "users", - "accounts", - "assets", - "is_active", - "date_created", - "date_updated", - "priority", - "action", - "comment", - "created_by", - "org_id", - ] - fields_m2m = ["reviewers", "reviewers_amount"] - fields = fields_small + fields_m2m - extra_kwargs = { - "reviewers": {"allow_null": False, "required": True}, - "priority": {"default": 50}, - "is_active": {"default": True}, - } - - def validate_reviewers(self, reviewers): - org_id = self.fields["org_id"].default() - org = Organization.get_instance(org_id) - if not org: - error = _("The organization `{}` does not exist".format(org_id)) - raise serializers.ValidationError(error) - users = org.get_members() - valid_reviewers = list(set(reviewers) & set(users)) - if not valid_reviewers: - error = _( - "None of the reviewers belong to Organization `{}`".format(org.name) - ) - raise serializers.ValidationError(error) - return valid_reviewers +class LoginAssetACLSerializer(BaseUserAssetAccountACLSerializerMixin, BulkOrgResourceModelSerializer): + class Meta(BaseUserAssetAccountACLSerializerMixin.Meta): + model = LoginAssetACL diff --git a/apps/assets/models/cmd_filter.py b/apps/assets/models/cmd_filter.py index 5b9b1ad85..5f4adebcf 100644 --- a/apps/assets/models/cmd_filter.py +++ b/apps/assets/models/cmd_filter.py @@ -1,17 +1,13 @@ # -*- coding: utf-8 -*- # -import re import uuid -from django.db import models -from django.db.models import Q from django.core.validators import MinValueValidator, MaxValueValidator +from django.db import models from django.utils.translation import ugettext_lazy as _ -from users.models import User, UserGroup +from common.utils import get_logger from orgs.mixins.models import OrgModelMixin -from common.utils import lazyproperty, get_logger, get_object_or_none -from ..models import Asset, Account logger = get_logger(__file__) @@ -93,125 +89,3 @@ class CommandFilterRule(OrgModelMixin): class Meta: ordering = ('priority', 'action') verbose_name = _("Command filter rule") - - @lazyproperty - def pattern(self): - if self.type == 'command': - s = self.construct_command_regex(content=self.content) - else: - s = r'{0}'.format(self.content) - return s - - @classmethod - def construct_command_regex(cls, content): - regex = [] - content = content.replace('\r\n', '\n') - for _cmd in content.split('\n'): - cmd = re.sub(r'\s+', ' ', _cmd) - cmd = re.escape(cmd) - cmd = cmd.replace('\\ ', '\s+') - - # 有空格就不能 铆钉单词了 - if ' ' in _cmd: - regex.append(cmd) - continue - - if not cmd: - continue - - # 如果是单个字符 - if cmd[-1].isalpha(): - regex.append(r'\b{0}\b'.format(cmd)) - else: - regex.append(r'\b{0}'.format(cmd)) - s = r'{}'.format('|'.join(regex)) - return s - - @staticmethod - def compile_regex(regex, ignore_case): - try: - if ignore_case: - pattern = re.compile(regex, re.IGNORECASE) - else: - pattern = re.compile(regex) - except Exception as e: - error = _('The generated regular expression is incorrect: {}').format(str(e)) - logger.error(error) - return False, error, None - return True, '', pattern - - def match(self, data): - succeed, error, pattern = self.compile_regex(self.pattern, self.ignore_case) - if not succeed: - return self.ACTION_UNKNOWN, '' - - found = pattern.search(data) - if not found: - return self.ACTION_UNKNOWN, '' - - if self.action == self.ActionChoices.allow: - return self.ActionChoices.allow, found.group() - else: - return self.ActionChoices.deny, found.group() - - def __str__(self): - return '{} % {}'.format(self.type, self.content) - - def create_command_confirm_ticket(self, run_command, session, cmd_filter_rule, org_id): - from tickets.const import TicketType - from tickets.models import ApplyCommandTicket - data = { - 'title': _('Command confirm') + ' ({})'.format(session.user), - 'type': TicketType.command_confirm, - 'applicant': session.user_obj, - 'apply_run_user_id': session.user_id, - 'apply_run_asset': str(session.asset), - 'apply_run_account': str(session.account), - 'apply_run_command': run_command[:4090], - 'apply_from_session_id': str(session.id), - 'apply_from_cmd_filter_rule_id': str(cmd_filter_rule.id), - 'apply_from_cmd_filter_id': str(cmd_filter_rule.filter.id), - 'org_id': org_id, - } - ticket = ApplyCommandTicket.objects.create(**data) - assignees = self.reviewers.all() - ticket.open_by_system(assignees) - return ticket - - @classmethod - def get_queryset( - cls, user_id=None, user_group_id=None, account=None, - asset_id=None, org_id=None - ): - from assets.models import Account - user_groups = [] - user = get_object_or_none(User, pk=user_id) - if user: - user_groups.extend(list(user.groups.all())) - user_group = get_object_or_none(UserGroup, pk=user_group_id) - if user_group: - org_id = user_group.org_id - user_groups.append(user_group) - - asset = get_object_or_none(Asset, pk=asset_id) - q = Q() - if user: - q |= Q(users=user) - if user_groups: - q |= Q(user_groups__in=set(user_groups)) - if account: - org_id = account.org_id - q |= Q(accounts__contains=account.username) | \ - Q(accounts__contains=Account.AliasAccount.ALL) - if asset: - org_id = asset.org_id - q |= Q(assets=asset) - if q: - cmd_filters = CommandFilter.objects.filter(q).filter(is_active=True) - if org_id: - cmd_filters = cmd_filters.filter(org_id=org_id) - rule_ids = cmd_filters.values_list('rules', flat=True) - rules = cls.objects.filter(id__in=rule_ids) - else: - rules = cls.objects.none() - return rules diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 7341b4bd1..ec6d2e98d 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -1,25 +1,25 @@ # -*- coding: utf-8 -*- # import inspect -from functools import partial import time +from functools import partial from typing import Callable -from django.utils.http import urlencode -from django.core.cache import cache from django.conf import settings from django.contrib import auth -from django.utils.translation import ugettext as _ -from rest_framework.request import Request from django.contrib.auth import ( BACKEND_SESSION_KEY, load_backend, PermissionDenied, user_login_failed, _clean_credentials, ) +from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured from django.shortcuts import reverse, redirect, get_object_or_404 +from django.utils.http import urlencode +from django.utils.translation import ugettext as _ +from rest_framework.request import Request -from common.utils import get_request_ip, get_logger, bulk_get, FlashMessageUtil from acls.models import LoginACL +from common.utils import get_request_ip, get_logger, bulk_get, FlashMessageUtil from users.models import User from users.utils import LoginBlockUtil, MFABlockUtils, LoginIpBlockUtil from . import errors