Merge pull request #9 from BeryJu/db-reset

DB Reset
This commit is contained in:
Jens L 2020-05-16 18:20:03 +02:00 committed by GitHub
commit 5596caedbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 295 additions and 217 deletions

View File

@ -5,8 +5,9 @@ from django.views.generic import TemplateView
from passbook import __version__ from passbook import __version__
from passbook.admin.mixins import AdminRequiredMixin from passbook.admin.mixins import AdminRequiredMixin
from passbook.core.models import Application, Policy, Provider, Source, User from passbook.core.models import Application, Provider, Source, User
from passbook.flows.models import Flow, Stage from passbook.flows.models import Flow, Stage
from passbook.policies.models import Policy
from passbook.root.celery import CELERY_APP from passbook.root.celery import CELERY_APP
from passbook.stages.invitation.models import Invitation from passbook.stages.invitation.models import Invitation

View File

@ -13,10 +13,10 @@ from django.views.generic.detail import DetailView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
from passbook.admin.forms.policies import PolicyTestForm from passbook.admin.forms.policies import PolicyTestForm
from passbook.core.models import Policy
from passbook.lib.utils.reflection import all_subclasses, path_to_class from passbook.lib.utils.reflection import all_subclasses, path_to_class
from passbook.lib.views import CreateAssignPermView from passbook.lib.views import CreateAssignPermView
from passbook.policies.engine import PolicyEngine from passbook.policies.engine import PolicyEngine
from passbook.policies.models import Policy
class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView): class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView):

View File

@ -16,7 +16,7 @@ from guardian.mixins import (
) )
from passbook.admin.forms.users import UserForm from passbook.admin.forms.users import UserForm
from passbook.core.models import Nonce, User from passbook.core.models import Token, User
from passbook.lib.views import CreateAssignPermView from passbook.lib.views import CreateAssignPermView
@ -92,12 +92,12 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
permission_required = "passbook_core.reset_user_password" permission_required = "passbook_core.reset_user_password"
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
"""Create nonce for user and return link""" """Create token for user and return link"""
super().get(request, *args, **kwargs) super().get(request, *args, **kwargs)
# TODO: create plan for user, get token # TODO: create plan for user, get token
nonce = Nonce.objects.create(user=self.object) token = Token.objects.create(user=self.object)
link = request.build_absolute_uri( link = request.build_absolute_uri(
reverse("passbook_flows:default-recovery", kwargs={"nonce": nonce.uuid}) reverse("passbook_flows:default-recovery", kwargs={"token": token.uuid})
) )
messages.success( messages.success(
request, _("Password reset link: <pre>%(link)s</pre>" % {"link": link}) request, _("Password reset link: <pre>%(link)s</pre>" % {"link": link})

View File

@ -1,8 +1,8 @@
"""permission classes for django restframework""" """permission classes for django restframework"""
from rest_framework.permissions import BasePermission, DjangoObjectPermissions from rest_framework.permissions import BasePermission, DjangoObjectPermissions
from passbook.core.models import PolicyModel
from passbook.policies.engine import PolicyEngine from passbook.policies.engine import PolicyEngine
from passbook.policies.models import PolicyBindingModel
class CustomObjectPermissions(DjangoObjectPermissions): class CustomObjectPermissions(DjangoObjectPermissions):
@ -24,8 +24,7 @@ class PolicyPermissions(BasePermission):
policy_engine: PolicyEngine policy_engine: PolicyEngine
def has_object_permission(self, request, view, obj: PolicyModel) -> bool: def has_object_permission(self, request, view, obj: PolicyBindingModel) -> bool:
# if not obj.po
self.policy_engine = PolicyEngine(obj.policies, request.user, request) self.policy_engine = PolicyEngine(obj.policies, request.user, request)
self.policy_engine.request.obj = obj self.policy_engine.request.obj = obj
return self.policy_engine.build().passing return self.policy_engine.build().passing

View File

@ -1,5 +1,4 @@
"""api v2 urls""" """api v2 urls"""
from django.conf import settings
from django.conf.urls import url from django.conf.urls import url
from django.urls import path from django.urls import path
from drf_yasg import openapi from drf_yasg import openapi
@ -19,6 +18,7 @@ from passbook.core.api.users import UserViewSet
from passbook.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet from passbook.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet
from passbook.lib.utils.reflection import get_apps from passbook.lib.utils.reflection import get_apps
from passbook.policies.api import PolicyBindingViewSet from passbook.policies.api import PolicyBindingViewSet
from passbook.policies.dummy.api import DummyPolicyViewSet
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
from passbook.policies.expression.api import ExpressionPolicyViewSet from passbook.policies.expression.api import ExpressionPolicyViewSet
from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet
@ -31,6 +31,7 @@ from passbook.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProvider
from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
from passbook.sources.oauth.api import OAuthSourceViewSet from passbook.sources.oauth.api import OAuthSourceViewSet
from passbook.stages.captcha.api import CaptchaStageViewSet from passbook.stages.captcha.api import CaptchaStageViewSet
from passbook.stages.dummy.api import DummyStageViewSet
from passbook.stages.email.api import EmailStageViewSet from passbook.stages.email.api import EmailStageViewSet
from passbook.stages.identification.api import IdentificationStageViewSet from passbook.stages.identification.api import IdentificationStageViewSet
from passbook.stages.invitation.api import InvitationStageViewSet, InvitationViewSet from passbook.stages.invitation.api import InvitationStageViewSet, InvitationViewSet
@ -97,10 +98,6 @@ router.register("stages/user_write", UserWriteStageViewSet)
router.register("flows/instances", FlowViewSet) router.register("flows/instances", FlowViewSet)
router.register("flows/bindings", FlowStageBindingViewSet) 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("stages/dummy", DummyStageViewSet)
router.register("policies/dummy", DummyPolicyViewSet) router.register("policies/dummy", DummyPolicyViewSet)

View File

@ -5,7 +5,7 @@ from django.test import TestCase
from guardian.shortcuts import get_anonymous_user from guardian.shortcuts import get_anonymous_user
from passbook.audit.models import Event, EventAction from passbook.audit.models import Event, EventAction
from passbook.core.models import Policy from passbook.policies.dummy.models import DummyPolicy
class TestAuditEvent(TestCase): class TestAuditEvent(TestCase):
@ -23,7 +23,7 @@ class TestAuditEvent(TestCase):
def test_new_with_uuid_model(self): def test_new_with_uuid_model(self):
"""Create a new Event passing a model (with UUID PK) as kwarg""" """Create a new Event passing a model (with UUID PK) as kwarg"""
temp_model = Policy.objects.create() temp_model = DummyPolicy.objects.create(name="test", result=True)
event = Event.new(EventAction.CUSTOM, model=temp_model) event = Event.new(EventAction.CUSTOM, model=temp_model)
event.save() # We save to ensure nothing is un-saveable event.save() # We save to ensure nothing is un-saveable
model_content_type = ContentType.objects.get_for_model(temp_model) model_content_type = ContentType.objects.get_for_model(temp_model)

View File

@ -2,8 +2,8 @@
from rest_framework.serializers import ModelSerializer, SerializerMethodField from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.viewsets import ReadOnlyModelViewSet from rest_framework.viewsets import ReadOnlyModelViewSet
from passbook.core.models import Policy
from passbook.policies.forms import GENERAL_FIELDS from passbook.policies.forms import GENERAL_FIELDS
from passbook.policies.models import Policy
class PolicySerializer(ModelSerializer): class PolicySerializer(ModelSerializer):

View File

@ -19,6 +19,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
("auth", "0011_update_proxy_permissions"), ("auth", "0011_update_proxy_permissions"),
("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -158,7 +159,7 @@ class Migration(migrations.Migration):
), ),
( (
"policies", "policies",
models.ManyToManyField(blank=True, to="passbook_core.Policy"), models.ManyToManyField(blank=True, to="passbook_policies.Policy"),
), ),
], ],
options={"abstract": False,}, options={"abstract": False,},
@ -182,30 +183,6 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Property Mappings", "verbose_name_plural": "Property Mappings",
}, },
), ),
migrations.CreateModel(
name="DebugPolicy",
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": "Debug Policy",
"verbose_name_plural": "Debug Policies",
},
bases=("passbook_core.policy",),
),
migrations.CreateModel( migrations.CreateModel(
name="Factor", name="Factor",
fields=[ fields=[
@ -217,7 +194,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.PolicyModel", to="passbook_policies.PolicyBindingModel",
), ),
), ),
("name", models.TextField()), ("name", models.TextField()),
@ -226,7 +203,7 @@ class Migration(migrations.Migration):
("enabled", models.BooleanField(default=True)), ("enabled", models.BooleanField(default=True)),
], ],
options={"abstract": False,}, options={"abstract": False,},
bases=("passbook_core.policymodel",), bases=("passbook_policies.policybindingmodel",),
), ),
migrations.CreateModel( migrations.CreateModel(
name="Source", name="Source",
@ -239,7 +216,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.PolicyModel", to="passbook_policies.PolicyBindingModel",
), ),
), ),
("name", models.TextField()), ("name", models.TextField()),
@ -247,7 +224,7 @@ class Migration(migrations.Migration):
("enabled", models.BooleanField(default=True)), ("enabled", models.BooleanField(default=True)),
], ],
options={"abstract": False,}, options={"abstract": False,},
bases=("passbook_core.policymodel",), bases=("passbook_policies.policybindingmodel",),
), ),
migrations.CreateModel( migrations.CreateModel(
name="Provider", name="Provider",
@ -284,7 +261,7 @@ class Migration(migrations.Migration):
( (
"expires", "expires",
models.DateTimeField( models.DateTimeField(
default=passbook.core.models.default_nonce_duration default=passbook.core.models.default_token_duration
), ),
), ),
("expiring", models.BooleanField(default=True)), ("expiring", models.BooleanField(default=True)),
@ -418,7 +395,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.PolicyModel", to="passbook_policies.PolicyBindingModel",
), ),
), ),
("name", models.TextField()), ("name", models.TextField()),
@ -438,7 +415,7 @@ class Migration(migrations.Migration):
), ),
], ],
options={"abstract": False,}, options={"abstract": False,},
bases=("passbook_core.policymodel",), bases=("passbook_policies.policybindingmodel",),
), ),
migrations.AddField( migrations.AddField(
model_name="user", model_name="user",

View File

@ -6,11 +6,7 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_policies", "0003_auto_20200508_1642"),
("passbook_stages_password", "0001_initial"),
("passbook_core", "0012_delete_factor"), ("passbook_core", "0012_delete_factor"),
] ]
operations = [ operations = []
migrations.DeleteModel(name="DebugPolicy",),
]

View File

@ -0,0 +1,52 @@
# Generated by Django 3.0.5 on 2020-05-16 14:07
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import passbook.core.models
class Migration(migrations.Migration):
dependencies = [
("passbook_core", "0014_delete_invitation"),
]
operations = [
migrations.CreateModel(
name="Token",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"expires",
models.DateTimeField(
default=passbook.core.models.default_token_duration
),
),
("expiring", models.BooleanField(default=True)),
("description", models.TextField(blank=True, default="")),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
options={"verbose_name": "Token", "verbose_name_plural": "Tokens",},
bases=(models.Model,),
),
migrations.DeleteModel(name="Nonce",),
]

View File

@ -0,0 +1,48 @@
# Generated by Django 3.0.5 on 2020-05-16 14:46
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("passbook_policies", "__first__"),
("passbook_core", "0015_auto_20200516_1407"),
]
operations = [
migrations.RemoveField(model_name="policymodel", name="policies",),
migrations.RemoveField(model_name="application", name="policymodel_ptr",),
migrations.RemoveField(model_name="source", name="policymodel_ptr",),
migrations.AddField(
model_name="application",
name="policybindingmodel_ptr",
field=models.OneToOneField(
auto_created=True,
default=None,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="passbook_policies.PolicyBindingModel",
),
preserve_default=False,
),
migrations.AddField(
model_name="source",
name="policybindingmodel_ptr",
field=models.OneToOneField(
auto_created=True,
default=None,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="passbook_policies.PolicyBindingModel",
),
preserve_default=False,
),
migrations.DeleteModel(name="Policy",),
migrations.DeleteModel(name="PolicyModel",),
]

View File

@ -22,15 +22,14 @@ from passbook.core.exceptions import PropertyMappingExpressionException
from passbook.core.signals import password_changed from passbook.core.signals import password_changed
from passbook.core.types import UILoginButton, UIUserSettings from passbook.core.types import UILoginButton, UIUserSettings
from passbook.lib.models import CreatedUpdatedModel, UUIDModel from passbook.lib.models import CreatedUpdatedModel, UUIDModel
from passbook.policies.exceptions import PolicyException from passbook.policies.models import PolicyBindingModel
from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()
NATIVE_ENVIRONMENT = NativeEnvironment() NATIVE_ENVIRONMENT = NativeEnvironment()
def default_nonce_duration(): def default_token_duration():
"""Default duration a Nonce is valid""" """Default duration a Token is valid"""
return now() + timedelta(minutes=30) return now() + timedelta(minutes=30)
@ -94,13 +93,7 @@ class Provider(ExportModelOperationsMixin("provider"), models.Model):
return super().__str__() return super().__str__()
class PolicyModel(UUIDModel, CreatedUpdatedModel): class Application(ExportModelOperationsMixin("application"), PolicyBindingModel):
"""Base model which can have policies applied to it"""
policies = models.ManyToManyField("Policy", blank=True)
class Application(ExportModelOperationsMixin("application"), PolicyModel):
"""Every Application which uses passbook for authentication/identification/authorization """Every Application which uses passbook for authentication/identification/authorization
needs an Application record. Other authentication types can subclass this Model to needs an Application record. Other authentication types can subclass this Model to
add custom fields and other properties""" add custom fields and other properties"""
@ -129,7 +122,7 @@ class Application(ExportModelOperationsMixin("application"), PolicyModel):
return self.name return self.name
class Source(ExportModelOperationsMixin("source"), PolicyModel): class Source(ExportModelOperationsMixin("source"), PolicyBindingModel):
"""Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server""" """Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server"""
name = models.TextField(help_text=_("Source's display Name.")) name = models.TextField(help_text=_("Source's display Name."))
@ -176,45 +169,26 @@ class UserSourceConnection(CreatedUpdatedModel):
unique_together = (("user", "source"),) unique_together = (("user", "source"),)
class Policy(ExportModelOperationsMixin("policy"), UUIDModel, CreatedUpdatedModel): class Token(ExportModelOperationsMixin("token"), UUIDModel):
"""Policies which specify if a user is authorized to use an Application. Can be overridden by
other types to add other fields, more logic, etc."""
name = models.TextField(blank=True, null=True)
negate = models.BooleanField(default=False)
order = models.IntegerField(default=0)
timeout = models.IntegerField(default=30)
objects = InheritanceManager()
def __str__(self):
return f"Policy {self.name}"
def passes(self, request: PolicyRequest) -> PolicyResult:
"""Check if user instance passes this policy"""
raise PolicyException()
class Nonce(ExportModelOperationsMixin("nonce"), UUIDModel):
"""One-time link for password resets/sign-up-confirmations""" """One-time link for password resets/sign-up-confirmations"""
expires = models.DateTimeField(default=default_nonce_duration) expires = models.DateTimeField(default=default_token_duration)
user = models.ForeignKey("User", on_delete=models.CASCADE) user = models.ForeignKey("User", on_delete=models.CASCADE, related_name="+")
expiring = models.BooleanField(default=True) expiring = models.BooleanField(default=True)
description = models.TextField(default="", blank=True) description = models.TextField(default="", blank=True)
@property @property
def is_expired(self) -> bool: def is_expired(self) -> bool:
"""Check if nonce is expired yet.""" """Check if token is expired yet."""
return now() > self.expires return now() > self.expires
def __str__(self): def __str__(self):
return f"Nonce f{self.uuid.hex} {self.description} (expires={self.expires})" return f"Token f{self.uuid.hex} {self.description} (expires={self.expires})"
class Meta: class Meta:
verbose_name = _("Nonce") verbose_name = _("Token")
verbose_name_plural = _("Nonces") verbose_name_plural = _("Tokens")
class PropertyMapping(UUIDModel): class PropertyMapping(UUIDModel):

View File

@ -17,7 +17,7 @@ password_changed = Signal(providing_args=["user", "password"])
# pylint: disable=unused-argument # pylint: disable=unused-argument
def invalidate_policy_cache(sender, instance, **_): def invalidate_policy_cache(sender, instance, **_):
"""Invalidate Policy cache when policy is updated""" """Invalidate Policy cache when policy is updated"""
from passbook.core.models import Policy from passbook.policies.models import Policy
from passbook.policies.process import cache_key from passbook.policies.process import cache_key
if isinstance(instance, Policy): if isinstance(instance, Policy):

View File

@ -2,14 +2,14 @@
from django.utils.timezone import now from django.utils.timezone import now
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Nonce from passbook.core.models import Token
from passbook.root.celery import CELERY_APP from passbook.root.celery import CELERY_APP
LOGGER = get_logger() LOGGER = get_logger()
@CELERY_APP.task() @CELERY_APP.task()
def clean_nonces(): def clean_tokens():
"""Remove expired nonces""" """Remove expired tokens"""
amount, _ = Nonce.objects.filter(expires__lt=now(), expiring=True).delete() amount, _ = Token.objects.filter(expires__lt=now(), expiring=True).delete()
LOGGER.debug("Deleted expired nonces", amount=amount) LOGGER.debug("Deleted expired tokens", amount=amount)

View File

@ -11,7 +11,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_policies", "0003_auto_20200508_1642"), # ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [

View File

@ -9,8 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_policies", "0003_auto_20200508_1642"), ("passbook_policies", "0001_initial"),
("passbook_core", "0013_delete_debugpolicy"),
] ]
operations = [ operations = [
@ -25,7 +24,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("result", models.BooleanField(default=False)), ("result", models.BooleanField(default=False)),
@ -36,6 +35,6 @@ class Migration(migrations.Migration):
"verbose_name": "Dummy Policy", "verbose_name": "Dummy Policy",
"verbose_name_plural": "Dummy Policies", "verbose_name_plural": "Dummy Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
] ]

View File

@ -6,7 +6,7 @@ from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()

View File

@ -7,7 +7,8 @@ from django.core.cache import cache
from django.http import HttpRequest from django.http import HttpRequest
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy, User from passbook.core.models import User
from passbook.policies.models import Policy
from passbook.policies.process import PolicyProcess, cache_key from passbook.policies.process import PolicyProcess, cache_key
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult

View File

@ -9,7 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_core", "0001_initial"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("deny_only", models.BooleanField(default=False)), ("deny_only", models.BooleanField(default=False)),
@ -34,6 +34,6 @@ class Migration(migrations.Migration):
"verbose_name": "Password Expiry Policy", "verbose_name": "Password Expiry Policy",
"verbose_name_plural": "Password Expiry Policies", "verbose_name_plural": "Password Expiry Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
] ]

View File

@ -6,7 +6,7 @@ from django.utils.timezone import now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()

View File

@ -9,7 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_core", "0007_auto_20200217_1934"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("expression", models.TextField()), ("expression", models.TextField()),
@ -33,6 +33,6 @@ class Migration(migrations.Migration):
"verbose_name": "Expression Policy", "verbose_name": "Expression Policy",
"verbose_name_plural": "Expression Policies", "verbose_name_plural": "Expression Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
] ]

View File

@ -2,8 +2,8 @@
from django.db import models from django.db import models
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from passbook.core.models import Policy
from passbook.policies.expression.evaluator import Evaluator from passbook.policies.expression.evaluator import Evaluator
from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult

View File

@ -9,7 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_core", "0001_initial"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("allowed_count", models.IntegerField(default=0)), ("allowed_count", models.IntegerField(default=0)),
@ -33,6 +33,6 @@ class Migration(migrations.Migration):
"verbose_name": "Have I Been Pwned Policy", "verbose_name": "Have I Been Pwned Policy",
"verbose_name_plural": "Have I Been Pwned Policies", "verbose_name_plural": "Have I Been Pwned Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
] ]

View File

@ -6,7 +6,8 @@ from django.utils.translation import gettext as _
from requests import get from requests import get
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy, PolicyResult, User from passbook.core.models import User
from passbook.policies.models import Policy, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()

View File

@ -10,11 +10,28 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [
("passbook_core", "0011_auto_20200222_1822"),
]
operations = [ operations = [
migrations.CreateModel(
name="Policy",
fields=[
("created", models.DateTimeField(auto_now_add=True)),
("last_updated", models.DateTimeField(auto_now=True)),
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.TextField(blank=True, null=True)),
("negate", models.BooleanField(default=False)),
("order", models.IntegerField(default=0)),
("timeout", models.IntegerField(default=30)),
],
options={"abstract": False,},
),
migrations.CreateModel( migrations.CreateModel(
name="PolicyBinding", name="PolicyBinding",
fields=[ fields=[
@ -34,7 +51,7 @@ class Migration(migrations.Migration):
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="+", related_name="+",
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
], ],
@ -60,7 +77,7 @@ class Migration(migrations.Migration):
models.ManyToManyField( models.ManyToManyField(
related_name="_policybindingmodel_policies_+", related_name="_policybindingmodel_policies_+",
through="passbook_policies.PolicyBinding", through="passbook_policies.PolicyBinding",
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
], ],

View File

@ -1,4 +1,4 @@
# Generated by Django 3.0.3 on 2020-05-08 16:42 # Generated by Django 3.0.5 on 2020-05-16 15:16
from django.db import migrations, models from django.db import migrations, models
@ -6,7 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_core", "0011_auto_20200222_1822"),
("passbook_policies", "0002_auto_20200508_1230"), ("passbook_policies", "0002_auto_20200508_1230"),
] ]
@ -18,7 +17,7 @@ class Migration(migrations.Migration):
blank=True, blank=True,
related_name="_policybindingmodel_policies_+", related_name="_policybindingmodel_policies_+",
through="passbook_policies.PolicyBinding", through="passbook_policies.PolicyBinding",
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
] ]

View File

@ -1,16 +1,18 @@
"""Policy base models""" """Policy base models"""
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from model_utils.managers import InheritanceManager
from passbook.core.models import Policy from passbook.lib.models import CreatedUpdatedModel, UUIDModel
from passbook.lib.models import UUIDModel from passbook.policies.exceptions import PolicyException
from passbook.policies.types import PolicyRequest, PolicyResult
class PolicyBindingModel(models.Model): class PolicyBindingModel(models.Model):
"""Base Model for objects that have policies applied to them.""" """Base Model for objects that have policies applied to them."""
policies = models.ManyToManyField( policies = models.ManyToManyField(
Policy, through="PolicyBinding", related_name="+", blank=True "Policy", through="PolicyBinding", related_name="+", blank=True
) )
class Meta: class Meta:
@ -24,7 +26,7 @@ class PolicyBinding(UUIDModel):
enabled = models.BooleanField(default=True) enabled = models.BooleanField(default=True)
policy = models.ForeignKey(Policy, on_delete=models.CASCADE, related_name="+") policy = models.ForeignKey("Policy", on_delete=models.CASCADE, related_name="+")
target = models.ForeignKey( target = models.ForeignKey(
PolicyBindingModel, on_delete=models.CASCADE, related_name="+" PolicyBindingModel, on_delete=models.CASCADE, related_name="+"
) )
@ -39,3 +41,22 @@ class PolicyBinding(UUIDModel):
verbose_name = _("Policy Binding") verbose_name = _("Policy Binding")
verbose_name_plural = _("Policy Bindings") verbose_name_plural = _("Policy Bindings")
class Policy(UUIDModel, CreatedUpdatedModel):
"""Policies which specify if a user is authorized to use an Application. Can be overridden by
other types to add other fields, more logic, etc."""
name = models.TextField(blank=True, null=True)
negate = models.BooleanField(default=False)
order = models.IntegerField(default=0)
timeout = models.IntegerField(default=30)
objects = InheritanceManager()
def __str__(self):
return f"Policy {self.name}"
def passes(self, request: PolicyRequest) -> PolicyResult:
"""Check if user instance passes this policy"""
raise PolicyException()

View File

@ -9,7 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_core", "0001_initial"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("amount_uppercase", models.IntegerField(default=0)), ("amount_uppercase", models.IntegerField(default=0)),
@ -41,6 +41,6 @@ class Migration(migrations.Migration):
"verbose_name": "Password Policy", "verbose_name": "Password Policy",
"verbose_name_plural": "Password Policies", "verbose_name_plural": "Password Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
] ]

View File

@ -5,7 +5,7 @@ from django.db import models
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()

View File

@ -6,8 +6,9 @@ from typing import Optional
from django.core.cache import cache from django.core.cache import cache
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Policy, User from passbook.core.models import User
from passbook.policies.exceptions import PolicyException from passbook.policies.exceptions import PolicyException
from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()

View File

@ -10,7 +10,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("passbook_core", "0001_initial"), ("passbook_policies", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
@ -43,7 +43,7 @@ class Migration(migrations.Migration):
parent_link=True, parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="passbook_core.Policy", to="passbook_policies.Policy",
), ),
), ),
("check_ip", models.BooleanField(default=True)), ("check_ip", models.BooleanField(default=True)),
@ -54,7 +54,7 @@ class Migration(migrations.Migration):
"verbose_name": "Reputation Policy", "verbose_name": "Reputation Policy",
"verbose_name_plural": "Reputation Policies", "verbose_name_plural": "Reputation Policies",
}, },
bases=("passbook_core.policy",), bases=("passbook_policies.policy",),
), ),
migrations.CreateModel( migrations.CreateModel(
name="UserReputation", name="UserReputation",

View File

@ -2,8 +2,9 @@
from django.db import models from django.db import models
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from passbook.core.models import Policy, User from passbook.core.models import User
from passbook.lib.utils.http import get_client_ip from passbook.lib.utils.http import get_client_ip
from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult from passbook.policies.types import PolicyRequest, PolicyResult

View File

@ -2,9 +2,10 @@
from django.core.cache import cache from django.core.cache import cache
from django.test import TestCase from django.test import TestCase
from passbook.core.models import Policy, User from passbook.core.models import User
from passbook.policies.dummy.models import DummyPolicy from passbook.policies.dummy.models import DummyPolicy
from passbook.policies.engine import PolicyEngine from passbook.policies.engine import PolicyEngine
from passbook.policies.models import Policy
class PolicyTestEngine(TestCase): class PolicyTestEngine(TestCase):

View File

@ -11,6 +11,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_core", "0001_initial"), ("passbook_core", "0001_initial"),
("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -87,7 +88,7 @@ class Migration(migrations.Migration):
), ),
( (
"conditions", "conditions",
models.ManyToManyField(blank=True, to="passbook_core.Policy"), models.ManyToManyField(blank=True, to="passbook_policies.Policy"),
), ),
], ],
options={ options={

View File

@ -8,14 +8,14 @@ from django.utils.timezone import now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Nonce, User from passbook.core.models import Token, User
from passbook.lib.config import CONFIG from passbook.lib.config import CONFIG
LOGGER = get_logger() LOGGER = get_logger()
class Command(BaseCommand): class Command(BaseCommand):
"""Create Nonce used to recover access""" """Create Token used to recover access"""
help = _("Create a Key which can be used to restore access to passbook.") help = _("Create a Key which can be used to restore access to passbook.")
@ -30,22 +30,22 @@ class Command(BaseCommand):
"user", action="store", help="Which user the Token gives access to." "user", action="store", help="Which user the Token gives access to."
) )
def get_url(self, nonce: Nonce) -> str: def get_url(self, token: Token) -> str:
"""Get full recovery link""" """Get full recovery link"""
path = reverse("passbook_recovery:use-nonce", kwargs={"uuid": str(nonce.uuid)}) path = reverse("passbook_recovery:use-token", kwargs={"uuid": str(token.uuid)})
return f"https://{CONFIG.y('domain')}{path}" return f"https://{CONFIG.y('domain')}{path}"
def handle(self, *args, **options): def handle(self, *args, **options):
"""Create Nonce used to recover access""" """Create Token used to recover access"""
duration = int(options.get("duration", 1)) duration = int(options.get("duration", 1))
delta = timedelta(days=duration * 365.2425) delta = timedelta(days=duration * 365.2425)
_now = now() _now = now()
expiry = _now + delta expiry = _now + delta
user = User.objects.get(username=options.get("user")) user = User.objects.get(username=options.get("user"))
nonce = Nonce.objects.create( token = Token.objects.create(
expires=expiry, expires=expiry,
user=user, user=user,
description=f"Recovery Nonce generated by {getuser()} on {_now}", description=f"Recovery Token generated by {getuser()} on {_now}",
) )
self.stdout.write( self.stdout.write(
( (
@ -53,4 +53,4 @@ class Command(BaseCommand):
f" anyone to access passbook as {user}." f" anyone to access passbook as {user}."
) )
) )
self.stdout.write(self.get_url(nonce)) self.stdout.write(self.get_url(token))

View File

@ -5,7 +5,7 @@ from django.core.management import call_command
from django.shortcuts import reverse from django.shortcuts import reverse
from django.test import TestCase from django.test import TestCase
from passbook.core.models import Nonce, User from passbook.core.models import Token, User
from passbook.lib.config import CONFIG from passbook.lib.config import CONFIG
@ -19,17 +19,17 @@ class TestRecovery(TestCase):
"""Test creation of a new key""" """Test creation of a new key"""
CONFIG.update_from_dict({"domain": "testserver"}) CONFIG.update_from_dict({"domain": "testserver"})
out = StringIO() out = StringIO()
self.assertEqual(len(Nonce.objects.all()), 0) self.assertEqual(len(Token.objects.all()), 0)
call_command("create_recovery_key", "1", self.user.username, stdout=out) call_command("create_recovery_key", "1", self.user.username, stdout=out)
self.assertIn("https://testserver/recovery/use-nonce/", out.getvalue()) self.assertIn("https://testserver/recovery/use-token/", out.getvalue())
self.assertEqual(len(Nonce.objects.all()), 1) self.assertEqual(len(Token.objects.all()), 1)
def test_recovery_view(self): def test_recovery_view(self):
"""Test recovery view""" """Test recovery view"""
out = StringIO() out = StringIO()
call_command("create_recovery_key", "1", self.user.username, stdout=out) call_command("create_recovery_key", "1", self.user.username, stdout=out)
nonce = Nonce.objects.first() token = Token.objects.first()
self.client.get( self.client.get(
reverse("passbook_recovery:use-nonce", kwargs={"uuid": str(nonce.uuid)}) reverse("passbook_recovery:use-token", kwargs={"uuid": str(token.uuid)})
) )
self.assertEqual(int(self.client.session["_auth_user_id"]), nonce.user.pk) self.assertEqual(int(self.client.session["_auth_user_id"]), token.user.pk)

View File

@ -2,8 +2,8 @@
from django.urls import path from django.urls import path
from passbook.recovery.views import UseNonceView from passbook.recovery.views import UseTokenView
urlpatterns = [ urlpatterns = [
path("use-nonce/<uuid:uuid>/", UseNonceView.as_view(), name="use-nonce"), path("use-token/<uuid:uuid>/", UseTokenView.as_view(), name="use-token"),
] ]

View File

@ -6,19 +6,19 @@ from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views import View from django.views import View
from passbook.core.models import Nonce from passbook.core.models import Token
class UseNonceView(View): class UseTokenView(View):
"""Use nonce to login""" """Use token to login"""
def get(self, request: HttpRequest, uuid: str) -> HttpResponse: def get(self, request: HttpRequest, uuid: str) -> HttpResponse:
"""Check if nonce exists, log user in and delete nonce.""" """Check if token exists, log user in and delete token."""
nonce: Nonce = get_object_or_404(Nonce, pk=uuid) token: Token = get_object_or_404(Token, pk=uuid)
if nonce.is_expired: if token.is_expired:
nonce.delete() token.delete()
raise Http404 raise Http404
login(request, nonce.user, backend="django.contrib.auth.backends.ModelBackend") login(request, token.user, backend="django.contrib.auth.backends.ModelBackend")
nonce.delete() token.delete()
messages.warning(request, _("Used recovery-link to authenticate.")) messages.warning(request, _("Used recovery-link to authenticate."))
return redirect("passbook_core:overview") return redirect("passbook_core:overview")

View File

@ -228,8 +228,8 @@ USE_TZ = True
# Add a 10 minute timeout to all Celery tasks. # Add a 10 minute timeout to all Celery tasks.
CELERY_TASK_SOFT_TIME_LIMIT = 600 CELERY_TASK_SOFT_TIME_LIMIT = 600
CELERY_BEAT_SCHEDULE = { CELERY_BEAT_SCHEDULE = {
"clean_nonces": { "clean_tokens": {
"task": "passbook.core.tasks.clean_nonces", "task": "passbook.core.tasks.clean_tokens",
"schedule": crontab(minute="*/5"), # Run every 5 minutes "schedule": crontab(minute="*/5"), # Run every 5 minutes
} }
} }

View File

@ -10,7 +10,7 @@ from django.utils.translation import gettext as _
from django.views.generic import FormView from django.views.generic import FormView
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Nonce from passbook.core.models import Token
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER
from passbook.flows.stage import AuthenticationStage from passbook.flows.stage import AuthenticationStage
from passbook.stages.email.forms import EmailStageSendForm from passbook.stages.email.forms import EmailStageSendForm
@ -38,9 +38,9 @@ class EmailStageView(FormView, AuthenticationStage):
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
if QS_KEY_TOKEN in request.GET: if QS_KEY_TOKEN in request.GET:
nonce = get_object_or_404(Nonce, pk=request.GET[QS_KEY_TOKEN]) token = get_object_or_404(Token, pk=request.GET[QS_KEY_TOKEN])
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = nonce.user self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = token.user
nonce.delete() token.delete()
messages.success(request, _("Successfully verified E-Mail.")) messages.success(request, _("Successfully verified E-Mail."))
return self.executor.stage_ok() return self.executor.stage_ok()
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
@ -50,16 +50,16 @@ class EmailStageView(FormView, AuthenticationStage):
valid_delta = timedelta( valid_delta = timedelta(
minutes=self.executor.current_stage.token_expiry + 1 minutes=self.executor.current_stage.token_expiry + 1
) # + 1 because django timesince always rounds down ) # + 1 because django timesince always rounds down
nonce = Nonce.objects.create(user=pending_user, expires=now() + valid_delta) token = Token.objects.create(user=pending_user, expires=now() + valid_delta)
# Send mail to user # Send mail to user
message = TemplateEmailMessage( message = TemplateEmailMessage(
subject=_("passbook - Password Recovery"), subject=_("passbook - Password Recovery"),
template_name=self.executor.current_stage.template, template_name=self.executor.current_stage.template,
to=[pending_user.email], to=[pending_user.email],
template_context={ template_context={
"url": self.get_full_url(**{QS_KEY_TOKEN: nonce.pk.hex}), "url": self.get_full_url(**{QS_KEY_TOKEN: token.pk.hex}),
"user": pending_user, "user": pending_user,
"expires": nonce.expires, "expires": token.expires,
}, },
) )
send_mails(self.executor.current_stage, message) send_mails(self.executor.current_stage, message)

View File

@ -5,7 +5,7 @@ from django.core import mail
from django.shortcuts import reverse from django.shortcuts import reverse
from django.test import Client, TestCase from django.test import Client, TestCase
from passbook.core.models import Nonce, User from passbook.core.models import Token, User
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from passbook.flows.views import SESSION_KEY_PLAN from passbook.flows.views import SESSION_KEY_PLAN
@ -77,7 +77,7 @@ class TestEmailStage(TestCase):
url = reverse( url = reverse(
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} "passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
) )
token = Nonce.objects.get(user=self.user) token = Token.objects.get(user=self.user)
url += f"?{QS_KEY_TOKEN}={token.pk.hex}" url += f"?{QS_KEY_TOKEN}={token.pk.hex}"
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)

View File

@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_flows", "0001_initial"), ("passbook_flows", "0001_initial"),
("passbook_core", "0012_delete_factor"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [
@ -39,7 +39,7 @@ class Migration(migrations.Migration):
), ),
( (
"password_policies", "password_policies",
models.ManyToManyField(blank=True, to="passbook_core.Policy"), models.ManyToManyField(blank=True, to="passbook_policies.Policy"),
), ),
], ],
options={ options={

View File

@ -12,7 +12,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_flows", "0005_auto_20200512_1158"), ("passbook_flows", "0005_auto_20200512_1158"),
("passbook_policies", "0003_auto_20200508_1642"), ("passbook_policies", "0001_initial"),
] ]
operations = [ operations = [

View File

@ -154,7 +154,7 @@ paths:
tags: tags:
- core - core
parameters: [] parameters: []
/core/applications/{uuid}/: /core/applications/{id}/:
get: get:
operationId: core_applications_read operationId: core_applications_read
description: Application Viewset description: Application Viewset
@ -208,12 +208,11 @@ paths:
tags: tags:
- core - core
parameters: parameters:
- name: uuid - name: id
in: path in: path
description: A UUID string identifying this application. description: A unique integer value identifying this application.
required: true required: true
type: string type: integer
format: uuid
/core/groups/: /core/groups/:
get: get:
operationId: core_groups_list operationId: core_groups_list
@ -2658,7 +2657,7 @@ paths:
tags: tags:
- sources - sources
parameters: [] parameters: []
/sources/all/{uuid}/: /sources/all/{id}/:
get: get:
operationId: sources_all_read operationId: sources_all_read
description: Source Viewset description: Source Viewset
@ -2671,12 +2670,11 @@ paths:
tags: tags:
- sources - sources
parameters: parameters:
- name: uuid - name: id
in: path in: path
description: A UUID string identifying this source. description: A unique integer value identifying this source.
required: true required: true
type: string type: integer
format: uuid
/sources/ldap/: /sources/ldap/:
get: get:
operationId: sources_ldap_list operationId: sources_ldap_list
@ -2744,7 +2742,7 @@ paths:
tags: tags:
- sources - sources
parameters: [] parameters: []
/sources/ldap/{uuid}/: /sources/ldap/{id}/:
get: get:
operationId: sources_ldap_read operationId: sources_ldap_read
description: LDAP Source Viewset description: LDAP Source Viewset
@ -2798,12 +2796,11 @@ paths:
tags: tags:
- sources - sources
parameters: parameters:
- name: uuid - name: id
in: path in: path
description: A UUID string identifying this LDAP Source. description: A unique integer value identifying this LDAP Source.
required: true required: true
type: string type: integer
format: uuid
/sources/oauth/: /sources/oauth/:
get: get:
operationId: sources_oauth_list operationId: sources_oauth_list
@ -2871,7 +2868,7 @@ paths:
tags: tags:
- sources - sources
parameters: [] parameters: []
/sources/oauth/{uuid}/: /sources/oauth/{id}/:
get: get:
operationId: sources_oauth_read operationId: sources_oauth_read
description: Source Viewset description: Source Viewset
@ -2925,12 +2922,11 @@ paths:
tags: tags:
- sources - sources
parameters: parameters:
- name: uuid - name: id
in: path in: path
description: A UUID string identifying this Generic OAuth Source. description: A unique integer value identifying this Generic OAuth Source.
required: true required: true
type: string type: integer
format: uuid
/stages/all/: /stages/all/:
get: get:
operationId: stages_all_list operationId: stages_all_list
@ -4837,9 +4833,8 @@ definitions:
type: object type: object
properties: properties:
pk: pk:
title: Uuid title: ID
type: string type: integer
format: uuid
readOnly: true readOnly: true
name: name:
title: Name title: Name
@ -4878,8 +4873,8 @@ definitions:
policies: policies:
type: array type: array
items: items:
type: string type: integer
format: uuid readOnly: true
uniqueItems: true uniqueItems: true
Group: Group:
required: required:
@ -5610,9 +5605,8 @@ definitions:
type: object type: object
properties: properties:
pk: pk:
title: Uuid title: ID
type: string type: integer
format: uuid
readOnly: true readOnly: true
name: name:
title: Name title: Name
@ -5647,9 +5641,8 @@ definitions:
type: object type: object
properties: properties:
pk: pk:
title: Uuid title: ID
type: string type: integer
format: uuid
readOnly: true readOnly: true
name: name:
title: Name title: Name
@ -5743,9 +5736,8 @@ definitions:
type: object type: object
properties: properties:
pk: pk:
title: Uuid title: ID
type: string type: integer
format: uuid
readOnly: true readOnly: true
name: name:
title: Name title: Name