flows/*: Initial flows stage1 implementation
This commit is contained in:
parent
179f0097c0
commit
8de66b27ad
|
@ -0,0 +1,11 @@
|
||||||
|
"""passbook flows app config"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PassbookFlowsConfig(AppConfig):
|
||||||
|
"""passbook flows app config"""
|
||||||
|
|
||||||
|
name = "passbook.flows"
|
||||||
|
label = "passbook_flows"
|
||||||
|
mountpoint = "flows/"
|
||||||
|
verbose_name = "passbook Flows"
|
|
@ -0,0 +1,108 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-07 18:35
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_policies", "0001_initial"),
|
||||||
|
("passbook_core", "0011_auto_20200222_1822"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Flow",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4,
|
||||||
|
editable=False,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField()),
|
||||||
|
("slug", models.SlugField(unique=True)),
|
||||||
|
(
|
||||||
|
"designation",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("AUTHENTICATION", "authentication"),
|
||||||
|
("ENROLLMENT", "enrollment"),
|
||||||
|
("RECOVERY", "recovery"),
|
||||||
|
],
|
||||||
|
max_length=100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"pbm",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
related_name="+",
|
||||||
|
to="passbook_policies.PolicyBindingModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"verbose_name": "Flow", "verbose_name_plural": "Flows",},
|
||||||
|
bases=("passbook_policies.policybindingmodel", models.Model),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="FlowFactorBinding",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"policybindingmodel_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
to="passbook_policies.PolicyBindingModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4,
|
||||||
|
editable=False,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("order", models.IntegerField()),
|
||||||
|
(
|
||||||
|
"factor",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to="passbook_core.Factor",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to="passbook_flows.Flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Flow Factor Binding",
|
||||||
|
"verbose_name_plural": "Flow Factor Bindings",
|
||||||
|
"unique_together": {("flow", "factor", "order")},
|
||||||
|
},
|
||||||
|
bases=("passbook_policies.policybindingmodel", models.Model),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="flow",
|
||||||
|
name="factors",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
through="passbook_flows.FlowFactorBinding", to="passbook_core.Factor"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,71 @@
|
||||||
|
"""Flow models"""
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from passbook.core.models import Factor
|
||||||
|
from passbook.lib.models import UUIDModel
|
||||||
|
from passbook.policies.models import PolicyBindingModel
|
||||||
|
|
||||||
|
|
||||||
|
class FlowDesignation(Enum):
|
||||||
|
"""Designation of what a Flow should be used for. At a later point, this
|
||||||
|
should be replaced by a database entry."""
|
||||||
|
|
||||||
|
AUTHENTICATION = "authentication"
|
||||||
|
ENROLLMENT = "enrollment"
|
||||||
|
RECOVERY = "recovery"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def as_choices() -> Tuple[Tuple[str, str]]:
|
||||||
|
"""Generate choices of actions used for database"""
|
||||||
|
return tuple(
|
||||||
|
(x, y.value) for x, y in getattr(FlowDesignation, "__members__").items()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Flow(PolicyBindingModel, UUIDModel):
|
||||||
|
"""Flow describes how a series of Factors should be executed to authenticate/enroll/recover
|
||||||
|
a user. Additionally, policies can be applied, to specify which users
|
||||||
|
have access to this flow."""
|
||||||
|
|
||||||
|
name = models.TextField()
|
||||||
|
slug = models.SlugField(unique=True)
|
||||||
|
|
||||||
|
designation = models.CharField(max_length=100, choices=FlowDesignation.as_choices())
|
||||||
|
|
||||||
|
factors = models.ManyToManyField(Factor, through="FlowFactorBinding")
|
||||||
|
|
||||||
|
pbm = models.OneToOneField(
|
||||||
|
PolicyBindingModel, parent_link=True, on_delete=models.CASCADE, related_name="+"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"Flow {self.name} ({self.slug})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("Flow")
|
||||||
|
verbose_name_plural = _("Flows")
|
||||||
|
|
||||||
|
|
||||||
|
class FlowFactorBinding(PolicyBindingModel, UUIDModel):
|
||||||
|
"""Relationship between Flow and Factor. Order is required and unique for
|
||||||
|
each flow-factor Binding. Additionally, policies can be specified, which determine if
|
||||||
|
this Binding applies to the current user"""
|
||||||
|
|
||||||
|
flow = models.ForeignKey("Flow", on_delete=models.CASCADE)
|
||||||
|
factor = models.ForeignKey(Factor, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
order = models.IntegerField()
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"Flow Factor Binding {self.flow} -> {self.factor}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("Flow Factor Binding")
|
||||||
|
verbose_name_plural = _("Flow Factor Bindings")
|
||||||
|
unique_together = (("flow", "factor", "order"),)
|
|
@ -0,0 +1,2 @@
|
||||||
|
"""flow urls"""
|
||||||
|
urlpatterns = []
|
|
@ -0,0 +1,10 @@
|
||||||
|
"""passbook policies app config"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PassbookPoliciesConfig(AppConfig):
|
||||||
|
"""passbook policies app config"""
|
||||||
|
|
||||||
|
name = "passbook.policies"
|
||||||
|
label = "passbook_policies"
|
||||||
|
verbose_name = "passbook Policies"
|
|
@ -0,0 +1,77 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-07 18:35
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0011_auto_20200222_1822"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="PolicyBinding",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4,
|
||||||
|
editable=False,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("enabled", models.BooleanField(default=True)),
|
||||||
|
("order", models.IntegerField(default=0)),
|
||||||
|
(
|
||||||
|
"policy",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="+",
|
||||||
|
to="passbook_core.Policy",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Policy Binding",
|
||||||
|
"verbose_name_plural": "Policy Bindings",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="PolicyBindingModel",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"policies",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="_policybindingmodel_policies_+",
|
||||||
|
through="passbook_policies.PolicyBinding",
|
||||||
|
to="passbook_core.Policy",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="policybinding",
|
||||||
|
name="target",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="+",
|
||||||
|
to="passbook_policies.PolicyBindingModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,31 @@
|
||||||
|
"""Policy base models"""
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from passbook.core.models import Policy
|
||||||
|
from passbook.lib.models import UUIDModel
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingModel(models.Model):
|
||||||
|
"""Base Model for objects which have Policies applied to them"""
|
||||||
|
|
||||||
|
policies = models.ManyToManyField(Policy, through="PolicyBinding", related_name="+")
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBinding(UUIDModel):
|
||||||
|
"""Relationship between a Policy and a PolicyBindingModel."""
|
||||||
|
|
||||||
|
enabled = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
policy = models.ForeignKey(Policy, on_delete=models.CASCADE, related_name="+")
|
||||||
|
target = models.ForeignKey(
|
||||||
|
PolicyBindingModel, on_delete=models.CASCADE, related_name="+"
|
||||||
|
)
|
||||||
|
|
||||||
|
# default value and non-unique for compatibility
|
||||||
|
order = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("Policy Binding")
|
||||||
|
verbose_name_plural = _("Policy Bindings")
|
|
@ -83,6 +83,8 @@ INSTALLED_APPS = [
|
||||||
"passbook.admin.apps.PassbookAdminConfig",
|
"passbook.admin.apps.PassbookAdminConfig",
|
||||||
"passbook.api.apps.PassbookAPIConfig",
|
"passbook.api.apps.PassbookAPIConfig",
|
||||||
"passbook.lib.apps.PassbookLibConfig",
|
"passbook.lib.apps.PassbookLibConfig",
|
||||||
|
"passbook.flows.apps.PassbookFlowsConfig",
|
||||||
|
"passbook.policies.apps.PassbookPoliciesConfig",
|
||||||
"passbook.audit.apps.PassbookAuditConfig",
|
"passbook.audit.apps.PassbookAuditConfig",
|
||||||
"passbook.crypto.apps.PassbookCryptoConfig",
|
"passbook.crypto.apps.PassbookCryptoConfig",
|
||||||
"passbook.recovery.apps.PassbookRecoveryConfig",
|
"passbook.recovery.apps.PassbookRecoveryConfig",
|
||||||
|
|
|
@ -30,7 +30,11 @@ for _passbook_app in get_apps():
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
urlpatterns.append(_path)
|
urlpatterns.append(_path)
|
||||||
LOGGER.debug("Mounted URLs", app_name=_passbook_app.name)
|
LOGGER.debug(
|
||||||
|
"Mounted URLs",
|
||||||
|
app_name=_passbook_app.name,
|
||||||
|
mountpoint=_passbook_app.mountpoint,
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
# Administration
|
# Administration
|
||||||
|
|
Reference in New Issue