Revert "*: providers and sources -> channels, PolicyModel to PolicyBindingModel that uses custom M2M through"
This reverts commit 7ed3ceb960
.
This commit is contained in:
parent
7ed3ceb960
commit
406f69080b
|
@ -1,4 +0,0 @@
|
||||||
"""passbook core inlet form fields"""
|
|
||||||
|
|
||||||
INLET_FORM_FIELDS = ["name", "slug", "enabled"]
|
|
||||||
INLET_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"]
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
"""passbook core source form fields"""
|
||||||
|
|
||||||
|
SOURCE_FORM_FIELDS = ["name", "slug", "enabled"]
|
||||||
|
SOURCE_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"]
|
|
@ -8,12 +8,12 @@ from passbook.admin.views import (
|
||||||
debug,
|
debug,
|
||||||
flows,
|
flows,
|
||||||
groups,
|
groups,
|
||||||
inlets,
|
|
||||||
invitations,
|
invitations,
|
||||||
outlets,
|
|
||||||
overview,
|
overview,
|
||||||
policies,
|
policy,
|
||||||
property_mapping,
|
property_mapping,
|
||||||
|
providers,
|
||||||
|
sources,
|
||||||
stages,
|
stages,
|
||||||
users,
|
users,
|
||||||
)
|
)
|
||||||
|
@ -39,49 +39,51 @@ urlpatterns = [
|
||||||
applications.ApplicationDeleteView.as_view(),
|
applications.ApplicationDeleteView.as_view(),
|
||||||
name="application-delete",
|
name="application-delete",
|
||||||
),
|
),
|
||||||
# Inlets
|
# Sources
|
||||||
path("inlets/", inlets.InletListView.as_view(), name="inlets"),
|
path("sources/", sources.SourceListView.as_view(), name="sources"),
|
||||||
path("inlets/create/", inlets.InletCreateView.as_view(), name="inlet-create"),
|
path("sources/create/", sources.SourceCreateView.as_view(), name="source-create"),
|
||||||
path(
|
path(
|
||||||
"inlets/<uuid:pk>/update/",
|
"sources/<uuid:pk>/update/",
|
||||||
inlets.InletUpdateView.as_view(),
|
sources.SourceUpdateView.as_view(),
|
||||||
name="inlet-update",
|
name="source-update",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"inlets/<uuid:pk>/delete/",
|
"sources/<uuid:pk>/delete/",
|
||||||
inlets.InletDeleteView.as_view(),
|
sources.SourceDeleteView.as_view(),
|
||||||
name="inlet-delete",
|
name="source-delete",
|
||||||
),
|
),
|
||||||
# Policies
|
# Policies
|
||||||
path("policies/", policies.PolicyListView.as_view(), name="policies"),
|
path("policies/", policy.PolicyListView.as_view(), name="policies"),
|
||||||
path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"),
|
path("policies/create/", policy.PolicyCreateView.as_view(), name="policy-create"),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/update/",
|
"policies/<uuid:pk>/update/",
|
||||||
policies.PolicyUpdateView.as_view(),
|
policy.PolicyUpdateView.as_view(),
|
||||||
name="policy-update",
|
name="policy-update",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/delete/",
|
"policies/<uuid:pk>/delete/",
|
||||||
policies.PolicyDeleteView.as_view(),
|
policy.PolicyDeleteView.as_view(),
|
||||||
name="policy-delete",
|
name="policy-delete",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/test/",
|
"policies/<uuid:pk>/test/", policy.PolicyTestView.as_view(), name="policy-test"
|
||||||
policies.PolicyTestView.as_view(),
|
|
||||||
name="policy-test",
|
|
||||||
),
|
),
|
||||||
# Outlets
|
# Providers
|
||||||
path("outlets/", outlets.OutletListView.as_view(), name="outlets"),
|
path("providers/", providers.ProviderListView.as_view(), name="providers"),
|
||||||
path("outlets/create/", outlets.OutletCreateView.as_view(), name="outlet-create",),
|
|
||||||
path(
|
path(
|
||||||
"outlets/<int:pk>/update/",
|
"providers/create/",
|
||||||
outlets.OutletUpdateView.as_view(),
|
providers.ProviderCreateView.as_view(),
|
||||||
name="outlet-update",
|
name="provider-create",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"outlets/<int:pk>/delete/",
|
"providers/<int:pk>/update/",
|
||||||
outlets.OutletDeleteView.as_view(),
|
providers.ProviderUpdateView.as_view(),
|
||||||
name="outlet-delete",
|
name="provider-update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"providers/<int:pk>/delete/",
|
||||||
|
providers.ProviderDeleteView.as_view(),
|
||||||
|
name="provider-delete",
|
||||||
),
|
),
|
||||||
# Stages
|
# Stages
|
||||||
path("stages/", stages.StageListView.as_view(), name="stages"),
|
path("stages/", stages.StageListView.as_view(), name="stages"),
|
||||||
|
|
|
@ -5,9 +5,8 @@ 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, Inlet, Outlet, User
|
from passbook.core.models import Application, Policy, 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
|
||||||
|
|
||||||
|
@ -28,14 +27,16 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
||||||
kwargs["application_count"] = len(Application.objects.all())
|
kwargs["application_count"] = len(Application.objects.all())
|
||||||
kwargs["policy_count"] = len(Policy.objects.all())
|
kwargs["policy_count"] = len(Policy.objects.all())
|
||||||
kwargs["user_count"] = len(User.objects.all())
|
kwargs["user_count"] = len(User.objects.all())
|
||||||
kwargs["outlet_count"] = len(Outlet.objects.all())
|
kwargs["provider_count"] = len(Provider.objects.all())
|
||||||
kwargs["inlet_count"] = len(Inlet.objects.all())
|
kwargs["source_count"] = len(Source.objects.all())
|
||||||
kwargs["stage_count"] = len(Stage.objects.all())
|
kwargs["stage_count"] = len(Stage.objects.all())
|
||||||
kwargs["flow_count"] = len(Flow.objects.all())
|
kwargs["flow_count"] = len(Flow.objects.all())
|
||||||
kwargs["invitation_count"] = len(Invitation.objects.all())
|
kwargs["invitation_count"] = len(Invitation.objects.all())
|
||||||
kwargs["version"] = __version__
|
kwargs["version"] = __version__
|
||||||
kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5))
|
kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5))
|
||||||
kwargs["outlets_without_application"] = Outlet.objects.filter(application=None)
|
kwargs["providers_without_application"] = Provider.objects.filter(
|
||||||
|
application=None
|
||||||
|
)
|
||||||
kwargs["policies_without_binding"] = len(
|
kwargs["policies_without_binding"] = len(
|
||||||
Policy.objects.filter(policymodel__isnull=True)
|
Policy.objects.filter(policymodel__isnull=True)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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):
|
|
@ -1,4 +1,4 @@
|
||||||
"""passbook Inlet administration"""
|
"""passbook Provider administration"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.mixins import (
|
from django.contrib.auth.mixins import (
|
||||||
|
@ -11,23 +11,23 @@ from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import DeleteView, ListView, UpdateView
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
from passbook.core.models import Inlet
|
from passbook.core.models import Provider
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class InletListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
class ProviderListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
"""Show list of all inlets"""
|
"""Show list of all providers"""
|
||||||
|
|
||||||
model = Inlet
|
model = Provider
|
||||||
permission_required = "passbook_core.view_inlet"
|
permission_required = "passbook_core.add_provider"
|
||||||
ordering = "name"
|
template_name = "administration/provider/list.html"
|
||||||
paginate_by = 40
|
paginate_by = 10
|
||||||
template_name = "administration/inlet/list.html"
|
ordering = "id"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs["types"] = {
|
kwargs["types"] = {
|
||||||
x.__name__: x._meta.verbose_name for x in all_subclasses(Inlet)
|
x.__name__: x._meta.verbose_name for x in all_subclasses(Provider)
|
||||||
}
|
}
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
@ -35,40 +35,40 @@ class InletListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
return super().get_queryset().select_subclasses()
|
return super().get_queryset().select_subclasses()
|
||||||
|
|
||||||
|
|
||||||
class InletCreateView(
|
class ProviderCreateView(
|
||||||
SuccessMessageMixin,
|
SuccessMessageMixin,
|
||||||
LoginRequiredMixin,
|
LoginRequiredMixin,
|
||||||
DjangoPermissionRequiredMixin,
|
DjangoPermissionRequiredMixin,
|
||||||
CreateAssignPermView,
|
CreateAssignPermView,
|
||||||
):
|
):
|
||||||
"""Create new Inlet"""
|
"""Create new Provider"""
|
||||||
|
|
||||||
model = Inlet
|
model = Provider
|
||||||
permission_required = "passbook_core.add_inlet"
|
permission_required = "passbook_core.add_provider"
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
success_url = reverse_lazy("passbook_admin:inlets")
|
success_url = reverse_lazy("passbook_admin:providers")
|
||||||
success_message = _("Successfully created Inlet")
|
success_message = _("Successfully created Provider")
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
inlet_type = self.request.GET.get("type")
|
provider_type = self.request.GET.get("type")
|
||||||
model = next(x for x in all_subclasses(Inlet) if x.__name__ == inlet_type)
|
model = next(x for x in all_subclasses(Provider) if x.__name__ == provider_type)
|
||||||
if not model:
|
if not model:
|
||||||
raise Http404
|
raise Http404
|
||||||
return path_to_class(model.form)
|
return path_to_class(model.form)
|
||||||
|
|
||||||
|
|
||||||
class InletUpdateView(
|
class ProviderUpdateView(
|
||||||
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
):
|
):
|
||||||
"""Update inlet"""
|
"""Update provider"""
|
||||||
|
|
||||||
model = Inlet
|
model = Provider
|
||||||
permission_required = "passbook_core.change_inlet"
|
permission_required = "passbook_core.change_provider"
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("passbook_admin:inlets")
|
success_url = reverse_lazy("passbook_admin:providers")
|
||||||
success_message = _("Successfully updated Inlet")
|
success_message = _("Successfully updated Provider")
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
form_class_path = self.get_object().form
|
form_class_path = self.get_object().form
|
||||||
|
@ -77,25 +77,29 @@ class InletUpdateView(
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return (
|
return (
|
||||||
Inlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
Provider.objects.filter(pk=self.kwargs.get("pk"))
|
||||||
|
.select_subclasses()
|
||||||
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InletDeleteView(
|
class ProviderDeleteView(
|
||||||
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
||||||
):
|
):
|
||||||
"""Delete inlet"""
|
"""Delete provider"""
|
||||||
|
|
||||||
model = Inlet
|
model = Provider
|
||||||
permission_required = "passbook_core.delete_inlet"
|
permission_required = "passbook_core.delete_provider"
|
||||||
|
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
success_url = reverse_lazy("passbook_admin:inlets")
|
success_url = reverse_lazy("passbook_admin:providers")
|
||||||
success_message = _("Successfully deleted Inlet")
|
success_message = _("Successfully deleted Provider")
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return (
|
return (
|
||||||
Inlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
Provider.objects.filter(pk=self.kwargs.get("pk"))
|
||||||
|
.select_subclasses()
|
||||||
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
|
@ -1,4 +1,4 @@
|
||||||
"""passbook Outlet administration"""
|
"""passbook Source administration"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.mixins import (
|
from django.contrib.auth.mixins import (
|
||||||
|
@ -11,23 +11,23 @@ from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import DeleteView, ListView, UpdateView
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
from passbook.core.models import Outlet
|
from passbook.core.models import Source
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
class SourceListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
"""Show list of all outlets"""
|
"""Show list of all sources"""
|
||||||
|
|
||||||
model = Outlet
|
model = Source
|
||||||
permission_required = "passbook_core.add_outlet"
|
permission_required = "passbook_core.view_source"
|
||||||
template_name = "administration/outlet/list.html"
|
ordering = "name"
|
||||||
paginate_by = 10
|
paginate_by = 40
|
||||||
ordering = "id"
|
template_name = "administration/source/list.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs["types"] = {
|
kwargs["types"] = {
|
||||||
x.__name__: x._meta.verbose_name for x in all_subclasses(Outlet)
|
x.__name__: x._meta.verbose_name for x in all_subclasses(Source)
|
||||||
}
|
}
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
@ -35,40 +35,40 @@ class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
return super().get_queryset().select_subclasses()
|
return super().get_queryset().select_subclasses()
|
||||||
|
|
||||||
|
|
||||||
class OutletCreateView(
|
class SourceCreateView(
|
||||||
SuccessMessageMixin,
|
SuccessMessageMixin,
|
||||||
LoginRequiredMixin,
|
LoginRequiredMixin,
|
||||||
DjangoPermissionRequiredMixin,
|
DjangoPermissionRequiredMixin,
|
||||||
CreateAssignPermView,
|
CreateAssignPermView,
|
||||||
):
|
):
|
||||||
"""Create new Outlet"""
|
"""Create new Source"""
|
||||||
|
|
||||||
model = Outlet
|
model = Source
|
||||||
permission_required = "passbook_core.add_outlet"
|
permission_required = "passbook_core.add_source"
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
success_url = reverse_lazy("passbook_admin:outlets")
|
success_url = reverse_lazy("passbook_admin:sources")
|
||||||
success_message = _("Successfully created Outlet")
|
success_message = _("Successfully created Source")
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
outlet_type = self.request.GET.get("type")
|
source_type = self.request.GET.get("type")
|
||||||
model = next(x for x in all_subclasses(Outlet) if x.__name__ == outlet_type)
|
model = next(x for x in all_subclasses(Source) if x.__name__ == source_type)
|
||||||
if not model:
|
if not model:
|
||||||
raise Http404
|
raise Http404
|
||||||
return path_to_class(model.form)
|
return path_to_class(model.form)
|
||||||
|
|
||||||
|
|
||||||
class OutletUpdateView(
|
class SourceUpdateView(
|
||||||
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
):
|
):
|
||||||
"""Update outlet"""
|
"""Update source"""
|
||||||
|
|
||||||
model = Outlet
|
model = Source
|
||||||
permission_required = "passbook_core.change_outlet"
|
permission_required = "passbook_core.change_source"
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("passbook_admin:outlets")
|
success_url = reverse_lazy("passbook_admin:sources")
|
||||||
success_message = _("Successfully updated Outlet")
|
success_message = _("Successfully updated Source")
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
form_class_path = self.get_object().form
|
form_class_path = self.get_object().form
|
||||||
|
@ -77,25 +77,25 @@ class OutletUpdateView(
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return (
|
return (
|
||||||
Outlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
Source.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OutletDeleteView(
|
class SourceDeleteView(
|
||||||
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
||||||
):
|
):
|
||||||
"""Delete outlet"""
|
"""Delete source"""
|
||||||
|
|
||||||
model = Outlet
|
model = Source
|
||||||
permission_required = "passbook_core.delete_outlet"
|
permission_required = "passbook_core.delete_source"
|
||||||
|
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
success_url = reverse_lazy("passbook_admin:outlets")
|
success_url = reverse_lazy("passbook_admin:sources")
|
||||||
success_message = _("Successfully deleted Outlet")
|
success_message = _("Successfully deleted Source")
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return (
|
return (
|
||||||
Outlet.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
Source.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
|
@ -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 Token, User
|
from passbook.core.models import Nonce, 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 token for user and return link"""
|
"""Create nonce 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
|
||||||
token = Token.objects.create(user=self.object)
|
nonce = Nonce.objects.create(user=self.object)
|
||||||
link = request.build_absolute_uri(
|
link = request.build_absolute_uri(
|
||||||
reverse("passbook_flows:default-recovery", kwargs={"token": token.uuid})
|
reverse("passbook_flows:default-recovery", kwargs={"nonce": nonce.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})
|
||||||
|
|
|
@ -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,7 +24,8 @@ class PolicyPermissions(BasePermission):
|
||||||
|
|
||||||
policy_engine: PolicyEngine
|
policy_engine: PolicyEngine
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj: PolicyBindingModel) -> bool:
|
def has_object_permission(self, request, view, obj: PolicyModel) -> bool:
|
||||||
self.policy_engine = PolicyEngine(obj.policies.all(), request.user, request)
|
# if not obj.po
|
||||||
|
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
|
||||||
|
|
|
@ -9,18 +9,12 @@ from structlog import get_logger
|
||||||
|
|
||||||
from passbook.api.permissions import CustomObjectPermissions
|
from passbook.api.permissions import CustomObjectPermissions
|
||||||
from passbook.audit.api import EventViewSet
|
from passbook.audit.api import EventViewSet
|
||||||
from passbook.channels.in_ldap.api import LDAPInletViewSet, LDAPPropertyMappingViewSet
|
|
||||||
from passbook.channels.in_oauth.api import OAuthInletViewSet
|
|
||||||
from passbook.channels.out_app_gw.api import ApplicationGatewayOutletViewSet
|
|
||||||
from passbook.channels.out_oauth.api import OAuth2OutletViewSet
|
|
||||||
from passbook.channels.out_oidc.api import OpenIDOutletViewSet
|
|
||||||
from passbook.channels.out_saml.api import SAMLOutletViewSet, SAMLPropertyMappingViewSet
|
|
||||||
from passbook.core.api.applications import ApplicationViewSet
|
from passbook.core.api.applications import ApplicationViewSet
|
||||||
from passbook.core.api.groups import GroupViewSet
|
from passbook.core.api.groups import GroupViewSet
|
||||||
from passbook.core.api.inlets import InletViewSet
|
|
||||||
from passbook.core.api.outlets import OutletViewSet
|
|
||||||
from passbook.core.api.policies import PolicyViewSet
|
from passbook.core.api.policies import PolicyViewSet
|
||||||
from passbook.core.api.propertymappings import PropertyMappingViewSet
|
from passbook.core.api.propertymappings import PropertyMappingViewSet
|
||||||
|
from passbook.core.api.providers import ProviderViewSet
|
||||||
|
from passbook.core.api.sources import SourceViewSet
|
||||||
from passbook.core.api.users import UserViewSet
|
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
|
||||||
|
@ -30,6 +24,12 @@ from passbook.policies.expression.api import ExpressionPolicyViewSet
|
||||||
from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet
|
from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet
|
||||||
from passbook.policies.password.api import PasswordPolicyViewSet
|
from passbook.policies.password.api import PasswordPolicyViewSet
|
||||||
from passbook.policies.reputation.api import ReputationPolicyViewSet
|
from passbook.policies.reputation.api import ReputationPolicyViewSet
|
||||||
|
from passbook.providers.app_gw.api import ApplicationGatewayProviderViewSet
|
||||||
|
from passbook.providers.oauth.api import OAuth2ProviderViewSet
|
||||||
|
from passbook.providers.oidc.api import OpenIDProviderViewSet
|
||||||
|
from passbook.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProviderViewSet
|
||||||
|
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.captcha.api import CaptchaStageViewSet
|
||||||
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
|
||||||
|
@ -57,15 +57,9 @@ router.register("core/users", UserViewSet)
|
||||||
|
|
||||||
router.register("audit/events", EventViewSet)
|
router.register("audit/events", EventViewSet)
|
||||||
|
|
||||||
router.register("inlets/all", InletViewSet)
|
router.register("sources/all", SourceViewSet)
|
||||||
router.register("inlets/ldap", LDAPInletViewSet)
|
router.register("sources/ldap", LDAPSourceViewSet)
|
||||||
router.register("inlets/oauth", OAuthInletViewSet)
|
router.register("sources/oauth", OAuthSourceViewSet)
|
||||||
|
|
||||||
router.register("outlets/all", OutletViewSet)
|
|
||||||
router.register("outlets/applicationgateway", ApplicationGatewayOutletViewSet)
|
|
||||||
router.register("outlets/oauth", OAuth2OutletViewSet)
|
|
||||||
router.register("outlets/openid", OpenIDOutletViewSet)
|
|
||||||
router.register("outlets/saml", SAMLOutletViewSet)
|
|
||||||
|
|
||||||
router.register("policies/all", PolicyViewSet)
|
router.register("policies/all", PolicyViewSet)
|
||||||
router.register("policies/bindings", PolicyBindingViewSet)
|
router.register("policies/bindings", PolicyBindingViewSet)
|
||||||
|
@ -75,6 +69,12 @@ router.register("policies/password", PasswordPolicyViewSet)
|
||||||
router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet)
|
router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet)
|
||||||
router.register("policies/reputation", ReputationPolicyViewSet)
|
router.register("policies/reputation", ReputationPolicyViewSet)
|
||||||
|
|
||||||
|
router.register("providers/all", ProviderViewSet)
|
||||||
|
router.register("providers/applicationgateway", ApplicationGatewayProviderViewSet)
|
||||||
|
router.register("providers/oauth", OAuth2ProviderViewSet)
|
||||||
|
router.register("providers/openid", OpenIDProviderViewSet)
|
||||||
|
router.register("providers/saml", SAMLProviderViewSet)
|
||||||
|
|
||||||
router.register("propertymappings/all", PropertyMappingViewSet)
|
router.register("propertymappings/all", PropertyMappingViewSet)
|
||||||
router.register("propertymappings/ldap", LDAPPropertyMappingViewSet)
|
router.register("propertymappings/ldap", LDAPPropertyMappingViewSet)
|
||||||
router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
|
router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Event",
|
name="AuditEntry",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -33,16 +33,15 @@ class Migration(migrations.Migration):
|
||||||
"action",
|
"action",
|
||||||
models.TextField(
|
models.TextField(
|
||||||
choices=[
|
choices=[
|
||||||
("LOGIN", "login"),
|
("login", "login"),
|
||||||
("LOGIN_FAILED", "login_failed"),
|
("login_failed", "login_failed"),
|
||||||
("LOGOUT", "logout"),
|
("logout", "logout"),
|
||||||
("AUTHORIZE_APPLICATION", "authorize_application"),
|
("authorize_application", "authorize_application"),
|
||||||
("SUSPICIOUS_REQUEST", "suspicious_request"),
|
("suspicious_request", "suspicious_request"),
|
||||||
("SIGN_UP", "sign_up"),
|
("sign_up", "sign_up"),
|
||||||
("PASSWORD_RESET", "password_reset"),
|
("password_reset", "password_reset"),
|
||||||
("INVITE_CREATED", "invitation_created"),
|
("invitation_created", "invitation_created"),
|
||||||
("INVITE_USED", "invitation_used"),
|
("invitation_used", "invitation_used"),
|
||||||
("CUSTOM", "custom"),
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -54,7 +53,7 @@ class Migration(migrations.Migration):
|
||||||
blank=True, default=dict
|
blank=True, default=dict
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("client_ip", models.GenericIPAddressField(null=True)),
|
("request_ip", models.GenericIPAddressField()),
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
(
|
(
|
||||||
"user",
|
"user",
|
||||||
|
@ -66,8 +65,8 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"verbose_name": "Audit Event",
|
"verbose_name": "Audit Entry",
|
||||||
"verbose_name_plural": "Audit Events",
|
"verbose_name_plural": "Audit Entries",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-28 08:29
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
("passbook_audit", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(old_name="AuditEntry", new_name="Event",),
|
||||||
|
]
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Generated by Django 2.2.8 on 2019-12-05 14:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import passbook.audit.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_audit", "0002_auto_20191028_0829"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="event",
|
||||||
|
options={
|
||||||
|
"verbose_name": "Audit Event",
|
||||||
|
"verbose_name_plural": "Audit Events",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="event",
|
||||||
|
name="action",
|
||||||
|
field=models.TextField(
|
||||||
|
choices=[
|
||||||
|
("LOGIN", "login"),
|
||||||
|
("LOGIN_FAILED", "login_failed"),
|
||||||
|
("LOGOUT", "logout"),
|
||||||
|
("AUTHORIZE_APPLICATION", "authorize_application"),
|
||||||
|
("SUSPICIOUS_REQUEST", "suspicious_request"),
|
||||||
|
("SIGN_UP", "sign_up"),
|
||||||
|
("PASSWORD_RESET", "password_reset"),
|
||||||
|
("INVITE_CREATED", "invitation_created"),
|
||||||
|
("INVITE_USED", "invitation_used"),
|
||||||
|
("CUSTOM", "custom"),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.8 on 2019-12-05 15:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_audit", "0003_auto_20191205_1407"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(model_name="event", name="request_ip",),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="event",
|
||||||
|
name="client_ip",
|
||||||
|
field=models.GenericIPAddressField(null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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.policies.models import Policy
|
from passbook.core.models import Policy
|
||||||
|
|
||||||
|
|
||||||
class TestAuditEvent(TestCase):
|
class TestAuditEvent(TestCase):
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
"""Passbook ldap app config"""
|
|
||||||
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookInletLDAPConfig(AppConfig):
|
|
||||||
"""Passbook ldap app config"""
|
|
||||||
|
|
||||||
name = "passbook.channels.in_ldap"
|
|
||||||
label = "passbook_channels_in_ldap"
|
|
||||||
verbose_name = "passbook Inlets.LDAP"
|
|
|
@ -1,33 +0,0 @@
|
||||||
"""LDAP Sync tasks"""
|
|
||||||
from passbook.channels.in_ldap.connector import Connector
|
|
||||||
from passbook.channels.in_ldap.models import LDAPInlet
|
|
||||||
from passbook.root.celery import CELERY_APP
|
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task()
|
|
||||||
def sync_groups(inlet_pk: int):
|
|
||||||
"""Sync LDAP Groups on background worker"""
|
|
||||||
inlet = LDAPInlet.objects.get(pk=inlet_pk)
|
|
||||||
connector = Connector(inlet)
|
|
||||||
connector.bind()
|
|
||||||
connector.sync_groups()
|
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task()
|
|
||||||
def sync_users(inlet_pk: int):
|
|
||||||
"""Sync LDAP Users on background worker"""
|
|
||||||
inlet = LDAPInlet.objects.get(pk=inlet_pk)
|
|
||||||
connector = Connector(inlet)
|
|
||||||
connector.bind()
|
|
||||||
connector.sync_users()
|
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task()
|
|
||||||
def sync():
|
|
||||||
"""Sync all inlets"""
|
|
||||||
for inlet in LDAPInlet.objects.filter(enabled=True):
|
|
||||||
connector = Connector(inlet)
|
|
||||||
connector.bind()
|
|
||||||
connector.sync_users()
|
|
||||||
connector.sync_groups()
|
|
||||||
connector.sync_membership()
|
|
|
@ -1,29 +0,0 @@
|
||||||
"""OAuth Inlet Serializer"""
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
|
||||||
from rest_framework.viewsets import ModelViewSet
|
|
||||||
|
|
||||||
from passbook.admin.forms.inlet import INLET_SERIALIZER_FIELDS
|
|
||||||
from passbook.channels.in_oauth.models import OAuthInlet
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthInletSerializer(ModelSerializer):
|
|
||||||
"""OAuth Inlet Serializer"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = OAuthInlet
|
|
||||||
fields = INLET_SERIALIZER_FIELDS + [
|
|
||||||
"inlet_type",
|
|
||||||
"request_token_url",
|
|
||||||
"authorization_url",
|
|
||||||
"access_token_url",
|
|
||||||
"profile_url",
|
|
||||||
"consumer_key",
|
|
||||||
"consumer_secret",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthInletViewSet(ModelViewSet):
|
|
||||||
"""Inlet Viewset"""
|
|
||||||
|
|
||||||
queryset = OAuthInlet.objects.all()
|
|
||||||
serializer_class = OAuthInletSerializer
|
|
|
@ -1,24 +0,0 @@
|
||||||
"""passbook oauth_client Authorization backend"""
|
|
||||||
|
|
||||||
from django.contrib.auth.backends import ModelBackend
|
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from passbook.channels.in_oauth.models import OAuthInlet, UserOAuthInletConnection
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizedServiceBackend(ModelBackend):
|
|
||||||
"Authentication backend for users registered with remote OAuth provider."
|
|
||||||
|
|
||||||
def authenticate(self, request, inlet=None, identifier=None):
|
|
||||||
"Fetch user for a given inlet by id."
|
|
||||||
inlet_q = Q(inlet__name=inlet)
|
|
||||||
if isinstance(inlet, OAuthInlet):
|
|
||||||
inlet_q = Q(inlet=inlet)
|
|
||||||
try:
|
|
||||||
access = UserOAuthInletConnection.objects.filter(
|
|
||||||
inlet_q, identifier=identifier
|
|
||||||
).select_related("user")[0]
|
|
||||||
except IndexError:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return access.user
|
|
|
@ -1,81 +0,0 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("passbook_core", "__first__"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="OAuthInlet",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"inlet_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_core.Inlet",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("inlet_type", models.CharField(max_length=255)),
|
|
||||||
(
|
|
||||||
"request_token_url",
|
|
||||||
models.CharField(
|
|
||||||
blank=True, max_length=255, verbose_name="Request Token URL"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"authorization_url",
|
|
||||||
models.CharField(max_length=255, verbose_name="Authorization URL"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"access_token_url",
|
|
||||||
models.CharField(max_length=255, verbose_name="Access Token URL"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"profile_url",
|
|
||||||
models.CharField(max_length=255, verbose_name="Profile URL"),
|
|
||||||
),
|
|
||||||
("consumer_key", models.TextField()),
|
|
||||||
("consumer_secret", models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "Generic OAuth Inlet",
|
|
||||||
"verbose_name_plural": "Generic OAuth Inlets",
|
|
||||||
},
|
|
||||||
bases=("passbook_core.inlet",),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="UserOAuthInletConnection",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"userinletconnection_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_core.UserInletConnection",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("identifier", models.CharField(max_length=255)),
|
|
||||||
("access_token", models.TextField(blank=True, default=None, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "User OAuth Inlet Connection",
|
|
||||||
"verbose_name_plural": "User OAuth Inlet Connections",
|
|
||||||
},
|
|
||||||
bases=("passbook_core.userinletconnection",),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,159 +0,0 @@
|
||||||
"""OAuth Client models"""
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.urls import reverse, reverse_lazy
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from passbook.channels.in_oauth.clients import get_client
|
|
||||||
from passbook.core.models import Inlet, UserInletConnection
|
|
||||||
from passbook.core.types import UILoginButton, UIUserSettings
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthInlet(Inlet):
|
|
||||||
"""Configuration for OAuth inlet."""
|
|
||||||
|
|
||||||
inlet_type = models.CharField(max_length=255)
|
|
||||||
request_token_url = models.CharField(
|
|
||||||
blank=True, max_length=255, verbose_name=_("Request Token URL")
|
|
||||||
)
|
|
||||||
authorization_url = models.CharField(
|
|
||||||
max_length=255, verbose_name=_("Authorization URL")
|
|
||||||
)
|
|
||||||
access_token_url = models.CharField(
|
|
||||||
max_length=255, verbose_name=_("Access Token URL")
|
|
||||||
)
|
|
||||||
profile_url = models.CharField(max_length=255, verbose_name=_("Profile URL"))
|
|
||||||
consumer_key = models.TextField()
|
|
||||||
consumer_secret = models.TextField()
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.OAuthInletForm"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ui_login_button(self) -> UILoginButton:
|
|
||||||
return UILoginButton(
|
|
||||||
url=reverse_lazy(
|
|
||||||
"passbook_channels_in_oauth:oauth-client-login",
|
|
||||||
kwargs={"inlet_slug": self.slug},
|
|
||||||
),
|
|
||||||
icon_path=f"passbook/inlets/{self.inlet_type}.svg",
|
|
||||||
name=self.name,
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ui_additional_info(self) -> str:
|
|
||||||
url = reverse_lazy(
|
|
||||||
"passbook_channels_in_oauth:oauth-client-callback",
|
|
||||||
kwargs={"inlet_slug": self.slug},
|
|
||||||
)
|
|
||||||
return f"Callback URL: <pre>{url}</pre>"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ui_user_settings(self) -> UIUserSettings:
|
|
||||||
icon_type = self.inlet_type
|
|
||||||
if icon_type == "azure ad":
|
|
||||||
icon_type = "windows"
|
|
||||||
icon_class = f"fab fa-{icon_type}"
|
|
||||||
view_name = "passbook_channels_in_oauth:oauth-client-user"
|
|
||||||
return UIUserSettings(
|
|
||||||
name=self.name,
|
|
||||||
icon=icon_class,
|
|
||||||
view_name=reverse((view_name), kwargs={"inlet_slug": self.slug}),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
verbose_name = _("Generic OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Generic OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class GitHubOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify GitHub Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.GitHubOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("GitHub OAuth Inlet")
|
|
||||||
verbose_name_plural = _("GitHub OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class TwitterOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify Twitter Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.TwitterOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("Twitter OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Twitter OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class FacebookOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify Facebook Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.FacebookOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("Facebook OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Facebook OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class DiscordOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify Discord Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.DiscordOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("Discord OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Discord OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class GoogleOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify Google Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.GoogleOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("Google OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Google OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class AzureADOAuthInlet(OAuthInlet):
|
|
||||||
"""Abstract subclass of OAuthInlet to specify AzureAD Form"""
|
|
||||||
|
|
||||||
form = "passbook.channels.in_oauth.forms.AzureADOAuthInletForm"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
abstract = True
|
|
||||||
verbose_name = _("Azure AD OAuth Inlet")
|
|
||||||
verbose_name_plural = _("Azure AD OAuth Inlets")
|
|
||||||
|
|
||||||
|
|
||||||
class UserOAuthInletConnection(UserInletConnection):
|
|
||||||
"""Authorized remote OAuth inlet."""
|
|
||||||
|
|
||||||
identifier = models.CharField(max_length=255)
|
|
||||||
access_token = models.TextField(blank=True, null=True, default=None)
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
self.access_token = self.access_token or None
|
|
||||||
super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def api_client(self):
|
|
||||||
"""Get API Client"""
|
|
||||||
return get_client(self.inlet, self.access_token or "")
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
verbose_name = _("User OAuth Inlet Connection")
|
|
||||||
verbose_name_plural = _("User OAuth Inlet Connections")
|
|
|
@ -1,15 +0,0 @@
|
||||||
"""Oauth2 Client Settings"""
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
"passbook.channels.in_oauth.backends.AuthorizedServiceBackend",
|
|
||||||
]
|
|
||||||
|
|
||||||
PASSBOOK_SOURCES_OAUTH_TYPES = [
|
|
||||||
"passbook.channels.in_oauth.types.discord",
|
|
||||||
"passbook.channels.in_oauth.types.facebook",
|
|
||||||
"passbook.channels.in_oauth.types.github",
|
|
||||||
"passbook.channels.in_oauth.types.google",
|
|
||||||
"passbook.channels.in_oauth.types.reddit",
|
|
||||||
"passbook.channels.in_oauth.types.twitter",
|
|
||||||
"passbook.channels.in_oauth.types.azure_ad",
|
|
||||||
]
|
|
|
@ -1,28 +0,0 @@
|
||||||
"""SAMLInlet API Views"""
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
|
||||||
from rest_framework.viewsets import ModelViewSet
|
|
||||||
|
|
||||||
from passbook.channels.in_saml.models import SAMLInlet
|
|
||||||
|
|
||||||
|
|
||||||
class SAMLInletSerializer(ModelSerializer):
|
|
||||||
"""SAMLInlet Serializer"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = SAMLInlet
|
|
||||||
fields = [
|
|
||||||
"pk",
|
|
||||||
"issuer",
|
|
||||||
"idp_url",
|
|
||||||
"idp_logout_url",
|
|
||||||
"auto_logout",
|
|
||||||
"signing_kp",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SAMLInletViewSet(ModelViewSet):
|
|
||||||
"""SAMLInlet Viewset"""
|
|
||||||
|
|
||||||
queryset = SAMLInlet.objects.all()
|
|
||||||
serializer_class = SAMLInletSerializer
|
|
|
@ -1,12 +0,0 @@
|
||||||
"""Passbook SAML app config"""
|
|
||||||
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookInletSAMLConfig(AppConfig):
|
|
||||||
"""passbook saml_idp app config"""
|
|
||||||
|
|
||||||
name = "passbook.channels.in_saml"
|
|
||||||
label = "passbook_channels_in_saml"
|
|
||||||
verbose_name = "passbook Inlets.SAML"
|
|
||||||
mountpoint = "source/saml/"
|
|
|
@ -1,68 +0,0 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("passbook_crypto", "0001_initial"),
|
|
||||||
("passbook_core", "__first__"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="SAMLInlet",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"inlet_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_core.Inlet",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"issuer",
|
|
||||||
models.TextField(
|
|
||||||
blank=True,
|
|
||||||
default=None,
|
|
||||||
help_text="Also known as Entity ID. Defaults the Metadata URL.",
|
|
||||||
verbose_name="Issuer",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("idp_url", models.URLField(verbose_name="IDP URL")),
|
|
||||||
(
|
|
||||||
"idp_logout_url",
|
|
||||||
models.URLField(
|
|
||||||
blank=True,
|
|
||||||
default=None,
|
|
||||||
null=True,
|
|
||||||
verbose_name="IDP Logout URL",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("auto_logout", models.BooleanField(default=False)),
|
|
||||||
(
|
|
||||||
"signing_kp",
|
|
||||||
models.ForeignKey(
|
|
||||||
default=None,
|
|
||||||
help_text="Certificate Key Pair of the IdP which Assertions are validated against.",
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
to="passbook_crypto.CertificateKeyPair",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "SAML Inlet",
|
|
||||||
"verbose_name_plural": "SAML Inlets",
|
|
||||||
},
|
|
||||||
bases=("passbook_core.inlet",),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,20 +0,0 @@
|
||||||
"""saml sp helpers"""
|
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import reverse
|
|
||||||
|
|
||||||
from passbook.channels.in_saml.models import SAMLInlet
|
|
||||||
|
|
||||||
|
|
||||||
def get_issuer(request: HttpRequest, inlet: SAMLInlet) -> str:
|
|
||||||
"""Get Inlet's Issuer, falling back to our Metadata URL if none is set"""
|
|
||||||
issuer = inlet.issuer
|
|
||||||
if issuer is None:
|
|
||||||
return build_full_url("metadata", request, inlet)
|
|
||||||
return issuer
|
|
||||||
|
|
||||||
|
|
||||||
def build_full_url(view: str, request: HttpRequest, inlet: SAMLInlet) -> str:
|
|
||||||
"""Build Full ACS URL to be used in IDP"""
|
|
||||||
return request.build_absolute_uri(
|
|
||||||
reverse(f"passbook_channels_in_saml:{view}", kwargs={"inlet_slug": inlet.slug})
|
|
||||||
)
|
|
|
@ -1,29 +0,0 @@
|
||||||
"""OAuth2Outlet API Views"""
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
|
||||||
from rest_framework.viewsets import ModelViewSet
|
|
||||||
|
|
||||||
from passbook.channels.out_oauth.models import OAuth2Outlet
|
|
||||||
|
|
||||||
|
|
||||||
class OAuth2OutletSerializer(ModelSerializer):
|
|
||||||
"""OAuth2Outlet Serializer"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = OAuth2Outlet
|
|
||||||
fields = [
|
|
||||||
"pk",
|
|
||||||
"name",
|
|
||||||
"redirect_uris",
|
|
||||||
"client_type",
|
|
||||||
"authorization_grant_type",
|
|
||||||
"client_id",
|
|
||||||
"client_secret",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class OAuth2OutletViewSet(ModelViewSet):
|
|
||||||
"""OAuth2Outlet Viewset"""
|
|
||||||
|
|
||||||
queryset = OAuth2Outlet.objects.all()
|
|
||||||
serializer_class = OAuth2OutletSerializer
|
|
|
@ -1,12 +0,0 @@
|
||||||
"""passbook auth oauth provider app config"""
|
|
||||||
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookOutletOAuthConfig(AppConfig):
|
|
||||||
"""passbook auth oauth provider app config"""
|
|
||||||
|
|
||||||
name = "passbook.channels.out_oauth"
|
|
||||||
label = "passbook_channels_out_oauth"
|
|
||||||
verbose_name = "passbook Outlets.OAuth"
|
|
||||||
mountpoint = ""
|
|
|
@ -1,9 +0,0 @@
|
||||||
"""passbook OIDC Provider"""
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
"oidc_provider",
|
|
||||||
]
|
|
||||||
|
|
||||||
OIDC_AFTER_USERLOGIN_HOOK = "passbook.channels.out_oidc.auth.check_permissions"
|
|
||||||
OIDC_IDTOKEN_INCLUDE_CLAIMS = True
|
|
||||||
OIDC_USERINFO = "passbook.channels.out_oidc.claims.userinfo"
|
|
|
@ -1,140 +0,0 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
import passbook.channels.out_saml.utils.time
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("passbook_core", "__first__"),
|
|
||||||
("passbook_crypto", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="SAMLPropertyMapping",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"propertymapping_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_core.PropertyMapping",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("saml_name", models.TextField(verbose_name="SAML Name")),
|
|
||||||
(
|
|
||||||
"friendly_name",
|
|
||||||
models.TextField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "SAML Property Mapping",
|
|
||||||
"verbose_name_plural": "SAML Property Mappings",
|
|
||||||
},
|
|
||||||
bases=("passbook_core.propertymapping",),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="SAMLOutlet",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"outlet_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_core.Outlet",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.TextField()),
|
|
||||||
("processor_path", models.CharField(choices=[], max_length=255)),
|
|
||||||
("acs_url", models.URLField(verbose_name="ACS URL")),
|
|
||||||
("audience", models.TextField(default="")),
|
|
||||||
("issuer", models.TextField(help_text="Also known as EntityID")),
|
|
||||||
(
|
|
||||||
"assertion_valid_not_before",
|
|
||||||
models.TextField(
|
|
||||||
default="minutes=-5",
|
|
||||||
help_text="Assertion valid not before current time + this value (Format: hours=-1;minutes=-2;seconds=-3).",
|
|
||||||
validators=[
|
|
||||||
passbook.channels.out_saml.utils.time.timedelta_string_validator
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"assertion_valid_not_on_or_after",
|
|
||||||
models.TextField(
|
|
||||||
default="minutes=5",
|
|
||||||
help_text="Assertion not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).",
|
|
||||||
validators=[
|
|
||||||
passbook.channels.out_saml.utils.time.timedelta_string_validator
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"session_valid_not_on_or_after",
|
|
||||||
models.TextField(
|
|
||||||
default="minutes=86400",
|
|
||||||
help_text="Session not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).",
|
|
||||||
validators=[
|
|
||||||
passbook.channels.out_saml.utils.time.timedelta_string_validator
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"digest_algorithm",
|
|
||||||
models.CharField(
|
|
||||||
choices=[("sha1", "SHA1"), ("sha256", "SHA256")],
|
|
||||||
default="sha256",
|
|
||||||
max_length=50,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"signature_algorithm",
|
|
||||||
models.CharField(
|
|
||||||
choices=[
|
|
||||||
("rsa-sha1", "RSA-SHA1"),
|
|
||||||
("rsa-sha256", "RSA-SHA256"),
|
|
||||||
("ecdsa-sha256", "ECDSA-SHA256"),
|
|
||||||
("dsa-sha1", "DSA-SHA1"),
|
|
||||||
],
|
|
||||||
default="rsa-sha256",
|
|
||||||
max_length=50,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"require_signing",
|
|
||||||
models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
help_text="Require Requests to be signed by an X509 Certificate. Must match the Certificate selected in `Singing Keypair`.",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"signing_kp",
|
|
||||||
models.ForeignKey(
|
|
||||||
default=None,
|
|
||||||
help_text="Singing is enabled upon selection of a Key Pair.",
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
to="passbook_crypto.CertificateKeyPair",
|
|
||||||
verbose_name="Signing Keypair",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "SAML Outlet",
|
|
||||||
"verbose_name_plural": "SAML Outlets",
|
|
||||||
},
|
|
||||||
bases=("passbook_core.outlet",),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,6 +0,0 @@
|
||||||
"""saml provider settings"""
|
|
||||||
|
|
||||||
PASSBOOK_PROVIDERS_SAML_PROCESSORS = [
|
|
||||||
"passbook.channels.out_saml.processors.generic",
|
|
||||||
"passbook.channels.out_saml.processors.salesforce",
|
|
||||||
]
|
|
|
@ -1,11 +0,0 @@
|
||||||
"""passbook saml provider app config"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookOutletSAMLv2Config(AppConfig):
|
|
||||||
"""passbook samlv2 provider app config"""
|
|
||||||
|
|
||||||
name = "passbook.channels.out_samlv2"
|
|
||||||
label = "passbook_channels_out_samlv2"
|
|
||||||
verbose_name = "passbook Outlets.SAMLv2"
|
|
||||||
mountpoint = "application/samlv2/"
|
|
|
@ -16,7 +16,7 @@ class ApplicationSerializer(ModelSerializer):
|
||||||
"name",
|
"name",
|
||||||
"slug",
|
"slug",
|
||||||
"skip_authorization",
|
"skip_authorization",
|
||||||
"outlet",
|
"provider",
|
||||||
"meta_launch_url",
|
"meta_launch_url",
|
||||||
"meta_icon_url",
|
"meta_icon_url",
|
||||||
"meta_description",
|
"meta_description",
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
"""Inlet API Views"""
|
|
||||||
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
|
||||||
|
|
||||||
from passbook.admin.forms.inlet import INLET_SERIALIZER_FIELDS
|
|
||||||
from passbook.core.models import Inlet
|
|
||||||
|
|
||||||
|
|
||||||
class InletSerializer(ModelSerializer):
|
|
||||||
"""Inlet Serializer"""
|
|
||||||
|
|
||||||
__type__ = SerializerMethodField(method_name="get_type")
|
|
||||||
|
|
||||||
def get_type(self, obj):
|
|
||||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
|
||||||
return obj._meta.object_name.lower().replace("inlet", "")
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = Inlet
|
|
||||||
fields = INLET_SERIALIZER_FIELDS + ["__type__"]
|
|
||||||
|
|
||||||
|
|
||||||
class InletViewSet(ReadOnlyModelViewSet):
|
|
||||||
"""Inlet Viewset"""
|
|
||||||
|
|
||||||
queryset = Inlet.objects.all()
|
|
||||||
serializer_class = InletSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Inlet.objects.select_subclasses()
|
|
|
@ -1,30 +0,0 @@
|
||||||
"""Outlet API Views"""
|
|
||||||
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
|
||||||
|
|
||||||
from passbook.core.models import Outlet
|
|
||||||
|
|
||||||
|
|
||||||
class OutletSerializer(ModelSerializer):
|
|
||||||
"""Outlet Serializer"""
|
|
||||||
|
|
||||||
__type__ = SerializerMethodField(method_name="get_type")
|
|
||||||
|
|
||||||
def get_type(self, obj):
|
|
||||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
|
||||||
return obj._meta.object_name.lower().replace("outlet", "")
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = Outlet
|
|
||||||
fields = ["pk", "property_mappings", "__type__"]
|
|
||||||
|
|
||||||
|
|
||||||
class OutletViewSet(ReadOnlyModelViewSet):
|
|
||||||
"""Outlet Viewset"""
|
|
||||||
|
|
||||||
queryset = Outlet.objects.all()
|
|
||||||
serializer_class = OutletSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Outlet.objects.select_subclasses()
|
|
|
@ -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):
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""Provider API Views"""
|
||||||
|
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
||||||
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||||
|
|
||||||
|
from passbook.core.models import Provider
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderSerializer(ModelSerializer):
|
||||||
|
"""Provider Serializer"""
|
||||||
|
|
||||||
|
__type__ = SerializerMethodField(method_name="get_type")
|
||||||
|
|
||||||
|
def get_type(self, obj):
|
||||||
|
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||||
|
return obj._meta.object_name.lower().replace("provider", "")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = Provider
|
||||||
|
fields = ["pk", "property_mappings", "__type__"]
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderViewSet(ReadOnlyModelViewSet):
|
||||||
|
"""Provider Viewset"""
|
||||||
|
|
||||||
|
queryset = Provider.objects.all()
|
||||||
|
serializer_class = ProviderSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Provider.objects.select_subclasses()
|
|
@ -0,0 +1,31 @@
|
||||||
|
"""Source API Views"""
|
||||||
|
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
||||||
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||||
|
|
||||||
|
from passbook.admin.forms.source import SOURCE_SERIALIZER_FIELDS
|
||||||
|
from passbook.core.models import Source
|
||||||
|
|
||||||
|
|
||||||
|
class SourceSerializer(ModelSerializer):
|
||||||
|
"""Source Serializer"""
|
||||||
|
|
||||||
|
__type__ = SerializerMethodField(method_name="get_type")
|
||||||
|
|
||||||
|
def get_type(self, obj):
|
||||||
|
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||||
|
return obj._meta.object_name.lower().replace("source", "")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = Source
|
||||||
|
fields = SOURCE_SERIALIZER_FIELDS + ["__type__"]
|
||||||
|
|
||||||
|
|
||||||
|
class SourceViewSet(ReadOnlyModelViewSet):
|
||||||
|
"""Source Viewset"""
|
||||||
|
|
||||||
|
queryset = Source.objects.all()
|
||||||
|
serializer_class = SourceSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Source.objects.select_subclasses()
|
|
@ -3,14 +3,14 @@ from django import forms
|
||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from passbook.core.models import Application, Outlet
|
from passbook.core.models import Application, Provider
|
||||||
|
|
||||||
|
|
||||||
class ApplicationForm(forms.ModelForm):
|
class ApplicationForm(forms.ModelForm):
|
||||||
"""Application Form"""
|
"""Application Form"""
|
||||||
|
|
||||||
outlet = forms.ModelChoiceField(
|
provider = forms.ModelChoiceField(
|
||||||
queryset=Outlet.objects.all().order_by("pk").select_subclasses(),
|
queryset=Provider.objects.all().order_by("pk").select_subclasses(),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class ApplicationForm(forms.ModelForm):
|
||||||
"name",
|
"name",
|
||||||
"slug",
|
"slug",
|
||||||
"skip_authorization",
|
"skip_authorization",
|
||||||
"outlet",
|
"provider",
|
||||||
"meta_launch_url",
|
"meta_launch_url",
|
||||||
"meta_icon_url",
|
"meta_icon_url",
|
||||||
"meta_description",
|
"meta_description",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 2.2.6 on 2019-10-07 14:06
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import django.contrib.auth.validators
|
||||||
import django.contrib.postgres.fields.jsonb
|
import django.contrib.postgres.fields.jsonb
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
import guardian.mixins
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
@ -20,7 +19,6 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("auth", "0011_update_proxy_permissions"),
|
("auth", "0011_update_proxy_permissions"),
|
||||||
("passbook_policies", "0001_initial"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -107,41 +105,63 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("uuid", models.UUIDField(default=uuid.uuid4, editable=False)),
|
("uuid", models.UUIDField(default=uuid.uuid4, editable=False)),
|
||||||
("name", models.TextField(help_text="User's display name.")),
|
("name", models.TextField()),
|
||||||
("password_change_date", models.DateTimeField(auto_now_add=True)),
|
("password_change_date", models.DateTimeField(auto_now_add=True)),
|
||||||
(
|
|
||||||
"attributes",
|
|
||||||
django.contrib.postgres.fields.jsonb.JSONField(
|
|
||||||
blank=True, default=dict
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
options={"permissions": (("reset_user_password", "Reset Password"),),},
|
options={
|
||||||
bases=(guardian.mixins.GuardianUserMixin, models.Model),
|
"verbose_name": "user",
|
||||||
|
"verbose_name_plural": "users",
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
managers=[("objects", django.contrib.auth.models.UserManager()),],
|
managers=[("objects", django.contrib.auth.models.UserManager()),],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Inlet",
|
name="Policy",
|
||||||
fields=[
|
fields=[
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("last_updated", models.DateTimeField(auto_now=True)),
|
||||||
(
|
(
|
||||||
"policybindingmodel_ptr",
|
"uuid",
|
||||||
models.OneToOneField(
|
models.UUIDField(
|
||||||
auto_created=True,
|
default=uuid.uuid4,
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
editable=False,
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
to="passbook_policies.PolicyBindingModel",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("name", models.TextField(help_text="Inlet's display Name.")),
|
("name", models.TextField(blank=True, null=True)),
|
||||||
(
|
(
|
||||||
"slug",
|
"action",
|
||||||
models.SlugField(help_text="Internal source name, used in URLs."),
|
models.CharField(
|
||||||
|
choices=[("allow", "allow"), ("deny", "deny")], max_length=20
|
||||||
),
|
),
|
||||||
("enabled", models.BooleanField(default=True)),
|
),
|
||||||
|
("negate", models.BooleanField(default=False)),
|
||||||
|
("order", models.IntegerField(default=0)),
|
||||||
|
("timeout", models.IntegerField(default=30)),
|
||||||
],
|
],
|
||||||
bases=("passbook_policies.policybindingmodel",),
|
options={"abstract": False,},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="PolicyModel",
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"policies",
|
||||||
|
models.ManyToManyField(blank=True, to="passbook_core.Policy"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"abstract": False,},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="PropertyMapping",
|
name="PropertyMapping",
|
||||||
|
@ -156,7 +176,6 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("name", models.TextField()),
|
("name", models.TextField()),
|
||||||
("expression", models.TextField()),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"verbose_name": "Property Mapping",
|
"verbose_name": "Property Mapping",
|
||||||
|
@ -164,38 +183,74 @@ class Migration(migrations.Migration):
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="UserInletConnection",
|
name="DebugPolicy",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"id",
|
"policy_ptr",
|
||||||
models.AutoField(
|
models.OneToOneField(
|
||||||
auto_created=True,
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
verbose_name="ID",
|
to="passbook_core.Policy",
|
||||||
),
|
|
||||||
),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("last_updated", models.DateTimeField(auto_now=True)),
|
|
||||||
(
|
|
||||||
"inlet",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
to="passbook_core.Inlet",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"user",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
("result", models.BooleanField(default=False)),
|
||||||
|
("wait_min", models.IntegerField(default=5)),
|
||||||
|
("wait_max", models.IntegerField(default=30)),
|
||||||
],
|
],
|
||||||
options={"unique_together": {("user", "inlet")},},
|
options={
|
||||||
|
"verbose_name": "Debug Policy",
|
||||||
|
"verbose_name_plural": "Debug Policies",
|
||||||
|
},
|
||||||
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Outlet",
|
name="Factor",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"policymodel_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="passbook_core.PolicyModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField()),
|
||||||
|
("slug", models.SlugField(unique=True)),
|
||||||
|
("order", models.IntegerField()),
|
||||||
|
("enabled", models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
options={"abstract": False,},
|
||||||
|
bases=("passbook_core.policymodel",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Source",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"policymodel_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="passbook_core.PolicyModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField()),
|
||||||
|
("slug", models.SlugField()),
|
||||||
|
("enabled", models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
options={"abstract": False,},
|
||||||
|
bases=("passbook_core.policymodel",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Provider",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"id",
|
"id",
|
||||||
|
@ -215,7 +270,7 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Token",
|
name="Nonce",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -229,11 +284,10 @@ class Migration(migrations.Migration):
|
||||||
(
|
(
|
||||||
"expires",
|
"expires",
|
||||||
models.DateTimeField(
|
models.DateTimeField(
|
||||||
default=passbook.core.models.default_token_duration
|
default=passbook.core.models.default_nonce_duration
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("expiring", models.BooleanField(default=True)),
|
("expiring", models.BooleanField(default=True)),
|
||||||
("description", models.TextField(blank=True, default="")),
|
|
||||||
(
|
(
|
||||||
"user",
|
"user",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
|
@ -242,15 +296,37 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={"verbose_name": "Token", "verbose_name_plural": "Tokens",},
|
options={"verbose_name": "Nonce", "verbose_name_plural": "Nonces",},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.CreateModel(
|
||||||
model_name="inlet",
|
name="Invitation",
|
||||||
name="property_mappings",
|
fields=[
|
||||||
field=models.ManyToManyField(
|
(
|
||||||
blank=True, default=None, to="passbook_core.PropertyMapping"
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4,
|
||||||
|
editable=False,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
("expires", models.DateTimeField(blank=True, default=None, null=True)),
|
||||||
|
("fixed_username", models.TextField(blank=True, default=None)),
|
||||||
|
("fixed_email", models.TextField(blank=True, default=None)),
|
||||||
|
("needs_confirmation", models.BooleanField(default=True)),
|
||||||
|
(
|
||||||
|
"created_by",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Invitation",
|
||||||
|
"verbose_name_plural": "Invitations",
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Group",
|
name="Group",
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -265,7 +341,7 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
("name", models.CharField(max_length=80, verbose_name="name")),
|
("name", models.CharField(max_length=80, verbose_name="name")),
|
||||||
(
|
(
|
||||||
"attributes",
|
"tags",
|
||||||
django.contrib.postgres.fields.jsonb.JSONField(
|
django.contrib.postgres.fields.jsonb.JSONField(
|
||||||
blank=True, default=dict
|
blank=True, default=dict
|
||||||
),
|
),
|
||||||
|
@ -283,57 +359,11 @@ class Migration(migrations.Migration):
|
||||||
],
|
],
|
||||||
options={"unique_together": {("name", "parent")},},
|
options={"unique_together": {("name", "parent")},},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name="Application",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"policybindingmodel_ptr",
|
|
||||||
models.OneToOneField(
|
|
||||||
auto_created=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
to="passbook_policies.PolicyBindingModel",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("name", models.TextField(help_text="Application's display Name.")),
|
|
||||||
(
|
|
||||||
"slug",
|
|
||||||
models.SlugField(
|
|
||||||
help_text="Internal application name, used in URLs."
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("skip_authorization", models.BooleanField(default=False)),
|
|
||||||
("meta_launch_url", models.URLField(blank=True, default="")),
|
|
||||||
("meta_icon_url", models.TextField(blank=True, default="")),
|
|
||||||
("meta_description", models.TextField(blank=True, default="")),
|
|
||||||
("meta_publisher", models.TextField(blank=True, default="")),
|
|
||||||
(
|
|
||||||
"outlet",
|
|
||||||
models.OneToOneField(
|
|
||||||
blank=True,
|
|
||||||
default=None,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
||||||
to="passbook_core.Outlet",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
bases=("passbook_policies.policybindingmodel",),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="user",
|
model_name="user",
|
||||||
name="groups",
|
name="groups",
|
||||||
field=models.ManyToManyField(to="passbook_core.Group"),
|
field=models.ManyToManyField(to="passbook_core.Group"),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name="user",
|
|
||||||
name="inlets",
|
|
||||||
field=models.ManyToManyField(
|
|
||||||
through="passbook_core.UserInletConnection", to="passbook_core.Inlet"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="user",
|
model_name="user",
|
||||||
name="user_permissions",
|
name="user_permissions",
|
||||||
|
@ -347,33 +377,74 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="PropertyMappingBinding",
|
name="UserSourceConnection",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"uuid",
|
"id",
|
||||||
models.UUIDField(
|
models.AutoField(
|
||||||
default=uuid.uuid4,
|
auto_created=True,
|
||||||
editable=False,
|
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("order", models.IntegerField(default=0)),
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("last_updated", models.DateTimeField(auto_now=True)),
|
||||||
(
|
(
|
||||||
"outlet",
|
"user",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
to="passbook_core.Outlet",
|
to=settings.AUTH_USER_MODEL,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"property_mapping",
|
"source",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
to="passbook_core.PropertyMapping",
|
to="passbook_core.Source",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={"unique_together": {("property_mapping", "outlet", "order")},},
|
options={"unique_together": {("user", "source")},},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Application",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"policymodel_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="passbook_core.PolicyModel",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField()),
|
||||||
|
("slug", models.SlugField()),
|
||||||
|
("launch_url", models.URLField(blank=True, null=True)),
|
||||||
|
("icon_url", models.TextField(blank=True, null=True)),
|
||||||
|
("skip_authorization", models.BooleanField(default=False)),
|
||||||
|
(
|
||||||
|
"provider",
|
||||||
|
models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||||
|
to="passbook_core.Provider",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"abstract": False,},
|
||||||
|
bases=("passbook_core.policymodel",),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="sources",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
through="passbook_core.UserSourceConnection", to="passbook_core.Source"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-10 10:58
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="user",
|
||||||
|
options={"permissions": (("reset_user_password", "Reset Password"),)},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-10 11:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="nonce",
|
||||||
|
name="description",
|
||||||
|
field=models.TextField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-11 09:14
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields.jsonb
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0002_nonce_description"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="group", old_name="tags", new_name="attributes",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="source",
|
||||||
|
name="property_mappings",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True, default=None, to="passbook_core.PropertyMapping"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="attributes",
|
||||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(
|
||||||
|
blank=True, default=dict
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-10 15:41
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0002_auto_20191010_1058"),
|
||||||
|
("passbook_core", "0002_nonce_description"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = []
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-14 11:56
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0003_auto_20191011_0914"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(model_name="policy", name="action",),
|
||||||
|
]
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-25 20:22
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0004_remove_policy_action"),
|
||||||
|
("passbook_core", "0003_merge_20191010_1541"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = []
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-17 16:15
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0005_merge_20191025_2022"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="propertymapping",
|
||||||
|
name="template",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-17 19:34
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0006_propertymapping_template"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="propertymapping", old_name="template", new_name="expression",
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-20 12:42
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0007_auto_20200217_1934"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="application", old_name="icon_url", new_name="meta_icon_url",
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="application", old_name="launch_url", new_name="meta_launch_url",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_description",
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_publisher",
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-21 14:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0008_auto_20200220_1242"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="name",
|
||||||
|
field=models.TextField(help_text="Application's display Name."),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="slug",
|
||||||
|
field=models.SlugField(
|
||||||
|
help_text="Internal application name, used in URLs."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="factor",
|
||||||
|
name="name",
|
||||||
|
field=models.TextField(help_text="Factor's display Name."),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="factor",
|
||||||
|
name="slug",
|
||||||
|
field=models.SlugField(
|
||||||
|
help_text="Internal factor name, used in URLs.", unique=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="source",
|
||||||
|
name="name",
|
||||||
|
field=models.TextField(help_text="Source's display Name."),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="source",
|
||||||
|
name="slug",
|
||||||
|
field=models.SlugField(help_text="Internal source name, used in URLs."),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="user",
|
||||||
|
name="name",
|
||||||
|
field=models.TextField(help_text="User's display name."),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-21 22:08
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0009_auto_20200221_1410"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_description",
|
||||||
|
field=models.TextField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_icon_url",
|
||||||
|
field=models.TextField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_launch_url",
|
||||||
|
field=models.URLField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_publisher",
|
||||||
|
field=models.TextField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-22 18:22
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def fix_application_null(apps, schema_editor):
|
||||||
|
"""Fix Application meta_fields being null"""
|
||||||
|
Application = apps.get_model("passbook_core", "Application")
|
||||||
|
for app in Application.objects.all():
|
||||||
|
if app.meta_launch_url is None:
|
||||||
|
app.meta_launch_url = ""
|
||||||
|
if app.meta_icon_url is None:
|
||||||
|
app.meta_icon_url = ""
|
||||||
|
if app.meta_description is None:
|
||||||
|
app.meta_description = ""
|
||||||
|
if app.meta_publisher is None:
|
||||||
|
app.meta_publisher = ""
|
||||||
|
app.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0010_auto_20200221_2208"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(fix_application_null)]
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-08 17:58
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0011_auto_20200222_1822"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel(name="Factor",),
|
||||||
|
]
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Generated by Django 3.0.5 on 2020-05-10 10:01
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_policies", "0003_auto_20200508_1642"),
|
||||||
|
("passbook_stages_password", "0001_initial"),
|
||||||
|
("passbook_core", "0012_delete_factor"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel(name="DebugPolicy",),
|
||||||
|
]
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 3.0.5 on 2020-05-11 19:57
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0013_delete_debugpolicy"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel(name="Invitation",),
|
||||||
|
]
|
|
@ -10,6 +10,7 @@ from django.db import models
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django_prometheus.models import ExportModelOperationsMixin
|
||||||
from guardian.mixins import GuardianUserMixin
|
from guardian.mixins import GuardianUserMixin
|
||||||
from jinja2 import Undefined
|
from jinja2 import Undefined
|
||||||
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
||||||
|
@ -21,18 +22,19 @@ 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.models import PolicyBindingModel
|
from passbook.policies.exceptions import PolicyException
|
||||||
|
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
NATIVE_ENVIRONMENT = NativeEnvironment()
|
NATIVE_ENVIRONMENT = NativeEnvironment()
|
||||||
|
|
||||||
|
|
||||||
def default_token_duration():
|
def default_nonce_duration():
|
||||||
"""Default duration a Token is valid"""
|
"""Default duration a Nonce is valid"""
|
||||||
return now() + timedelta(minutes=30)
|
return now() + timedelta(minutes=30)
|
||||||
|
|
||||||
|
|
||||||
class Group(UUIDModel):
|
class Group(ExportModelOperationsMixin("group"), UUIDModel):
|
||||||
"""Custom Group model which supports a basic hierarchy"""
|
"""Custom Group model which supports a basic hierarchy"""
|
||||||
|
|
||||||
name = models.CharField(_("name"), max_length=80)
|
name = models.CharField(_("name"), max_length=80)
|
||||||
|
@ -53,13 +55,13 @@ class Group(UUIDModel):
|
||||||
unique_together = (("name", "parent",),)
|
unique_together = (("name", "parent",),)
|
||||||
|
|
||||||
|
|
||||||
class User(GuardianUserMixin, AbstractUser):
|
class User(ExportModelOperationsMixin("user"), GuardianUserMixin, AbstractUser):
|
||||||
"""Custom User model to allow easier adding o f user-based settings"""
|
"""Custom User model to allow easier adding o f user-based settings"""
|
||||||
|
|
||||||
uuid = models.UUIDField(default=uuid4, editable=False)
|
uuid = models.UUIDField(default=uuid4, editable=False)
|
||||||
name = models.TextField(help_text=_("User's display name."))
|
name = models.TextField(help_text=_("User's display name."))
|
||||||
|
|
||||||
inlets = models.ManyToManyField("Inlet", through="UserInletConnection")
|
sources = models.ManyToManyField("Source", through="UserSourceConnection")
|
||||||
groups = models.ManyToManyField("Group")
|
groups = models.ManyToManyField("Group")
|
||||||
password_change_date = models.DateTimeField(auto_now_add=True)
|
password_change_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
@ -76,7 +78,29 @@ class User(GuardianUserMixin, AbstractUser):
|
||||||
permissions = (("reset_user_password", "Reset Password"),)
|
permissions = (("reset_user_password", "Reset Password"),)
|
||||||
|
|
||||||
|
|
||||||
class Application(PolicyBindingModel):
|
class Provider(ExportModelOperationsMixin("provider"), models.Model):
|
||||||
|
"""Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application"""
|
||||||
|
|
||||||
|
property_mappings = models.ManyToManyField(
|
||||||
|
"PropertyMapping", default=None, blank=True
|
||||||
|
)
|
||||||
|
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
|
# This class defines no field for easier inheritance
|
||||||
|
def __str__(self):
|
||||||
|
if hasattr(self, "name"):
|
||||||
|
return getattr(self, "name")
|
||||||
|
return super().__str__()
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyModel(UUIDModel, CreatedUpdatedModel):
|
||||||
|
"""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"""
|
||||||
|
@ -84,8 +108,8 @@ class Application(PolicyBindingModel):
|
||||||
name = models.TextField(help_text=_("Application's display Name."))
|
name = models.TextField(help_text=_("Application's display Name."))
|
||||||
slug = models.SlugField(help_text=_("Internal application name, used in URLs."))
|
slug = models.SlugField(help_text=_("Internal application name, used in URLs."))
|
||||||
skip_authorization = models.BooleanField(default=False)
|
skip_authorization = models.BooleanField(default=False)
|
||||||
outlet = models.OneToOneField(
|
provider = models.OneToOneField(
|
||||||
"Outlet", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
|
"Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
|
||||||
)
|
)
|
||||||
|
|
||||||
meta_launch_url = models.URLField(default="", blank=True)
|
meta_launch_url = models.URLField(default="", blank=True)
|
||||||
|
@ -95,20 +119,20 @@ class Application(PolicyBindingModel):
|
||||||
|
|
||||||
objects = InheritanceManager()
|
objects = InheritanceManager()
|
||||||
|
|
||||||
def get_outlet(self) -> Optional["Outlet"]:
|
def get_provider(self) -> Optional[Provider]:
|
||||||
"""Get casted outlet instance"""
|
"""Get casted provider instance"""
|
||||||
if not self.outlet:
|
if not self.provider:
|
||||||
return None
|
return None
|
||||||
return Outlet.objects.get_subclass(pk=self.outlet.pk)
|
return Provider.objects.get_subclass(pk=self.provider.pk)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Inlet(PolicyBindingModel):
|
class Source(ExportModelOperationsMixin("source"), PolicyModel):
|
||||||
"""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=_("Inlet's display Name."))
|
name = models.TextField(help_text=_("Source's display Name."))
|
||||||
slug = models.SlugField(help_text=_("Internal source name, used in URLs."))
|
slug = models.SlugField(help_text=_("Internal source name, used in URLs."))
|
||||||
|
|
||||||
enabled = models.BooleanField(default=True)
|
enabled = models.BooleanField(default=True)
|
||||||
|
@ -141,69 +165,56 @@ class Inlet(PolicyBindingModel):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class UserInletConnection(CreatedUpdatedModel):
|
class UserSourceConnection(CreatedUpdatedModel):
|
||||||
"""Connection between User and Inlet."""
|
"""Connection between User and Source."""
|
||||||
|
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
inlet = models.ForeignKey(Inlet, on_delete=models.CASCADE)
|
source = models.ForeignKey(Source, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
unique_together = (("user", "inlet"),)
|
unique_together = (("user", "source"),)
|
||||||
|
|
||||||
|
|
||||||
class Token(UUIDModel):
|
class Policy(ExportModelOperationsMixin("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()
|
||||||
|
|
||||||
|
|
||||||
|
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_token_duration)
|
expires = models.DateTimeField(default=default_nonce_duration)
|
||||||
user = models.ForeignKey("User", on_delete=models.CASCADE, related_name="+")
|
user = models.ForeignKey("User", on_delete=models.CASCADE)
|
||||||
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 token is expired yet."""
|
"""Check if nonce is expired yet."""
|
||||||
return now() > self.expires
|
return now() > self.expires
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Token f{self.uuid.hex} {self.description} (expires={self.expires})"
|
return f"Nonce f{self.uuid.hex} {self.description} (expires={self.expires})"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _("Token")
|
verbose_name = _("Nonce")
|
||||||
verbose_name_plural = _("Tokens")
|
verbose_name_plural = _("Nonces")
|
||||||
|
|
||||||
|
|
||||||
class Outlet(models.Model):
|
|
||||||
"""Application-independent Outlet instance. For example SAML2 Remote, OAuth2 Application"""
|
|
||||||
|
|
||||||
property_mappings = models.ManyToManyField(
|
|
||||||
"PropertyMapping", default=None, blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
objects = InheritanceManager()
|
|
||||||
|
|
||||||
# This class defines no field for easier inheritance
|
|
||||||
def __str__(self):
|
|
||||||
if hasattr(self, "name"):
|
|
||||||
return getattr(self, "name")
|
|
||||||
return super().__str__()
|
|
||||||
|
|
||||||
|
|
||||||
class PropertyMappingBinding(UUIDModel):
|
|
||||||
"""Binds a PropertyMapping instance to an outlet"""
|
|
||||||
|
|
||||||
property_mapping = models.ForeignKey("PropertyMapping", on_delete=models.CASCADE)
|
|
||||||
outlet = models.ForeignKey("Outlet", on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
order = models.IntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"PropertyMapping Binding p={self.property_mapping} outlet={self.outlet}"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
unique_together = (("property_mapping", "outlet", "order"),)
|
|
||||||
|
|
||||||
|
|
||||||
class PropertyMapping(UUIDModel):
|
class PropertyMapping(UUIDModel):
|
||||||
|
|
|
@ -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.policies.models import Policy
|
from passbook.core.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):
|
||||||
|
|
|
@ -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 Token
|
from passbook.core.models import Nonce
|
||||||
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_tokens():
|
def clean_nonces():
|
||||||
"""Remove expired tokens"""
|
"""Remove expired nonces"""
|
||||||
amount, _ = Token.objects.filter(expires__lt=now(), expiring=True).delete()
|
amount, _ = Nonce.objects.filter(expires__lt=now(), expiring=True).delete()
|
||||||
LOGGER.debug("Deleted expired tokens", amount=amount)
|
LOGGER.debug("Deleted expired nonces", amount=amount)
|
||||||
|
|
|
@ -34,17 +34,17 @@
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% user_inlets as user_inlets_loc %}
|
{% user_sources as user_sources_loc %}
|
||||||
{% if user_inlets_loc %}
|
{% if user_sources_loc %}
|
||||||
<section class="pf-c-nav__section">
|
<section class="pf-c-nav__section">
|
||||||
<h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2>
|
<h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2>
|
||||||
<ul class="pf-c-nav__list">
|
<ul class="pf-c-nav__list">
|
||||||
{% for inlet in user_inlets_loc %}
|
{% for source in user_sources_loc %}
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item">
|
||||||
<a href="{{ inlet.view_name }}"
|
<a href="{{ source.view_name }}"
|
||||||
class="pf-c-nav__link {% if user_settings.view_name == request.get_full_path %} pf-m-current {% endif %}">
|
class="pf-c-nav__link {% if user_settings.view_name == request.get_full_path %} pf-m-current {% endif %}">
|
||||||
<i class="{{ inlet.icon }}"></i>
|
<i class="{{ source.icon }}"></i>
|
||||||
{{ inlet.name }}
|
{{ source.name }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -4,7 +4,7 @@ from typing import Iterable, List
|
||||||
from django import template
|
from django import template
|
||||||
from django.template.context import RequestContext
|
from django.template.context import RequestContext
|
||||||
|
|
||||||
from passbook.core.models import Inlet
|
from passbook.core.models import Source
|
||||||
from passbook.core.types import UIUserSettings
|
from passbook.core.types import UIUserSettings
|
||||||
from passbook.flows.models import Stage
|
from passbook.flows.models import Stage
|
||||||
from passbook.policies.engine import PolicyEngine
|
from passbook.policies.engine import PolicyEngine
|
||||||
|
@ -27,14 +27,14 @@ def user_stages(context: RequestContext) -> List[UIUserSettings]:
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def user_inlets(context: RequestContext) -> List[UIUserSettings]:
|
def user_sources(context: RequestContext) -> List[UIUserSettings]:
|
||||||
"""Return a list of all inlets which are enabled for the user"""
|
"""Return a list of all sources which are enabled for the user"""
|
||||||
user = context.get("request").user
|
user = context.get("request").user
|
||||||
_all_inlets: Iterable[(Inlet)] = (
|
_all_sources: Iterable[Source] = (
|
||||||
(Inlet).objects.filter(enabled=True).select_subclasses()
|
Source.objects.filter(enabled=True).select_subclasses()
|
||||||
)
|
)
|
||||||
matching_inlets: List[UIUserSettings] = []
|
matching_sources: List[UIUserSettings] = []
|
||||||
for source in _all_inlets:
|
for source in _all_sources:
|
||||||
user_settings = source.ui_user_settings
|
user_settings = source.ui_user_settings
|
||||||
if not user_settings:
|
if not user_settings:
|
||||||
continue
|
continue
|
||||||
|
@ -43,5 +43,5 @@ def user_inlets(context: RequestContext) -> List[UIUserSettings]:
|
||||||
)
|
)
|
||||||
policy_engine.build()
|
policy_engine.build()
|
||||||
if policy_engine.passing:
|
if policy_engine.passing:
|
||||||
matching_inlets.append(user_settings)
|
matching_sources.append(user_settings)
|
||||||
return matching_inlets
|
return matching_sources
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.http import HttpRequest
|
||||||
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 Application, Outlet, User
|
from passbook.core.models import Application, Provider, User
|
||||||
from passbook.policies.engine import PolicyEngine
|
from passbook.policies.engine import PolicyEngine
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
@ -14,19 +14,22 @@ LOGGER = get_logger()
|
||||||
|
|
||||||
class AccessMixin:
|
class AccessMixin:
|
||||||
"""Mixin class for usage in Authorization views.
|
"""Mixin class for usage in Authorization views.
|
||||||
Outlet functions to check application access, etc"""
|
Provider functions to check application access, etc"""
|
||||||
|
|
||||||
# request is set by view but since this Mixin has no base class
|
# request is set by view but since this Mixin has no base class
|
||||||
request: HttpRequest = None
|
request: HttpRequest = None
|
||||||
|
|
||||||
def outlet_to_application(self, outlet: Outlet) -> Application:
|
def provider_to_application(self, provider: Provider) -> Application:
|
||||||
"""Lookup application assigned to outlet, throw error if no application assigned"""
|
"""Lookup application assigned to provider, throw error if no application assigned"""
|
||||||
try:
|
try:
|
||||||
return outlet.application
|
return provider.application
|
||||||
except Application.DoesNotExist as exc:
|
except Application.DoesNotExist as exc:
|
||||||
messages.error(
|
messages.error(
|
||||||
self.request,
|
self.request,
|
||||||
_('Outlet "%(name)s" has no application assigned' % {"name": outlet}),
|
_(
|
||||||
|
'Provider "%(name)s" has no application assigned'
|
||||||
|
% {"name": provider}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 3.0.3 on 2020-03-03 21:45
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def create_self_signed(apps, schema_editor):
|
||||||
|
CertificateKeyPair = apps.get_model("passbook_crypto", "CertificateKeyPair")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
from passbook.crypto.builder import CertificateBuilder
|
||||||
|
|
||||||
|
builder = CertificateBuilder()
|
||||||
|
builder.build()
|
||||||
|
CertificateKeyPair.objects.using(db_alias).create(
|
||||||
|
name="passbook Self-signed Certificate",
|
||||||
|
certificate_data=builder.certificate,
|
||||||
|
key_data=builder.private_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
@ -27,22 +41,27 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("name", models.TextField()),
|
("name", models.TextField()),
|
||||||
(
|
("certificate_data", models.TextField()),
|
||||||
"certificate_data",
|
("key_data", models.TextField(blank=True, default="")),
|
||||||
models.TextField(help_text="PEM-encoded Certificate data"),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"key_data",
|
|
||||||
models.TextField(
|
|
||||||
blank=True,
|
|
||||||
default="",
|
|
||||||
help_text="Optional Private Key. If this is set, you can use this keypair for encryption.",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"verbose_name": "Certificate-Key Pair",
|
"verbose_name": "Certificate-Key Pair",
|
||||||
"verbose_name_plural": "Certificate-Key Pairs",
|
"verbose_name_plural": "Certificate-Key Pairs",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.RunPython(create_self_signed),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="certificatekeypair",
|
||||||
|
name="certificate_data",
|
||||||
|
field=models.TextField(help_text="PEM-encoded Certificate data"),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="certificatekeypair",
|
||||||
|
name="key_data",
|
||||||
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default="",
|
||||||
|
help_text="Optional Private Key. If this is set, you can use this keypair for encryption.",
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 3.0.3 on 2020-05-08 18:27
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "__first__"),
|
("passbook_policies", "0003_auto_20200508_1642"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -33,12 +33,10 @@ class Migration(migrations.Migration):
|
||||||
"designation",
|
"designation",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("authentication", "Authentication"),
|
("AUTHENTICATION", "authentication"),
|
||||||
("invalidation", "Invalidation"),
|
("ENROLLMENT", "enrollment"),
|
||||||
("enrollment", "Enrollment"),
|
("RECOVERY", "recovery"),
|
||||||
("unenrollment", "Unrenollment"),
|
("PASSWORD_CHANGE", "password_change"),
|
||||||
("recovery", "Recovery"),
|
|
||||||
("password_change", "Password Change"),
|
|
||||||
],
|
],
|
||||||
max_length=100,
|
max_length=100,
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-09 12:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_flows", "0002_default_flows"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="flow",
|
||||||
|
name="designation",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("authentication", "Authentication"),
|
||||||
|
("enrollment", "Enrollment"),
|
||||||
|
("recovery", "Recovery"),
|
||||||
|
("password_change", "Password Change"),
|
||||||
|
],
|
||||||
|
max_length=100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 3.0.5 on 2020-05-10 23:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_flows", "0003_auto_20200509_1258"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="flow",
|
||||||
|
name="designation",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("authentication", "Authentication"),
|
||||||
|
("enrollment", "Enrollment"),
|
||||||
|
("recovery", "Recovery"),
|
||||||
|
("password_change", "Password Change"),
|
||||||
|
("invalidation", "Invalidation"),
|
||||||
|
],
|
||||||
|
max_length=100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.0.5 on 2020-05-12 11:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_flows", "0004_auto_20200510_2310"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="flow",
|
||||||
|
name="designation",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("authentication", "Authentication"),
|
||||||
|
("invalidation", "Invalidation"),
|
||||||
|
("enrollment", "Enrollment"),
|
||||||
|
("unenrollment", "Unrenollment"),
|
||||||
|
("recovery", "Recovery"),
|
||||||
|
("password_change", "Password Change"),
|
||||||
|
],
|
||||||
|
max_length=100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 3.0.5 on 2020-05-10 10:01
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,7 +9,8 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_policies", "0003_auto_20200508_1642"),
|
||||||
|
("passbook_core", "0013_delete_debugpolicy"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -24,7 +25,7 @@ class Migration(migrations.Migration):
|
||||||
parent_link=True,
|
parent_link=True,
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
to="passbook_policies.Policy",
|
to="passbook_core.Policy",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("result", models.BooleanField(default=False)),
|
("result", models.BooleanField(default=False)),
|
||||||
|
@ -35,6 +36,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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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.policies.models import Policy
|
from passbook.core.models import Policy
|
||||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
|
@ -7,8 +7,7 @@ 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 User
|
from passbook.core.models import Policy, 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
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_core", "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_policies.Policy",
|
to="passbook_core.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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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.policies.models import Policy
|
from passbook.core.models import Policy
|
||||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 3.0.3 on 2020-02-18 14:00
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_core", "0007_auto_20200217_1934"),
|
||||||
]
|
]
|
||||||
|
|
||||||
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_policies.Policy",
|
to="passbook_core.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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_core", "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_policies.Policy",
|
to="passbook_core.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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,8 +6,7 @@ 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.policies.models import Policy
|
from passbook.core.models import Policy, PolicyResult, User
|
||||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
@ -20,14 +19,14 @@ class HaveIBeenPwendPolicy(Policy):
|
||||||
|
|
||||||
form = "passbook.policies.hibp.forms.HaveIBeenPwnedPolicyForm"
|
form = "passbook.policies.hibp.forms.HaveIBeenPwnedPolicyForm"
|
||||||
|
|
||||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
def passes(self, user: User) -> PolicyResult:
|
||||||
"""Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5
|
"""Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5
|
||||||
characters of Password in request and checks if full hash is in response. Returns 0
|
characters of Password in request and checks if full hash is in response. Returns 0
|
||||||
if Password is not in result otherwise the count of how many times it was used."""
|
if Password is not in result otherwise the count of how many times it was used."""
|
||||||
# Only check if password is being set
|
# Only check if password is being set
|
||||||
if not hasattr(request.user, "__password__"):
|
if not hasattr(user, "__password__"):
|
||||||
return PolicyResult(True)
|
return PolicyResult(True)
|
||||||
password = getattr(request.user, "__password__")
|
password = getattr(user, "__password__")
|
||||||
pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec
|
pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec
|
||||||
url = "https://api.pwnedpasswords.com/range/%s" % pw_hash[:5]
|
url = "https://api.pwnedpasswords.com/range/%s" % pw_hash[:5]
|
||||||
result = get(url).text
|
result = get(url).text
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:58
|
# Generated by Django 3.0.3 on 2020-05-07 18:35
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -10,30 +10,11 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = []
|
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=[
|
||||||
|
@ -53,7 +34,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_policies.Policy",
|
to="passbook_core.Policy",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -77,17 +58,12 @@ class Migration(migrations.Migration):
|
||||||
(
|
(
|
||||||
"policies",
|
"policies",
|
||||||
models.ManyToManyField(
|
models.ManyToManyField(
|
||||||
blank=True,
|
|
||||||
related_name="_policybindingmodel_policies_+",
|
related_name="_policybindingmodel_policies_+",
|
||||||
through="passbook_policies.PolicyBinding",
|
through="passbook_policies.PolicyBinding",
|
||||||
to="passbook_policies.Policy",
|
to="passbook_core.Policy",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
|
||||||
"verbose_name": "Policy Binding Model",
|
|
||||||
"verbose_name_plural": "Policy Binding Models",
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="policybinding",
|
model_name="policybinding",
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-08 12:30
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_policies", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="policybindingmodel",
|
||||||
|
options={
|
||||||
|
"verbose_name": "Policy Binding Model",
|
||||||
|
"verbose_name_plural": "Policy Binding Models",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-05-08 16:42
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0011_auto_20200222_1822"),
|
||||||
|
("passbook_policies", "0002_auto_20200508_1230"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="policybindingmodel",
|
||||||
|
name="policies",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name="_policybindingmodel_policies_+",
|
||||||
|
through="passbook_policies.PolicyBinding",
|
||||||
|
to="passbook_core.Policy",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,30 +1,9 @@
|
||||||
"""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.lib.models import CreatedUpdatedModel, UUIDModel
|
from passbook.core.models import Policy
|
||||||
from passbook.policies.exceptions import PolicyException
|
from passbook.lib.models import UUIDModel
|
||||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyBindingModel(models.Model):
|
class PolicyBindingModel(models.Model):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_core", "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_policies.Policy",
|
to="passbook_core.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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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.policies.models import Policy
|
from passbook.core.models import Policy
|
||||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
|
@ -6,9 +6,8 @@ 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 User
|
from passbook.core.models import Policy, 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()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -10,7 +10,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_policies", "0001_initial"),
|
("passbook_core", "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_policies.Policy",
|
to="passbook_core.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_policies.policy",),
|
bases=("passbook_core.policy",),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="UserReputation",
|
name="UserReputation",
|
||||||
|
|
|
@ -2,9 +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 User
|
from passbook.core.models import Policy, 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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
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 User
|
from passbook.core.models import Policy, 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):
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
"""ApplicationGatewayOutlet API Views"""
|
"""ApplicationGatewayProvider API Views"""
|
||||||
from oauth2_provider.generators import generate_client_id, generate_client_secret
|
from oauth2_provider.generators import generate_client_id, generate_client_secret
|
||||||
from oidc_provider.models import Client
|
from oidc_provider.models import Client
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from passbook.channels.out_app_gw.models import ApplicationGatewayOutlet
|
from passbook.providers.app_gw.models import ApplicationGatewayProvider
|
||||||
from passbook.channels.out_oidc.api import OpenIDOutletSerializer
|
from passbook.providers.oidc.api import OpenIDProviderSerializer
|
||||||
|
|
||||||
|
|
||||||
class ApplicationGatewayOutletSerializer(ModelSerializer):
|
class ApplicationGatewayProviderSerializer(ModelSerializer):
|
||||||
"""ApplicationGatewayOutlet Serializer"""
|
"""ApplicationGatewayProvider Serializer"""
|
||||||
|
|
||||||
client = OpenIDOutletSerializer()
|
client = OpenIDProviderSerializer()
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
instance = super().create(validated_data)
|
instance = super().create(validated_data)
|
||||||
|
@ -33,13 +33,13 @@ class ApplicationGatewayOutletSerializer(ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = ApplicationGatewayOutlet
|
model = ApplicationGatewayProvider
|
||||||
fields = ["pk", "name", "internal_host", "external_host", "client"]
|
fields = ["pk", "name", "internal_host", "external_host", "client"]
|
||||||
read_only_fields = ["client"]
|
read_only_fields = ["client"]
|
||||||
|
|
||||||
|
|
||||||
class ApplicationGatewayOutletViewSet(ModelViewSet):
|
class ApplicationGatewayProviderViewSet(ModelViewSet):
|
||||||
"""ApplicationGatewayOutlet Viewset"""
|
"""ApplicationGatewayProvider Viewset"""
|
||||||
|
|
||||||
queryset = ApplicationGatewayOutlet.objects.all()
|
queryset = ApplicationGatewayProvider.objects.all()
|
||||||
serializer_class = ApplicationGatewayOutletSerializer
|
serializer_class = ApplicationGatewayProviderSerializer
|
|
@ -5,7 +5,7 @@ from django.apps import AppConfig
|
||||||
class PassbookApplicationApplicationGatewayConfig(AppConfig):
|
class PassbookApplicationApplicationGatewayConfig(AppConfig):
|
||||||
"""passbook app_gw app"""
|
"""passbook app_gw app"""
|
||||||
|
|
||||||
name = "passbook.channels.out_app_gw"
|
name = "passbook.providers.app_gw"
|
||||||
label = "passbook_channels_out_app_gw"
|
label = "passbook_providers_app_gw"
|
||||||
verbose_name = "passbook Outlets.Application Security Gateway"
|
verbose_name = "passbook Providers.Application Security Gateway"
|
||||||
mountpoint = "application/gateway/"
|
mountpoint = "application/gateway/"
|
|
@ -3,11 +3,11 @@ from django import forms
|
||||||
from oauth2_provider.generators import generate_client_id, generate_client_secret
|
from oauth2_provider.generators import generate_client_id, generate_client_secret
|
||||||
from oidc_provider.models import Client, ResponseType
|
from oidc_provider.models import Client, ResponseType
|
||||||
|
|
||||||
from passbook.channels.out_app_gw.models import ApplicationGatewayOutlet
|
from passbook.providers.app_gw.models import ApplicationGatewayProvider
|
||||||
|
|
||||||
|
|
||||||
class ApplicationGatewayOutletForm(forms.ModelForm):
|
class ApplicationGatewayProviderForm(forms.ModelForm):
|
||||||
"""Security Gateway Outlet form"""
|
"""Security Gateway Provider form"""
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.instance.pk:
|
if not self.instance.pk:
|
||||||
|
@ -31,7 +31,7 @@ class ApplicationGatewayOutletForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = ApplicationGatewayOutlet
|
model = ApplicationGatewayProvider
|
||||||
fields = ["name", "internal_host", "external_host"]
|
fields = ["name", "internal_host", "external_host"]
|
||||||
widgets = {
|
widgets = {
|
||||||
"name": forms.TextInput(),
|
"name": forms.TextInput(),
|
|
@ -0,0 +1,99 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-07 14:07
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ApplicationGatewayProvider",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"provider_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="passbook_core.Provider",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"server_name",
|
||||||
|
django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.TextField(), size=None
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"upstream",
|
||||||
|
django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.TextField(), size=None
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("enabled", models.BooleanField(default=True)),
|
||||||
|
(
|
||||||
|
"authentication_header",
|
||||||
|
models.TextField(blank=True, default="X-Remote-User"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"default_content_type",
|
||||||
|
models.TextField(default="application/octet-stream"),
|
||||||
|
),
|
||||||
|
("upstream_ssl_verification", models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Application Gateway Provider",
|
||||||
|
"verbose_name_plural": "Application Gateway Providers",
|
||||||
|
},
|
||||||
|
bases=("passbook_core.provider",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="RewriteRule",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"propertymapping_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="passbook_core.PropertyMapping",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("match", models.TextField()),
|
||||||
|
("halt", models.BooleanField(default=False)),
|
||||||
|
("replacement", models.TextField()),
|
||||||
|
(
|
||||||
|
"redirect",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("internal", "Internal"),
|
||||||
|
(301, "Moved Permanently"),
|
||||||
|
(302, "Found"),
|
||||||
|
],
|
||||||
|
max_length=50,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"conditions",
|
||||||
|
models.ManyToManyField(blank=True, to="passbook_core.Policy"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Rewrite Rule",
|
||||||
|
"verbose_name_plural": "Rewrite Rules",
|
||||||
|
},
|
||||||
|
bases=("passbook_core.propertymapping",),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-11-11 17:03
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_core", "0005_merge_20191025_2022"),
|
||||||
|
("passbook_providers_app_gw", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(model_name="rewriterule", name="conditions",),
|
||||||
|
migrations.RemoveField(model_name="rewriterule", name="propertymapping_ptr",),
|
||||||
|
migrations.DeleteModel(name="ApplicationGatewayProvider",),
|
||||||
|
migrations.DeleteModel(name="RewriteRule",),
|
||||||
|
]
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-15 19:59
|
# Generated by Django 2.2.7 on 2019-11-11 17:08
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -9,28 +9,28 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("passbook_core", "__first__"),
|
("passbook_core", "0005_merge_20191025_2022"),
|
||||||
("oidc_provider", "0026_client_multiple_response_types"),
|
("oidc_provider", "0026_client_multiple_response_types"),
|
||||||
|
("passbook_providers_app_gw", "0002_auto_20191111_1703"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="ApplicationGatewayOutlet",
|
name="ApplicationGatewayProvider",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"outlet_ptr",
|
"provider_ptr",
|
||||||
models.OneToOneField(
|
models.OneToOneField(
|
||||||
auto_created=True,
|
auto_created=True,
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
parent_link=True,
|
parent_link=True,
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
serialize=False,
|
serialize=False,
|
||||||
to="passbook_core.Outlet",
|
to="passbook_core.Provider",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("name", models.TextField()),
|
("name", models.TextField()),
|
||||||
("internal_host", models.TextField()),
|
("host", models.TextField()),
|
||||||
("external_host", models.TextField()),
|
|
||||||
(
|
(
|
||||||
"client",
|
"client",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
|
@ -40,9 +40,9 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"verbose_name": "Application Gateway Outlet",
|
"verbose_name": "Application Gateway Provider",
|
||||||
"verbose_name_plural": "Application Gateway Outlets",
|
"verbose_name_plural": "Application Gateway Providers",
|
||||||
},
|
},
|
||||||
bases=("passbook_core.outlet",),
|
bases=("passbook_core.provider",),
|
||||||
),
|
),
|
||||||
]
|
]
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 2.2.9 on 2020-01-02 15:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("passbook_providers_app_gw", "0003_applicationgatewayprovider"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="applicationgatewayprovider",
|
||||||
|
old_name="host",
|
||||||
|
new_name="external_host",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationgatewayprovider",
|
||||||
|
name="internal_host",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -9,12 +9,12 @@ from django.utils.translation import gettext as _
|
||||||
from oidc_provider.models import Client
|
from oidc_provider.models import Client
|
||||||
|
|
||||||
from passbook import __version__
|
from passbook import __version__
|
||||||
from passbook.core.models import Outlet
|
from passbook.core.models import Provider
|
||||||
from passbook.lib.utils.template import render_to_string
|
from passbook.lib.utils.template import render_to_string
|
||||||
|
|
||||||
|
|
||||||
class ApplicationGatewayOutlet(Outlet):
|
class ApplicationGatewayProvider(Provider):
|
||||||
"""This outlet uses oauth2_proxy with the OIDC Outlet."""
|
"""This provider uses oauth2_proxy with the OIDC Provider."""
|
||||||
|
|
||||||
name = models.TextField()
|
name = models.TextField()
|
||||||
internal_host = models.TextField()
|
internal_host = models.TextField()
|
||||||
|
@ -22,7 +22,7 @@ class ApplicationGatewayOutlet(Outlet):
|
||||||
|
|
||||||
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
||||||
|
|
||||||
form = "passbook.channels.out_app_gw.forms.ApplicationGatewayOutletForm"
|
form = "passbook.providers.app_gw.forms.ApplicationGatewayProviderForm"
|
||||||
|
|
||||||
def html_setup_urls(self, request: HttpRequest) -> Optional[str]:
|
def html_setup_urls(self, request: HttpRequest) -> Optional[str]:
|
||||||
"""return template and context modal with URLs for authorize, token, openid-config, etc"""
|
"""return template and context modal with URLs for authorize, token, openid-config, etc"""
|
||||||
|
@ -32,7 +32,7 @@ class ApplicationGatewayOutlet(Outlet):
|
||||||
)
|
)
|
||||||
return render_to_string(
|
return render_to_string(
|
||||||
"app_gw/setup_modal.html",
|
"app_gw/setup_modal.html",
|
||||||
{"outlet": self, "cookie_secret": cookie_secret, "version": __version__},
|
{"provider": self, "cookie_secret": cookie_secret, "version": __version__},
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -40,5 +40,5 @@ class ApplicationGatewayOutlet(Outlet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _("Application Gateway Outlet")
|
verbose_name = _("Application Gateway Provider")
|
||||||
verbose_name_plural = _("Application Gateway Outlets")
|
verbose_name_plural = _("Application Gateway Providers")
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue