Revert "*: providers and sources -> channels, PolicyModel to PolicyBindingModel that uses custom M2M through"

This reverts commit 7ed3ceb960.
This commit is contained in:
Jens Langhammer 2020-05-16 16:02:42 +02:00
parent 7ed3ceb960
commit 406f69080b
293 changed files with 4692 additions and 3244 deletions

View File

@ -1,4 +0,0 @@
"""passbook core inlet form fields"""
INLET_FORM_FIELDS = ["name", "slug", "enabled"]
INLET_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"]

View File

@ -0,0 +1,4 @@
"""passbook core source form fields"""
SOURCE_FORM_FIELDS = ["name", "slug", "enabled"]
SOURCE_SERIALIZER_FIELDS = ["pk", "name", "slug", "enabled"]

View File

@ -8,12 +8,12 @@ from passbook.admin.views import (
debug,
flows,
groups,
inlets,
invitations,
outlets,
overview,
policies,
policy,
property_mapping,
providers,
sources,
stages,
users,
)
@ -39,49 +39,51 @@ urlpatterns = [
applications.ApplicationDeleteView.as_view(),
name="application-delete",
),
# Inlets
path("inlets/", inlets.InletListView.as_view(), name="inlets"),
path("inlets/create/", inlets.InletCreateView.as_view(), name="inlet-create"),
# Sources
path("sources/", sources.SourceListView.as_view(), name="sources"),
path("sources/create/", sources.SourceCreateView.as_view(), name="source-create"),
path(
"inlets/<uuid:pk>/update/",
inlets.InletUpdateView.as_view(),
name="inlet-update",
"sources/<uuid:pk>/update/",
sources.SourceUpdateView.as_view(),
name="source-update",
),
path(
"inlets/<uuid:pk>/delete/",
inlets.InletDeleteView.as_view(),
name="inlet-delete",
"sources/<uuid:pk>/delete/",
sources.SourceDeleteView.as_view(),
name="source-delete",
),
# Policies
path("policies/", policies.PolicyListView.as_view(), name="policies"),
path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"),
path("policies/", policy.PolicyListView.as_view(), name="policies"),
path("policies/create/", policy.PolicyCreateView.as_view(), name="policy-create"),
path(
"policies/<uuid:pk>/update/",
policies.PolicyUpdateView.as_view(),
policy.PolicyUpdateView.as_view(),
name="policy-update",
),
path(
"policies/<uuid:pk>/delete/",
policies.PolicyDeleteView.as_view(),
policy.PolicyDeleteView.as_view(),
name="policy-delete",
),
path(
"policies/<uuid:pk>/test/",
policies.PolicyTestView.as_view(),
name="policy-test",
"policies/<uuid:pk>/test/", policy.PolicyTestView.as_view(), name="policy-test"
),
# Outlets
path("outlets/", outlets.OutletListView.as_view(), name="outlets"),
path("outlets/create/", outlets.OutletCreateView.as_view(), name="outlet-create",),
# Providers
path("providers/", providers.ProviderListView.as_view(), name="providers"),
path(
"outlets/<int:pk>/update/",
outlets.OutletUpdateView.as_view(),
name="outlet-update",
"providers/create/",
providers.ProviderCreateView.as_view(),
name="provider-create",
),
path(
"outlets/<int:pk>/delete/",
outlets.OutletDeleteView.as_view(),
name="outlet-delete",
"providers/<int:pk>/update/",
providers.ProviderUpdateView.as_view(),
name="provider-update",
),
path(
"providers/<int:pk>/delete/",
providers.ProviderDeleteView.as_view(),
name="provider-delete",
),
# Stages
path("stages/", stages.StageListView.as_view(), name="stages"),

View File

@ -5,9 +5,8 @@ from django.views.generic import TemplateView
from passbook import __version__
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.policies.models import Policy
from passbook.root.celery import CELERY_APP
from passbook.stages.invitation.models import Invitation
@ -28,14 +27,16 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
kwargs["application_count"] = len(Application.objects.all())
kwargs["policy_count"] = len(Policy.objects.all())
kwargs["user_count"] = len(User.objects.all())
kwargs["outlet_count"] = len(Outlet.objects.all())
kwargs["inlet_count"] = len(Inlet.objects.all())
kwargs["provider_count"] = len(Provider.objects.all())
kwargs["source_count"] = len(Source.objects.all())
kwargs["stage_count"] = len(Stage.objects.all())
kwargs["flow_count"] = len(Flow.objects.all())
kwargs["invitation_count"] = len(Invitation.objects.all())
kwargs["version"] = __version__
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(
Policy.objects.filter(policymodel__isnull=True)
)

View File

@ -13,10 +13,10 @@ from django.views.generic.detail import DetailView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
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.views import CreateAssignPermView
from passbook.policies.engine import PolicyEngine
from passbook.policies.models import Policy
class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView):

View File

@ -1,4 +1,4 @@
"""passbook Inlet administration"""
"""passbook Provider administration"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
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 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.views import CreateAssignPermView
class InletListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all inlets"""
class ProviderListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all providers"""
model = Inlet
permission_required = "passbook_core.view_inlet"
ordering = "name"
paginate_by = 40
template_name = "administration/inlet/list.html"
model = Provider
permission_required = "passbook_core.add_provider"
template_name = "administration/provider/list.html"
paginate_by = 10
ordering = "id"
def get_context_data(self, **kwargs):
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)
@ -35,40 +35,40 @@ class InletListView(LoginRequiredMixin, PermissionListMixin, ListView):
return super().get_queryset().select_subclasses()
class InletCreateView(
class ProviderCreateView(
SuccessMessageMixin,
LoginRequiredMixin,
DjangoPermissionRequiredMixin,
CreateAssignPermView,
):
"""Create new Inlet"""
"""Create new Provider"""
model = Inlet
permission_required = "passbook_core.add_inlet"
model = Provider
permission_required = "passbook_core.add_provider"
template_name = "generic/create.html"
success_url = reverse_lazy("passbook_admin:inlets")
success_message = _("Successfully created Inlet")
success_url = reverse_lazy("passbook_admin:providers")
success_message = _("Successfully created Provider")
def get_form_class(self):
inlet_type = self.request.GET.get("type")
model = next(x for x in all_subclasses(Inlet) if x.__name__ == inlet_type)
provider_type = self.request.GET.get("type")
model = next(x for x in all_subclasses(Provider) if x.__name__ == provider_type)
if not model:
raise Http404
return path_to_class(model.form)
class InletUpdateView(
class ProviderUpdateView(
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
):
"""Update inlet"""
"""Update provider"""
model = Inlet
permission_required = "passbook_core.change_inlet"
model = Provider
permission_required = "passbook_core.change_provider"
template_name = "generic/update.html"
success_url = reverse_lazy("passbook_admin:inlets")
success_message = _("Successfully updated Inlet")
success_url = reverse_lazy("passbook_admin:providers")
success_message = _("Successfully updated Provider")
def get_form_class(self):
form_class_path = self.get_object().form
@ -77,25 +77,29 @@ class InletUpdateView(
def get_object(self, queryset=None):
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
):
"""Delete inlet"""
"""Delete provider"""
model = Inlet
permission_required = "passbook_core.delete_inlet"
model = Provider
permission_required = "passbook_core.delete_provider"
template_name = "generic/delete.html"
success_url = reverse_lazy("passbook_admin:inlets")
success_message = _("Successfully deleted Inlet")
success_url = reverse_lazy("passbook_admin:providers")
success_message = _("Successfully deleted Provider")
def get_object(self, queryset=None):
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):

View File

@ -1,4 +1,4 @@
"""passbook Outlet administration"""
"""passbook Source administration"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
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 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.views import CreateAssignPermView
class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all outlets"""
class SourceListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all sources"""
model = Outlet
permission_required = "passbook_core.add_outlet"
template_name = "administration/outlet/list.html"
paginate_by = 10
ordering = "id"
model = Source
permission_required = "passbook_core.view_source"
ordering = "name"
paginate_by = 40
template_name = "administration/source/list.html"
def get_context_data(self, **kwargs):
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)
@ -35,40 +35,40 @@ class OutletListView(LoginRequiredMixin, PermissionListMixin, ListView):
return super().get_queryset().select_subclasses()
class OutletCreateView(
class SourceCreateView(
SuccessMessageMixin,
LoginRequiredMixin,
DjangoPermissionRequiredMixin,
CreateAssignPermView,
):
"""Create new Outlet"""
"""Create new Source"""
model = Outlet
permission_required = "passbook_core.add_outlet"
model = Source
permission_required = "passbook_core.add_source"
template_name = "generic/create.html"
success_url = reverse_lazy("passbook_admin:outlets")
success_message = _("Successfully created Outlet")
success_url = reverse_lazy("passbook_admin:sources")
success_message = _("Successfully created Source")
def get_form_class(self):
outlet_type = self.request.GET.get("type")
model = next(x for x in all_subclasses(Outlet) if x.__name__ == outlet_type)
source_type = self.request.GET.get("type")
model = next(x for x in all_subclasses(Source) if x.__name__ == source_type)
if not model:
raise Http404
return path_to_class(model.form)
class OutletUpdateView(
class SourceUpdateView(
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
):
"""Update outlet"""
"""Update source"""
model = Outlet
permission_required = "passbook_core.change_outlet"
model = Source
permission_required = "passbook_core.change_source"
template_name = "generic/update.html"
success_url = reverse_lazy("passbook_admin:outlets")
success_message = _("Successfully updated Outlet")
success_url = reverse_lazy("passbook_admin:sources")
success_message = _("Successfully updated Source")
def get_form_class(self):
form_class_path = self.get_object().form
@ -77,25 +77,25 @@ class OutletUpdateView(
def get_object(self, queryset=None):
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
):
"""Delete outlet"""
"""Delete source"""
model = Outlet
permission_required = "passbook_core.delete_outlet"
model = Source
permission_required = "passbook_core.delete_source"
template_name = "generic/delete.html"
success_url = reverse_lazy("passbook_admin:outlets")
success_message = _("Successfully deleted Outlet")
success_url = reverse_lazy("passbook_admin:sources")
success_message = _("Successfully deleted Source")
def get_object(self, queryset=None):
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):

View File

@ -16,7 +16,7 @@ from guardian.mixins import (
)
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
@ -92,12 +92,12 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
permission_required = "passbook_core.reset_user_password"
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)
# 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(
reverse("passbook_flows:default-recovery", kwargs={"token": token.uuid})
reverse("passbook_flows:default-recovery", kwargs={"nonce": nonce.uuid})
)
messages.success(
request, _("Password reset link: <pre>%(link)s</pre>" % {"link": link})

View File

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

View File

@ -9,18 +9,12 @@ from structlog import get_logger
from passbook.api.permissions import CustomObjectPermissions
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.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.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.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet
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.password.api import PasswordPolicyViewSet
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.email.api import EmailStageViewSet
from passbook.stages.identification.api import IdentificationStageViewSet
@ -57,15 +57,9 @@ router.register("core/users", UserViewSet)
router.register("audit/events", EventViewSet)
router.register("inlets/all", InletViewSet)
router.register("inlets/ldap", LDAPInletViewSet)
router.register("inlets/oauth", OAuthInletViewSet)
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("sources/all", SourceViewSet)
router.register("sources/ldap", LDAPSourceViewSet)
router.register("sources/oauth", OAuthSourceViewSet)
router.register("policies/all", PolicyViewSet)
router.register("policies/bindings", PolicyBindingViewSet)
@ -75,6 +69,12 @@ router.register("policies/password", PasswordPolicyViewSet)
router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet)
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/ldap", LDAPPropertyMappingViewSet)
router.register("propertymappings/saml", SAMLPropertyMappingViewSet)

View File

@ -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
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name="Event",
name="AuditEntry",
fields=[
(
"uuid",
@ -33,16 +33,15 @@ class Migration(migrations.Migration):
"action",
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"),
("login", "login"),
("login_failed", "login_failed"),
("logout", "logout"),
("authorize_application", "authorize_application"),
("suspicious_request", "suspicious_request"),
("sign_up", "sign_up"),
("password_reset", "password_reset"),
("invitation_created", "invitation_created"),
("invitation_used", "invitation_used"),
]
),
),
@ -54,7 +53,7 @@ class Migration(migrations.Migration):
blank=True, default=dict
),
),
("client_ip", models.GenericIPAddressField(null=True)),
("request_ip", models.GenericIPAddressField()),
("created", models.DateTimeField(auto_now_add=True)),
(
"user",
@ -66,8 +65,8 @@ class Migration(migrations.Migration):
),
],
options={
"verbose_name": "Audit Event",
"verbose_name_plural": "Audit Events",
"verbose_name": "Audit Entry",
"verbose_name_plural": "Audit Entries",
},
),
]

View File

@ -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",),
]

View File

@ -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"),
]
),
),
]

View File

@ -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),
),
]

View File

@ -5,7 +5,7 @@ from django.test import TestCase
from guardian.shortcuts import get_anonymous_user
from passbook.audit.models import Event, EventAction
from passbook.policies.models import Policy
from passbook.core.models import Policy
class TestAuditEvent(TestCase):

View File

@ -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"

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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",),
),
]

View File

@ -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")

View File

@ -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",
]

View File

@ -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

View File

@ -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/"

View File

@ -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",),
),
]

View File

@ -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})
)

View File

@ -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

View File

@ -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 = ""

View File

@ -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"

View File

@ -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",),
),
]

View File

@ -1,6 +0,0 @@
"""saml provider settings"""
PASSBOOK_PROVIDERS_SAML_PROCESSORS = [
"passbook.channels.out_saml.processors.generic",
"passbook.channels.out_saml.processors.salesforce",
]

View File

@ -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/"

View File

@ -16,7 +16,7 @@ class ApplicationSerializer(ModelSerializer):
"name",
"slug",
"skip_authorization",
"outlet",
"provider",
"meta_launch_url",
"meta_icon_url",
"meta_description",

View File

@ -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()

View File

@ -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()

View File

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

View File

@ -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()

View File

@ -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()

View File

@ -3,14 +3,14 @@ from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
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):
"""Application Form"""
outlet = forms.ModelChoiceField(
queryset=Outlet.objects.all().order_by("pk").select_subclasses(),
provider = forms.ModelChoiceField(
queryset=Provider.objects.all().order_by("pk").select_subclasses(),
required=False,
)
@ -21,7 +21,7 @@ class ApplicationForm(forms.ModelForm):
"name",
"slug",
"skip_authorization",
"outlet",
"provider",
"meta_launch_url",
"meta_icon_url",
"meta_description",

View File

@ -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
@ -7,7 +7,6 @@ import django.contrib.auth.validators
import django.contrib.postgres.fields.jsonb
import django.db.models.deletion
import django.utils.timezone
import guardian.mixins
from django.conf import settings
from django.db import migrations, models
@ -20,7 +19,6 @@ class Migration(migrations.Migration):
dependencies = [
("auth", "0011_update_proxy_permissions"),
("passbook_policies", "0001_initial"),
]
operations = [
@ -107,41 +105,63 @@ class Migration(migrations.Migration):
),
),
("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)),
(
"attributes",
django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict
),
),
],
options={"permissions": (("reset_user_password", "Reset Password"),),},
bases=(guardian.mixins.GuardianUserMixin, models.Model),
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
managers=[("objects", django.contrib.auth.models.UserManager()),],
),
migrations.CreateModel(
name="Inlet",
name="Policy",
fields=[
("created", models.DateTimeField(auto_now_add=True)),
("last_updated", models.DateTimeField(auto_now=True)),
(
"policybindingmodel_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
"uuid",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
to="passbook_policies.PolicyBindingModel",
),
),
("name", models.TextField(help_text="Inlet's display Name.")),
("name", models.TextField(blank=True, null=True)),
(
"slug",
models.SlugField(help_text="Internal source name, used in URLs."),
"action",
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(
name="PropertyMapping",
@ -156,7 +176,6 @@ class Migration(migrations.Migration):
),
),
("name", models.TextField()),
("expression", models.TextField()),
],
options={
"verbose_name": "Property Mapping",
@ -164,38 +183,74 @@ class Migration(migrations.Migration):
},
),
migrations.CreateModel(
name="UserInletConnection",
name="DebugPolicy",
fields=[
(
"id",
models.AutoField(
"policy_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("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,
to="passbook_core.Policy",
),
),
("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(
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=[
(
"id",
@ -215,7 +270,7 @@ class Migration(migrations.Migration):
],
),
migrations.CreateModel(
name="Token",
name="Nonce",
fields=[
(
"uuid",
@ -229,11 +284,10 @@ class Migration(migrations.Migration):
(
"expires",
models.DateTimeField(
default=passbook.core.models.default_token_duration
default=passbook.core.models.default_nonce_duration
),
),
("expiring", models.BooleanField(default=True)),
("description", models.TextField(blank=True, default="")),
(
"user",
models.ForeignKey(
@ -242,14 +296,36 @@ class Migration(migrations.Migration):
),
),
],
options={"verbose_name": "Token", "verbose_name_plural": "Tokens",},
options={"verbose_name": "Nonce", "verbose_name_plural": "Nonces",},
),
migrations.AddField(
model_name="inlet",
name="property_mappings",
field=models.ManyToManyField(
blank=True, default=None, to="passbook_core.PropertyMapping"
),
migrations.CreateModel(
name="Invitation",
fields=[
(
"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(
name="Group",
@ -265,7 +341,7 @@ class Migration(migrations.Migration):
),
("name", models.CharField(max_length=80, verbose_name="name")),
(
"attributes",
"tags",
django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict
),
@ -283,57 +359,11 @@ class Migration(migrations.Migration):
],
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(
model_name="user",
name="groups",
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(
model_name="user",
name="user_permissions",
@ -347,33 +377,74 @@ class Migration(migrations.Migration):
),
),
migrations.CreateModel(
name="PropertyMappingBinding",
name="UserSourceConnection",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
editable=False,
"id",
models.AutoField(
auto_created=True,
primary_key=True,
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(
on_delete=django.db.models.deletion.CASCADE,
to="passbook_core.Outlet",
to=settings.AUTH_USER_MODEL,
),
),
(
"property_mapping",
"source",
models.ForeignKey(
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"
),
),
]

View File

@ -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"),)},
),
]

View File

@ -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=""),
),
]

View File

@ -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
),
),
]

View File

@ -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 = []

View File

@ -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",),
]

View File

@ -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 = []

View File

@ -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,
),
]

View File

@ -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",
),
]

View File

@ -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),
),
]

View File

@ -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."),
),
]

View File

@ -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=""),
),
]

View File

@ -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)]

View File

@ -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",),
]

View File

@ -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",),
]

View File

@ -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",),
]

View File

@ -10,6 +10,7 @@ from django.db import models
from django.http import HttpRequest
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_prometheus.models import ExportModelOperationsMixin
from guardian.mixins import GuardianUserMixin
from jinja2 import Undefined
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.types import UILoginButton, UIUserSettings
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()
NATIVE_ENVIRONMENT = NativeEnvironment()
def default_token_duration():
"""Default duration a Token is valid"""
def default_nonce_duration():
"""Default duration a Nonce is valid"""
return now() + timedelta(minutes=30)
class Group(UUIDModel):
class Group(ExportModelOperationsMixin("group"), UUIDModel):
"""Custom Group model which supports a basic hierarchy"""
name = models.CharField(_("name"), max_length=80)
@ -53,13 +55,13 @@ class Group(UUIDModel):
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"""
uuid = models.UUIDField(default=uuid4, editable=False)
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")
password_change_date = models.DateTimeField(auto_now_add=True)
@ -76,7 +78,29 @@ class User(GuardianUserMixin, AbstractUser):
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
needs an Application record. Other authentication types can subclass this Model to
add custom fields and other properties"""
@ -84,8 +108,8 @@ class Application(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)
outlet = models.OneToOneField(
"Outlet", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
provider = models.OneToOneField(
"Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
)
meta_launch_url = models.URLField(default="", blank=True)
@ -95,20 +119,20 @@ class Application(PolicyBindingModel):
objects = InheritanceManager()
def get_outlet(self) -> Optional["Outlet"]:
"""Get casted outlet instance"""
if not self.outlet:
def get_provider(self) -> Optional[Provider]:
"""Get casted provider instance"""
if not self.provider:
return None
return Outlet.objects.get_subclass(pk=self.outlet.pk)
return Provider.objects.get_subclass(pk=self.provider.pk)
def __str__(self):
return self.name
class Inlet(PolicyBindingModel):
class Source(ExportModelOperationsMixin("source"), PolicyModel):
"""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."))
enabled = models.BooleanField(default=True)
@ -141,69 +165,56 @@ class Inlet(PolicyBindingModel):
return self.name
class UserInletConnection(CreatedUpdatedModel):
"""Connection between User and Inlet."""
class UserSourceConnection(CreatedUpdatedModel):
"""Connection between User and Source."""
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:
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"""
expires = models.DateTimeField(default=default_token_duration)
user = models.ForeignKey("User", on_delete=models.CASCADE, related_name="+")
expires = models.DateTimeField(default=default_nonce_duration)
user = models.ForeignKey("User", on_delete=models.CASCADE)
expiring = models.BooleanField(default=True)
description = models.TextField(default="", blank=True)
@property
def is_expired(self) -> bool:
"""Check if token is expired yet."""
"""Check if nonce is expired yet."""
return now() > self.expires
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:
verbose_name = _("Token")
verbose_name_plural = _("Tokens")
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"),)
verbose_name = _("Nonce")
verbose_name_plural = _("Nonces")
class PropertyMapping(UUIDModel):

View File

@ -17,7 +17,7 @@ password_changed = Signal(providing_args=["user", "password"])
# pylint: disable=unused-argument
def invalidate_policy_cache(sender, instance, **_):
"""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
if isinstance(instance, Policy):

View File

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

View File

@ -34,17 +34,17 @@
</ul>
</section>
{% endif %}
{% user_inlets as user_inlets_loc %}
{% if user_inlets_loc %}
{% user_sources as user_sources_loc %}
{% if user_sources_loc %}
<section class="pf-c-nav__section">
<h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2>
<ul class="pf-c-nav__list">
{% for inlet in user_inlets_loc %}
{% for source in user_sources_loc %}
<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 %}">
<i class="{{ inlet.icon }}"></i>
{{ inlet.name }}
<i class="{{ source.icon }}"></i>
{{ source.name }}
</a>
</li>
{% endfor %}

View File

@ -4,7 +4,7 @@ from typing import Iterable, List
from django import template
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.flows.models import Stage
from passbook.policies.engine import PolicyEngine
@ -27,14 +27,14 @@ def user_stages(context: RequestContext) -> List[UIUserSettings]:
@register.simple_tag(takes_context=True)
def user_inlets(context: RequestContext) -> List[UIUserSettings]:
"""Return a list of all inlets which are enabled for the user"""
def user_sources(context: RequestContext) -> List[UIUserSettings]:
"""Return a list of all sources which are enabled for the user"""
user = context.get("request").user
_all_inlets: Iterable[(Inlet)] = (
(Inlet).objects.filter(enabled=True).select_subclasses()
_all_sources: Iterable[Source] = (
Source.objects.filter(enabled=True).select_subclasses()
)
matching_inlets: List[UIUserSettings] = []
for source in _all_inlets:
matching_sources: List[UIUserSettings] = []
for source in _all_sources:
user_settings = source.ui_user_settings
if not user_settings:
continue
@ -43,5 +43,5 @@ def user_inlets(context: RequestContext) -> List[UIUserSettings]:
)
policy_engine.build()
if policy_engine.passing:
matching_inlets.append(user_settings)
return matching_inlets
matching_sources.append(user_settings)
return matching_sources

View File

@ -6,7 +6,7 @@ from django.http import HttpRequest
from django.utils.translation import gettext as _
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
LOGGER = get_logger()
@ -14,19 +14,22 @@ LOGGER = get_logger()
class AccessMixin:
"""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: HttpRequest = None
def outlet_to_application(self, outlet: Outlet) -> Application:
"""Lookup application assigned to outlet, throw error if no application assigned"""
def provider_to_application(self, provider: Provider) -> Application:
"""Lookup application assigned to provider, throw error if no application assigned"""
try:
return outlet.application
return provider.application
except Application.DoesNotExist as exc:
messages.error(
self.request,
_('Outlet "%(name)s" has no application assigned' % {"name": outlet}),
_(
'Provider "%(name)s" has no application assigned'
% {"name": provider}
),
)
raise exc

View File

@ -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
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):
initial = True
@ -27,22 +41,27 @@ class Migration(migrations.Migration):
),
),
("name", models.TextField()),
(
"certificate_data",
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.",
),
),
("certificate_data", models.TextField()),
("key_data", models.TextField(blank=True, default="")),
],
options={
"verbose_name": "Certificate-Key Pair",
"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.",
),
),
]

View File

@ -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
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
("passbook_policies", "__first__"),
("passbook_policies", "0003_auto_20200508_1642"),
]
operations = [
@ -33,12 +33,10 @@ class Migration(migrations.Migration):
"designation",
models.CharField(
choices=[
("authentication", "Authentication"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("password_change", "Password Change"),
("AUTHENTICATION", "authentication"),
("ENROLLMENT", "enrollment"),
("RECOVERY", "recovery"),
("PASSWORD_CHANGE", "password_change"),
],
max_length=100,
),

View File

@ -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,
),
),
]

View File

@ -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,
),
),
]

View File

@ -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,
),
),
]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,8 +6,7 @@ from django.utils.translation import gettext as _
from requests import get
from structlog import get_logger
from passbook.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult
from passbook.core.models import Policy, PolicyResult, User
LOGGER = get_logger()
@ -20,14 +19,14 @@ class HaveIBeenPwendPolicy(Policy):
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
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."""
# Only check if password is being set
if not hasattr(request.user, "__password__"):
if not hasattr(user, "__password__"):
return PolicyResult(True)
password = getattr(request.user, "__password__")
password = getattr(user, "__password__")
pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec
url = "https://api.pwnedpasswords.com/range/%s" % pw_hash[:5]
result = get(url).text

View File

@ -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
@ -10,30 +10,11 @@ class Migration(migrations.Migration):
initial = True
dependencies = []
dependencies = [
("passbook_core", "0011_auto_20200222_1822"),
]
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(
name="PolicyBinding",
fields=[
@ -53,7 +34,7 @@ class Migration(migrations.Migration):
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="passbook_policies.Policy",
to="passbook_core.Policy",
),
),
],
@ -77,17 +58,12 @@ class Migration(migrations.Migration):
(
"policies",
models.ManyToManyField(
blank=True,
related_name="_policybindingmodel_policies_+",
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(
model_name="policybinding",

View File

@ -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",
},
),
]

View File

@ -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",
),
),
]

View File

@ -1,30 +1,9 @@
"""Policy base models"""
from django.db import models
from django.utils.translation import gettext_lazy as _
from model_utils.managers import InheritanceManager
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
from passbook.policies.exceptions import PolicyException
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()
from passbook.core.models import Policy
from passbook.lib.models import UUIDModel
class PolicyBindingModel(models.Model):

View File

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

View File

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

View File

@ -6,9 +6,8 @@ from typing import Optional
from django.core.cache import cache
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.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger()

View File

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

View File

@ -2,9 +2,8 @@
from django.db import models
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.policies.models import Policy
from passbook.policies.types import PolicyRequest, PolicyResult

View File

@ -2,10 +2,9 @@
from django.core.cache import cache
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.engine import PolicyEngine
from passbook.policies.models import Policy
class PolicyTestEngine(TestCase):

View File

@ -1,17 +1,17 @@
"""ApplicationGatewayOutlet API Views"""
"""ApplicationGatewayProvider API Views"""
from oauth2_provider.generators import generate_client_id, generate_client_secret
from oidc_provider.models import Client
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet
from passbook.channels.out_app_gw.models import ApplicationGatewayOutlet
from passbook.channels.out_oidc.api import OpenIDOutletSerializer
from passbook.providers.app_gw.models import ApplicationGatewayProvider
from passbook.providers.oidc.api import OpenIDProviderSerializer
class ApplicationGatewayOutletSerializer(ModelSerializer):
"""ApplicationGatewayOutlet Serializer"""
class ApplicationGatewayProviderSerializer(ModelSerializer):
"""ApplicationGatewayProvider Serializer"""
client = OpenIDOutletSerializer()
client = OpenIDProviderSerializer()
def create(self, validated_data):
instance = super().create(validated_data)
@ -33,13 +33,13 @@ class ApplicationGatewayOutletSerializer(ModelSerializer):
class Meta:
model = ApplicationGatewayOutlet
model = ApplicationGatewayProvider
fields = ["pk", "name", "internal_host", "external_host", "client"]
read_only_fields = ["client"]
class ApplicationGatewayOutletViewSet(ModelViewSet):
"""ApplicationGatewayOutlet Viewset"""
class ApplicationGatewayProviderViewSet(ModelViewSet):
"""ApplicationGatewayProvider Viewset"""
queryset = ApplicationGatewayOutlet.objects.all()
serializer_class = ApplicationGatewayOutletSerializer
queryset = ApplicationGatewayProvider.objects.all()
serializer_class = ApplicationGatewayProviderSerializer

View File

@ -5,7 +5,7 @@ from django.apps import AppConfig
class PassbookApplicationApplicationGatewayConfig(AppConfig):
"""passbook app_gw app"""
name = "passbook.channels.out_app_gw"
label = "passbook_channels_out_app_gw"
verbose_name = "passbook Outlets.Application Security Gateway"
name = "passbook.providers.app_gw"
label = "passbook_providers_app_gw"
verbose_name = "passbook Providers.Application Security Gateway"
mountpoint = "application/gateway/"

View File

@ -3,11 +3,11 @@ from django import forms
from oauth2_provider.generators import generate_client_id, generate_client_secret
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):
"""Security Gateway Outlet form"""
class ApplicationGatewayProviderForm(forms.ModelForm):
"""Security Gateway Provider form"""
def save(self, *args, **kwargs):
if not self.instance.pk:
@ -31,7 +31,7 @@ class ApplicationGatewayOutletForm(forms.ModelForm):
class Meta:
model = ApplicationGatewayOutlet
model = ApplicationGatewayProvider
fields = ["name", "internal_host", "external_host"]
widgets = {
"name": forms.TextInput(),

View File

@ -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",),
),
]

View File

@ -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",),
]

View File

@ -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
from django.db import migrations, models
@ -9,28 +9,28 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
("passbook_core", "__first__"),
("passbook_core", "0005_merge_20191025_2022"),
("oidc_provider", "0026_client_multiple_response_types"),
("passbook_providers_app_gw", "0002_auto_20191111_1703"),
]
operations = [
migrations.CreateModel(
name="ApplicationGatewayOutlet",
name="ApplicationGatewayProvider",
fields=[
(
"outlet_ptr",
"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.Outlet",
to="passbook_core.Provider",
),
),
("name", models.TextField()),
("internal_host", models.TextField()),
("external_host", models.TextField()),
("host", models.TextField()),
(
"client",
models.ForeignKey(
@ -40,9 +40,9 @@ class Migration(migrations.Migration):
),
],
options={
"verbose_name": "Application Gateway Outlet",
"verbose_name_plural": "Application Gateway Outlets",
"verbose_name": "Application Gateway Provider",
"verbose_name_plural": "Application Gateway Providers",
},
bases=("passbook_core.outlet",),
bases=("passbook_core.provider",),
),
]

View File

@ -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,
),
]

View File

@ -9,12 +9,12 @@ from django.utils.translation import gettext as _
from oidc_provider.models import Client
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
class ApplicationGatewayOutlet(Outlet):
"""This outlet uses oauth2_proxy with the OIDC Outlet."""
class ApplicationGatewayProvider(Provider):
"""This provider uses oauth2_proxy with the OIDC Provider."""
name = models.TextField()
internal_host = models.TextField()
@ -22,7 +22,7 @@ class ApplicationGatewayOutlet(Outlet):
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]:
"""return template and context modal with URLs for authorize, token, openid-config, etc"""
@ -32,7 +32,7 @@ class ApplicationGatewayOutlet(Outlet):
)
return render_to_string(
"app_gw/setup_modal.html",
{"outlet": self, "cookie_secret": cookie_secret, "version": __version__},
{"provider": self, "cookie_secret": cookie_secret, "version": __version__},
)
def __str__(self):
@ -40,5 +40,5 @@ class ApplicationGatewayOutlet(Outlet):
class Meta:
verbose_name = _("Application Gateway Outlet")
verbose_name_plural = _("Application Gateway Outlets")
verbose_name = _("Application Gateway Provider")
verbose_name_plural = _("Application Gateway Providers")

Some files were not shown because too many files have changed in this diff Show More