policies/dummy: separate dummy policy from core into app
This commit is contained in:
parent
c0b05a62f4
commit
9bccf9bb0a
|
@ -1,4 +1,5 @@
|
|||
"""api v2 urls"""
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
from django.urls import path
|
||||
from drf_yasg import openapi
|
||||
|
@ -31,7 +32,6 @@ from passbook.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProvider
|
|||
from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
|
||||
from passbook.sources.oauth.api import OAuthSourceViewSet
|
||||
from passbook.stages.captcha.api import CaptchaStageViewSet
|
||||
from passbook.stages.dummy.api import DummyStageViewSet
|
||||
from passbook.stages.email.api import EmailStageViewSet
|
||||
from passbook.stages.identification.api import IdentificationStageViewSet
|
||||
from passbook.stages.login.api import LoginStageViewSet
|
||||
|
@ -78,7 +78,6 @@ router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
|
|||
|
||||
router.register("stages/all", StageViewSet)
|
||||
router.register("stages/captcha", CaptchaStageViewSet)
|
||||
router.register("stages/dummy", DummyStageViewSet)
|
||||
router.register("stages/email", EmailStageViewSet)
|
||||
router.register("stages/otp", OTPStageViewSet)
|
||||
router.register("stages/password", PasswordStageViewSet)
|
||||
|
@ -88,6 +87,13 @@ router.register("stages/login", LoginStageViewSet)
|
|||
router.register("flows", FlowViewSet)
|
||||
router.register("flows/bindings", FlowStageBindingViewSet)
|
||||
|
||||
if settings.DEBUG:
|
||||
from passbook.stages.dummy.api import DummyStageViewSet
|
||||
from passbook.policies.dummy.api import DummyPolicyViewSet
|
||||
|
||||
router.register("stages/dummy", DummyStageViewSet)
|
||||
router.register("policies/dummy", DummyPolicyViewSet)
|
||||
|
||||
info = openapi.Info(
|
||||
title="passbook API",
|
||||
default_version="v2",
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 3.0.5 on 2020-05-10 00:08
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_core", "0012_delete_factor"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(name="DebugPolicy",),
|
||||
]
|
|
@ -1,7 +1,5 @@
|
|||
"""passbook core models"""
|
||||
from datetime import timedelta
|
||||
from random import SystemRandom
|
||||
from time import sleep
|
||||
from typing import Any, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
|
@ -198,29 +196,6 @@ class Policy(ExportModelOperationsMixin("policy"), UUIDModel, CreatedUpdatedMode
|
|||
raise PolicyException()
|
||||
|
||||
|
||||
class DebugPolicy(Policy):
|
||||
"""Policy used for debugging the PolicyEngine. Returns a fixed result,
|
||||
but takes a random time to process."""
|
||||
|
||||
result = models.BooleanField(default=False)
|
||||
wait_min = models.IntegerField(default=5)
|
||||
wait_max = models.IntegerField(default=30)
|
||||
|
||||
form = "passbook.core.forms.policies.DebugPolicyForm"
|
||||
|
||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
||||
"""Wait random time then return result"""
|
||||
wait = SystemRandom().randrange(self.wait_min, self.wait_max)
|
||||
LOGGER.debug("Policy waiting", policy=self, delay=wait)
|
||||
sleep(wait)
|
||||
return PolicyResult(self.result, "Debugging")
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name = _("Debug Policy")
|
||||
verbose_name_plural = _("Debug Policies")
|
||||
|
||||
|
||||
class Invitation(ExportModelOperationsMixin("invitation"), UUIDModel):
|
||||
"""Single-use invitation link"""
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
"""Dummy Policy API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from passbook.policies.dummy.models import DummyPolicy
|
||||
from passbook.policies.forms import GENERAL_SERIALIZER_FIELDS
|
||||
|
||||
|
||||
class DummyPolicySerializer(ModelSerializer):
|
||||
"""Dummy Policy Serializer"""
|
||||
|
||||
class Meta:
|
||||
model = DummyPolicy
|
||||
fields = GENERAL_SERIALIZER_FIELDS + ["result", "wait_min", "wait_max"]
|
||||
|
||||
|
||||
class DummyPolicyViewSet(ModelViewSet):
|
||||
"""Dummy Viewset"""
|
||||
|
||||
queryset = DummyPolicy.objects.all()
|
||||
serializer_class = DummyPolicySerializer
|
|
@ -0,0 +1,11 @@
|
|||
"""Passbook policy dummy app config"""
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PassbookPolicyDummyConfig(AppConfig):
|
||||
"""Passbook policy_dummy app config"""
|
||||
|
||||
name = "passbook.policies.dummy"
|
||||
label = "passbook_policies_dummy"
|
||||
verbose_name = "passbook Policies.Dummy"
|
|
@ -3,16 +3,16 @@
|
|||
from django import forms
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.core.models import DebugPolicy
|
||||
from passbook.policies.dummy.models import DummyPolicy
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
|
||||
|
||||
class DebugPolicyForm(forms.ModelForm):
|
||||
"""DebugPolicyForm Form"""
|
||||
class DummyPolicyForm(forms.ModelForm):
|
||||
"""DummyPolicyForm Form"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = DebugPolicy
|
||||
model = DummyPolicy
|
||||
fields = GENERAL_FIELDS + ["result", "wait_min", "wait_max"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 3.0.5 on 2020-05-10 00:08
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("passbook_core", "0013_delete_debugpolicy"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="DummyPolicy",
|
||||
fields=[
|
||||
(
|
||||
"policy_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="passbook_core.Policy",
|
||||
),
|
||||
),
|
||||
("result", models.BooleanField(default=False)),
|
||||
("wait_min", models.IntegerField(default=5)),
|
||||
("wait_max", models.IntegerField(default=30)),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Dummy Policy",
|
||||
"verbose_name_plural": "Dummy Policies",
|
||||
},
|
||||
bases=("passbook_core.policy",),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,35 @@
|
|||
"""Dummy policy"""
|
||||
from random import SystemRandom
|
||||
from time import sleep
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from structlog import get_logger
|
||||
|
||||
from passbook.core.models import Policy
|
||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
class DummyPolicy(Policy):
|
||||
"""Policy used for debugging the PolicyEngine. Returns a fixed result,
|
||||
but takes a random time to process."""
|
||||
|
||||
result = models.BooleanField(default=False)
|
||||
wait_min = models.IntegerField(default=5)
|
||||
wait_max = models.IntegerField(default=30)
|
||||
|
||||
form = "passbook.policies.dummy.forms.DummyPolicyForm"
|
||||
|
||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
||||
"""Wait random time then return result"""
|
||||
wait = SystemRandom().randrange(self.wait_min, self.wait_max)
|
||||
LOGGER.debug("Policy waiting", policy=self, delay=wait)
|
||||
sleep(wait)
|
||||
return PolicyResult(self.result, "dummy")
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name = _("Dummy Policy")
|
||||
verbose_name_plural = _("Dummy Policies")
|
|
@ -1,4 +1,4 @@
|
|||
"""Source API Views"""
|
||||
"""Password Expiry Policy API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
|
@ -15,7 +15,7 @@ class PasswordExpiryPolicySerializer(ModelSerializer):
|
|||
|
||||
|
||||
class PasswordExpiryPolicyViewSet(ModelViewSet):
|
||||
"""Source Viewset"""
|
||||
"""Password Expiry Viewset"""
|
||||
|
||||
queryset = PasswordExpiryPolicy.objects.all()
|
||||
serializer_class = PasswordExpiryPolicySerializer
|
||||
|
|
|
@ -4,8 +4,8 @@ from django import forms
|
|||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.core.forms.policies import GENERAL_FIELDS
|
||||
from passbook.policies.expiry.models import PasswordExpiryPolicy
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
|
||||
|
||||
class PasswordExpiryPolicyForm(forms.ModelForm):
|
||||
|
|
|
@ -4,7 +4,7 @@ from django import forms
|
|||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.core.forms.policies import GENERAL_FIELDS
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
from passbook.policies.hibp.models import HaveIBeenPwendPolicy
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.core.forms.policies import GENERAL_FIELDS
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
from passbook.policies.reputation.models import ReputationPolicy
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
from django.core.cache import cache
|
||||
from django.test import TestCase
|
||||
|
||||
from passbook.core.models import DebugPolicy, Policy, User
|
||||
from passbook.core.models import Policy, User
|
||||
from passbook.policies.dummy.models import DummyPolicy
|
||||
from passbook.policies.engine import PolicyEngine
|
||||
|
||||
|
||||
|
@ -12,13 +13,13 @@ class PolicyTestEngine(TestCase):
|
|||
def setUp(self):
|
||||
cache.clear()
|
||||
self.user = User.objects.create_user(username="policyuser")
|
||||
self.policy_false = DebugPolicy.objects.create(
|
||||
self.policy_false = DummyPolicy.objects.create(
|
||||
result=False, wait_min=0, wait_max=1
|
||||
)
|
||||
self.policy_true = DebugPolicy.objects.create(
|
||||
self.policy_true = DummyPolicy.objects.create(
|
||||
result=True, wait_min=0, wait_max=1
|
||||
)
|
||||
self.policy_negate = DebugPolicy.objects.create(
|
||||
self.policy_negate = DummyPolicy.objects.create(
|
||||
negate=True, result=True, wait_min=0, wait_max=1
|
||||
)
|
||||
self.policy_raises = Policy.objects.create(name="raises")
|
||||
|
@ -31,13 +32,13 @@ class PolicyTestEngine(TestCase):
|
|||
def test_engine(self):
|
||||
"""Ensure all policies passes (Mix of false and true -> false)"""
|
||||
engine = PolicyEngine(
|
||||
DebugPolicy.objects.filter(negate__exact=False), self.user
|
||||
DummyPolicy.objects.filter(negate__exact=False), self.user
|
||||
)
|
||||
self.assertEqual(engine.build().passing, False)
|
||||
|
||||
def test_engine_negate(self):
|
||||
"""Test negate flag"""
|
||||
engine = PolicyEngine(DebugPolicy.objects.filter(negate__exact=True), self.user)
|
||||
engine = PolicyEngine(DummyPolicy.objects.filter(negate__exact=True), self.user)
|
||||
self.assertEqual(engine.build().passing, False)
|
||||
|
||||
def test_engine_policy_error(self):
|
||||
|
@ -48,7 +49,7 @@ class PolicyTestEngine(TestCase):
|
|||
def test_engine_cache(self):
|
||||
"""Ensure empty policy list passes"""
|
||||
engine = PolicyEngine(
|
||||
DebugPolicy.objects.filter(negate__exact=False), self.user
|
||||
DummyPolicy.objects.filter(negate__exact=False), self.user
|
||||
)
|
||||
self.assertEqual(len(cache.keys("policy_*")), 0)
|
||||
self.assertEqual(engine.build().passing, False)
|
||||
|
|
|
@ -101,7 +101,6 @@ INSTALLED_APPS = [
|
|||
"passbook.stages.otp.apps.PassbookStageOTPConfig",
|
||||
"passbook.stages.captcha.apps.PassbookStageCaptchaConfig",
|
||||
"passbook.stages.password.apps.PassbookStagePasswordConfig",
|
||||
"passbook.stages.dummy.apps.PassbookStageDummyConfig",
|
||||
"passbook.stages.email.apps.PassbookStageEmailConfig",
|
||||
"passbook.policies.expiry.apps.PassbookPolicyExpiryConfig",
|
||||
"passbook.policies.reputation.apps.PassbookPolicyReputationConfig",
|
||||
|
@ -391,4 +390,10 @@ if DEBUG:
|
|||
INSTALLED_APPS.append("debug_toolbar")
|
||||
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
|
||||
|
||||
# Load Dummy/Debug objects
|
||||
INSTALLED_APPS += [
|
||||
"passbook.stages.dummy.apps.PassbookStageDummyConfig",
|
||||
"passbook.policies.dummy.apps.PassbookPolicyDummyConfig",
|
||||
]
|
||||
|
||||
INSTALLED_APPS.append("passbook.core.apps.PassbookCoreConfig")
|
||||
|
|
Reference in New Issue