diff --git a/passbook/admin/forms/rule.py b/passbook/admin/forms/policies.py similarity index 67% rename from passbook/admin/forms/rule.py rename to passbook/admin/forms/policies.py index a633a83e8..9bca84a98 100644 --- a/passbook/admin/forms/rule.py +++ b/passbook/admin/forms/policies.py @@ -4,7 +4,7 @@ from django import forms from passbook.core.models import User -class RuleTestForm(forms.Form): - """Form to test rule against user""" +class PolicyTestForm(forms.Form): + """Form to test policies against user""" user = forms.ModelChoiceField(queryset=User.objects.all()) diff --git a/passbook/admin/templates/administration/base.html b/passbook/admin/templates/administration/base.html index 4dac1922f..7ed02b095 100644 --- a/passbook/admin/templates/administration/base.html +++ b/passbook/admin/templates/administration/base.html @@ -20,8 +20,8 @@
  • {% trans 'Factors' %}
  • -
  • - {% trans 'Rules' %} +
  • + {% trans 'Policies' %}
  • {% trans 'Invitations' %} diff --git a/passbook/admin/templates/administration/overview.html b/passbook/admin/templates/administration/overview.html index 6ebcaa759..8d0a9e9a8 100644 --- a/passbook/admin/templates/administration/overview.html +++ b/passbook/admin/templates/administration/overview.html @@ -31,11 +31,11 @@
    @@ -53,4 +53,4 @@
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/passbook/admin/templates/administration/rule/list.html b/passbook/admin/templates/administration/policy/list.html similarity index 66% rename from passbook/admin/templates/administration/rule/list.html rename to passbook/admin/templates/administration/policy/list.html index d0a324ffe..51218e286 100644 --- a/passbook/admin/templates/administration/rule/list.html +++ b/passbook/admin/templates/administration/policy/list.html @@ -9,7 +9,7 @@ {% block content %}
    -

    {% trans "Rules" %}

    +

    {% trans "Policies" %}

    @@ -31,18 +31,18 @@ - {% for rule in object_list %} + {% for policy in object_list %} - {{ rule.name }} - {{ rule|fieldtype }} + {{ policy.name }} + {{ policy|fieldtype }} - {% trans 'Edit' %} - {% trans 'Test' %} - {% trans 'Delete' %} + {% trans 'Edit' %} + {% trans 'Test' %} + {% trans 'Delete' %} {% endfor %}
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/passbook/admin/templates/administration/policy/test.html b/passbook/admin/templates/administration/policy/test.html new file mode 100644 index 000000000..6a5ddcbb1 --- /dev/null +++ b/passbook/admin/templates/administration/policy/test.html @@ -0,0 +1,7 @@ +{% extends 'generic/form.html' %} + +{% load i18n %} + +{% block above_form %} +

    {% blocktrans with policy=policy %}Test policy {{ policy }}{% endblocktrans %}

    +{% endblock %} diff --git a/passbook/admin/templates/administration/rule/test.html b/passbook/admin/templates/administration/rule/test.html deleted file mode 100644 index 5d8a9f4f6..000000000 --- a/passbook/admin/templates/administration/rule/test.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'generic/form.html' %} - -{% load i18n %} - -{% block above_form %} -

    {% blocktrans with rule=rule %}Test rule {{ rule }}{% endblocktrans %}

    -{% endblock %} \ No newline at end of file diff --git a/passbook/admin/urls.py b/passbook/admin/urls.py index 941d99cf2..77b48e419 100644 --- a/passbook/admin/urls.py +++ b/passbook/admin/urls.py @@ -3,7 +3,7 @@ from django.urls import include, path from rest_framework_swagger.views import get_swagger_view from passbook.admin.views import (applications, audit, factors, groups, - invitations, overview, providers, rules, + invitations, overview, policy, providers, sources, users) schema_view = get_swagger_view(title='passbook Admin Internal API') @@ -25,12 +25,12 @@ urlpatterns = [ path('sources/create/', sources.SourceCreateView.as_view(), name='source-create'), path('sources//update/', sources.SourceUpdateView.as_view(), name='source-update'), path('sources//delete/', sources.SourceDeleteView.as_view(), name='source-delete'), - # Rules - path('rules/', rules.RuleListView.as_view(), name='rules'), - path('rules/create/', rules.RuleCreateView.as_view(), name='rule-create'), - path('rules//update/', rules.RuleUpdateView.as_view(), name='rule-update'), - path('rules//delete/', rules.RuleDeleteView.as_view(), name='rule-delete'), - path('rules//test/', rules.RuleTestView.as_view(), name='rule-test'), + # Policies + path('policies/', policy.PolicyListView.as_view(), name='policies'), + path('policies/create/', policy.PolicyCreateView.as_view(), name='policy-create'), + path('policies//update/', policy.PolicyUpdateView.as_view(), name='policy-update'), + path('policies//delete/', policy.PolicyDeleteView.as_view(), name='policy-delete'), + path('policies//test/', policy.PolicyTestView.as_view(), name='policy-test'), # Providers path('providers/', providers.ProviderListView.as_view(), name='providers'), path('providers/create/', diff --git a/passbook/admin/views/overview.py b/passbook/admin/views/overview.py index 49a402736..504b863b1 100644 --- a/passbook/admin/views/overview.py +++ b/passbook/admin/views/overview.py @@ -2,7 +2,7 @@ from django.views.generic import TemplateView from passbook.admin.mixins import AdminRequiredMixin -from passbook.core.models import Application, Provider, Rule, User +from passbook.core.models import Application, Policy, Provider, User class AdministrationOverviewView(AdminRequiredMixin, TemplateView): @@ -12,7 +12,7 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView): def get_context_data(self, **kwargs): kwargs['application_count'] = len(Application.objects.all()) - kwargs['rule_count'] = len(Rule.objects.all()) + kwargs['policy_count'] = len(Policy.objects.all()) kwargs['user_count'] = len(User.objects.all()) kwargs['provider_count'] = len(Provider.objects.all()) return super().get_context_data(**kwargs) diff --git a/passbook/admin/views/policy.py b/passbook/admin/views/policy.py new file mode 100644 index 000000000..1bf29dac4 --- /dev/null +++ b/passbook/admin/views/policy.py @@ -0,0 +1,104 @@ +"""passbook Policy administration""" +from django.contrib import messages +from django.contrib.messages.views import SuccessMessageMixin +from django.http import Http404 +from django.urls import reverse_lazy +from django.utils.translation import ugettext as _ +from django.views.generic import (CreateView, DeleteView, FormView, ListView, + UpdateView) +from django.views.generic.detail import DetailView + +from passbook.admin.forms.policies import PolicyTestForm +from passbook.admin.mixins import AdminRequiredMixin +from passbook.core.models import Policy +from passbook.lib.utils.reflection import path_to_class + + +class PolicyListView(AdminRequiredMixin, ListView): + """Show list of all policys""" + + model = Policy + template_name = 'administration/policy/list.html' + + def get_context_data(self, **kwargs): + kwargs['types'] = { + x.__name__: x._meta.verbose_name for x in Policy.__subclasses__()} + return super().get_context_data(**kwargs) + + def get_queryset(self): + return super().get_queryset().order_by('order').select_subclasses() + + +class PolicyCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView): + """Create new Policy""" + + template_name = 'generic/create_inheritance.html' + success_url = reverse_lazy('passbook_admin:policys') + success_message = _('Successfully created Policy') + + def get_form_class(self): + policy_type = self.request.GET.get('type') + model = next(x for x in Policy.__subclasses__() + if x.__name__ == policy_type) + if not model: + raise Http404 + return path_to_class(model.form) + + +class PolicyUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView): + """Update policy""" + + model = Policy + template_name = 'generic/update.html' + success_url = reverse_lazy('passbook_admin:policys') + success_message = _('Successfully updated Policy') + + def get_form_class(self): + form_class_path = self.get_object().form + form_class = path_to_class(form_class_path) + return form_class + + def get_object(self, queryset=None): + return Policy.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() + + +class PolicyDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView): + """Delete policy""" + + model = Policy + template_name = 'generic/delete.html' + success_url = reverse_lazy('passbook_admin:policys') + success_message = _('Successfully updated Policy') + + def get_object(self, queryset=None): + return Policy.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() + + +class PolicyTestView(AdminRequiredMixin, DetailView, FormView): + """View to test policy(s)""" + + model = Policy + form_class = PolicyTestForm + template_name = 'administration/policy/test.html' + object = None + + def get_object(self, queryset=None): + return Policy.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() + + def get_context_data(self, **kwargs): + kwargs['policy'] = self.get_object() + return super().get_context_data(**kwargs) + + def post(self, *args, **kwargs): + self.object = self.get_object() + return super().post(*args, **kwargs) + + def form_valid(self, form): + policy = self.get_object() + user = form.cleaned_data.get('user') + result = policy.passes(user) + if result: + messages.success(self.request, _('User successfully passed policy.')) + else: + messages.error(self.request, _("User didn't pass policy.")) + return self.render_to_response(self.get_context_data(form=form, result=result)) diff --git a/passbook/admin/views/rules.py b/passbook/admin/views/rules.py deleted file mode 100644 index c4aa85510..000000000 --- a/passbook/admin/views/rules.py +++ /dev/null @@ -1,104 +0,0 @@ -"""passbook Rule administration""" -from django.contrib import messages -from django.contrib.messages.views import SuccessMessageMixin -from django.http import Http404 -from django.urls import reverse_lazy -from django.utils.translation import ugettext as _ -from django.views.generic import (CreateView, DeleteView, FormView, ListView, - UpdateView) -from django.views.generic.detail import DetailView - -from passbook.admin.forms.rule import RuleTestForm -from passbook.admin.mixins import AdminRequiredMixin -from passbook.core.models import Rule -from passbook.lib.utils.reflection import path_to_class - - -class RuleListView(AdminRequiredMixin, ListView): - """Show list of all rules""" - - model = Rule - template_name = 'administration/rule/list.html' - - def get_context_data(self, **kwargs): - kwargs['types'] = { - x.__name__: x._meta.verbose_name for x in Rule.__subclasses__()} - return super().get_context_data(**kwargs) - - def get_queryset(self): - return super().get_queryset().order_by('order').select_subclasses() - - -class RuleCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView): - """Create new Rule""" - - template_name = 'generic/create_inheritance.html' - success_url = reverse_lazy('passbook_admin:rules') - success_message = _('Successfully created Rule') - - def get_form_class(self): - rule_type = self.request.GET.get('type') - model = next(x for x in Rule.__subclasses__() - if x.__name__ == rule_type) - if not model: - raise Http404 - return path_to_class(model.form) - - -class RuleUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView): - """Update rule""" - - model = Rule - template_name = 'generic/update.html' - success_url = reverse_lazy('passbook_admin:rules') - success_message = _('Successfully updated Rule') - - def get_form_class(self): - form_class_path = self.get_object().form - form_class = path_to_class(form_class_path) - return form_class - - def get_object(self, queryset=None): - return Rule.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() - - -class RuleDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView): - """Delete rule""" - - model = Rule - template_name = 'generic/delete.html' - success_url = reverse_lazy('passbook_admin:rules') - success_message = _('Successfully updated Rule') - - def get_object(self, queryset=None): - return Rule.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() - - -class RuleTestView(AdminRequiredMixin, DetailView, FormView): - """View to test rule(s)""" - - model = Rule - form_class = RuleTestForm - template_name = 'administration/rule/test.html' - object = None - - def get_object(self, queryset=None): - return Rule.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first() - - def get_context_data(self, **kwargs): - kwargs['rule'] = self.get_object() - return super().get_context_data(**kwargs) - - def post(self, *args, **kwargs): - self.object = self.get_object() - return super().post(*args, **kwargs) - - def form_valid(self, form): - rule = self.get_object() - user = form.cleaned_data.get('user') - result = rule.passes(user) - if result: - messages.success(self.request, _('User successfully passed rule.')) - else: - messages.error(self.request, _("User didn't pass rule.")) - return self.render_to_response(self.get_context_data(form=form, result=result)) diff --git a/passbook/audit/migrations/0001_initial.py b/passbook/audit/migrations/0001_initial.py index d6b25b693..568b3d7d7 100644 --- a/passbook/audit/migrations/0001_initial.py +++ b/passbook/audit/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.3 on 2018-11-25 10:39 +# Generated by Django 2.1.7 on 2019-02-16 09:13 import uuid @@ -20,13 +20,32 @@ class Migration(migrations.Migration): name='AuditEntry', fields=[ ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('action', models.TextField()), + ('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'), ('invitation_created', 'invitation_created'), ('invitation_used', 'invitation_used')])), ('date', models.DateTimeField(auto_now_add=True)), ('app', models.TextField()), + ('_context', models.TextField()), + ('request_ip', models.GenericIPAddressField()), + ('created', models.DateTimeField(auto_now_add=True)), ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ], options={ - 'abstract': False, + 'verbose_name': 'Audit Entry', + 'verbose_name_plural': 'Audit Entries', }, ), + migrations.CreateModel( + name='LoginAttempt', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateField(auto_now_add=True)), + ('last_updated', models.DateTimeField(auto_now=True)), + ('target_uid', models.CharField(max_length=254)), + ('request_ip', models.GenericIPAddressField()), + ('attempts', models.IntegerField(default=1)), + ], + ), + migrations.AlterUniqueTogether( + name='loginattempt', + unique_together={('target_uid', 'request_ip', 'created')}, + ), ] diff --git a/passbook/audit/migrations/0002_auto_20181210_1039.py b/passbook/audit/migrations/0002_auto_20181210_1039.py deleted file mode 100644 index 67f88bbb6..000000000 --- a/passbook/audit/migrations/0002_auto_20181210_1039.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-10 10:39 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_audit', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='auditentry', - name='context', - field=models.TextField(default=''), - preserve_default=False, - ), - migrations.AddField( - model_name='auditentry', - name='request_ip', - field=models.GenericIPAddressField(default=''), - preserve_default=False, - ), - migrations.AlterField( - model_name='auditentry', - 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')]), - ), - ] diff --git a/passbook/audit/migrations/0003_auto_20181210_1213.py b/passbook/audit/migrations/0003_auto_20181210_1213.py deleted file mode 100644 index 16d7c103a..000000000 --- a/passbook/audit/migrations/0003_auto_20181210_1213.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-10 12:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_audit', '0002_auto_20181210_1039'), - ] - - operations = [ - migrations.AlterModelOptions( - name='auditentry', - options={'verbose_name': 'Audit Entry', 'verbose_name_plural': 'Audit Entries'}, - ), - migrations.RenameField( - model_name='auditentry', - old_name='context', - new_name='_context', - ), - migrations.AlterField( - model_name='auditentry', - 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'), ('invitation_used', 'invitation_used')]), - ), - ] diff --git a/passbook/audit/migrations/0004_auto_20181210_1348.py b/passbook/audit/migrations/0004_auto_20181210_1348.py deleted file mode 100644 index b1e151fc3..000000000 --- a/passbook/audit/migrations/0004_auto_20181210_1348.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-10 13:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_audit', '0003_auto_20181210_1213'), - ] - - operations = [ - migrations.AlterField( - model_name='auditentry', - 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'), ('invitation_created', 'invitation_created'), ('invitation_used', 'invitation_used')]), - ), - ] diff --git a/passbook/audit/migrations/0005_auditentry_created.py b/passbook/audit/migrations/0005_auditentry_created.py deleted file mode 100644 index 5ee9c9118..000000000 --- a/passbook/audit/migrations/0005_auditentry_created.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-11 15:00 - -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_audit', '0004_auto_20181210_1348'), - ] - - operations = [ - migrations.AddField( - model_name='auditentry', - name='created', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), - preserve_default=False, - ), - ] diff --git a/passbook/audit/migrations/0006_auto_20181218_1252.py b/passbook/audit/migrations/0006_auto_20181218_1252.py deleted file mode 100644 index 5317e3f6e..000000000 --- a/passbook/audit/migrations/0006_auto_20181218_1252.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-18 12:52 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_audit', '0005_auditentry_created'), - ] - - operations = [ - migrations.CreateModel( - name='LoginAttempt', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateField(auto_now_add=True)), - ('last_updated', models.DateTimeField(auto_now=True)), - ('target_uid', models.CharField(max_length=254)), - ('request_ip', models.GenericIPAddressField()), - ('attempts', models.IntegerField(default=1)), - ], - ), - migrations.AlterUniqueTogether( - name='loginattempt', - unique_together={('target_uid', 'request_ip', 'created')}, - ), - ] diff --git a/passbook/core/apps.py b/passbook/core/apps.py index 8548b9da2..ae651b1b8 100644 --- a/passbook/core/apps.py +++ b/passbook/core/apps.py @@ -16,7 +16,7 @@ class PassbookCoreConfig(AppConfig): verbose_name = 'passbook Core' def ready(self): - import_module('passbook.core.rules') + import_module('passbook.core.policies') factors_to_load = CONFIG.y('passbook.factors', []) for factors_to_load in factors_to_load: try: diff --git a/passbook/core/auth/view.py b/passbook/core/auth/view.py index 8ef594e9e..e591b33cc 100644 --- a/passbook/core/auth/view.py +++ b/passbook/core/auth/view.py @@ -49,7 +49,7 @@ class AuthenticationView(UserPassesTestMixin, View): self.pending_factors = request.session[AuthenticationView.SESSION_PENDING_FACTORS] else: # Get an initial list of factors which are currently enabled - # and apply to the current user. We check rules here and block the request + # and apply to the current user. We check policies here and block the request _all_factors = Factor.objects.filter(enabled=True) self.pending_factors = [] for factor in _all_factors: diff --git a/passbook/core/forms/applications.py b/passbook/core/forms/applications.py index 4a7d50712..642de6471 100644 --- a/passbook/core/forms/applications.py +++ b/passbook/core/forms/applications.py @@ -13,7 +13,7 @@ class ApplicationForm(forms.ModelForm): model = Application fields = ['name', 'slug', 'launch_url', 'icon_url', - 'rules', 'provider', 'skip_authorization'] + 'policies', 'provider', 'skip_authorization'] widgets = { 'name': forms.TextInput(), 'launch_url': forms.TextInput(), diff --git a/passbook/core/forms/factor.py b/passbook/core/forms/factor.py index 326fe795f..9ad91c1fd 100644 --- a/passbook/core/forms/factor.py +++ b/passbook/core/forms/factor.py @@ -17,7 +17,7 @@ class FactorForm(forms.ModelForm): class Meta: model = Factor - fields = ['name', 'slug', 'order', 'rules', 'type', 'enabled'] + fields = ['name', 'slug', 'order', 'policies', 'type', 'enabled'] widgets = { 'type': forms.Select(choices=get_factors()), 'name': forms.TextInput(), diff --git a/passbook/core/forms/rules.py b/passbook/core/forms/policies.py similarity index 70% rename from passbook/core/forms/rules.py rename to passbook/core/forms/policies.py index 0e83a23f4..c80a3bbc9 100644 --- a/passbook/core/forms/rules.py +++ b/passbook/core/forms/policies.py @@ -1,18 +1,18 @@ -"""passbook rule forms""" +"""passbook Policy forms""" from django import forms from django.utils.translation import gettext as _ -from passbook.core.models import DebugRule, FieldMatcherRule, WebhookRule +from passbook.core.models import DebugPolicy, FieldMatcherPolicy, WebhookPolicy GENERAL_FIELDS = ['name', 'action', 'negate', 'order', ] -class FieldMatcherRuleForm(forms.ModelForm): - """FieldMatcherRule Form""" +class FieldMatcherPolicyForm(forms.ModelForm): + """FieldMatcherPolicy Form""" class Meta: - model = FieldMatcherRule + model = FieldMatcherPolicy fields = GENERAL_FIELDS + ['user_field', 'match_action', 'value', ] widgets = { 'name': forms.TextInput(), @@ -20,12 +20,12 @@ class FieldMatcherRuleForm(forms.ModelForm): } -class WebhookRuleForm(forms.ModelForm): - """WebhookRuleForm Form""" +class WebhookPolicyForm(forms.ModelForm): + """WebhookPolicyForm Form""" class Meta: - model = WebhookRule + model = WebhookPolicy fields = GENERAL_FIELDS + ['url', 'method', 'json_body', 'json_headers', 'result_jsonpath', 'result_json_value', ] widgets = { @@ -37,12 +37,12 @@ class WebhookRuleForm(forms.ModelForm): } -class DebugRuleForm(forms.ModelForm): - """DebugRuleForm Form""" +class DebugPolicyForm(forms.ModelForm): + """DebugPolicyForm Form""" class Meta: - model = DebugRule + model = DebugPolicy fields = GENERAL_FIELDS + ['result', 'wait_min', 'wait_max'] widgets = { 'name': forms.TextInput(), diff --git a/passbook/core/migrations/0001_initial.py b/passbook/core/migrations/0001_initial.py index c3afb6961..94e90987e 100644 --- a/passbook/core/migrations/0001_initial.py +++ b/passbook/core/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.5 on 2019-02-08 10:42 +# Generated by Django 2.1.7 on 2019-02-16 09:10 import uuid @@ -68,13 +68,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='Provider', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ], - ), - migrations.CreateModel( - name='Rule', + name='Policy', fields=[ ('created', models.DateField(auto_now_add=True)), ('last_updated', models.DateTimeField(auto_now=True)), @@ -89,7 +83,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='RuleModel', + name='PolicyModel', fields=[ ('created', models.DateField(auto_now_add=True)), ('last_updated', models.DateTimeField(auto_now=True)), @@ -99,6 +93,12 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.CreateModel( + name='Provider', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), migrations.CreateModel( name='UserSourceConnection', fields=[ @@ -111,51 +111,82 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Application', fields=[ - ('rulemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.RuleModel')), + ('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(default=None, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='passbook_core.Provider')), + ('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.rulemodel',), + bases=('passbook_core.policymodel',), ), migrations.CreateModel( - name='DebugRule', + name='DebugPolicy', fields=[ - ('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Rule')), + ('policy_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Policy')), ('result', models.BooleanField(default=False)), ('wait_min', models.IntegerField(default=5)), ('wait_max', models.IntegerField(default=30)), ], options={ - 'verbose_name': 'Debug Rule', - 'verbose_name_plural': 'Debug Rules', + 'verbose_name': 'Debug Policy', + 'verbose_name_plural': 'Debug Policys', }, - bases=('passbook_core.rule',), + bases=('passbook_core.policy',), ), migrations.CreateModel( - name='FieldMatcherRule', + name='Factor', fields=[ - ('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Rule')), - ('user_field', models.TextField(choices=[('username', 'username'), ('first_name', 'first_name'), ('last_name', 'last_name'), ('email', 'email'), ('is_staff', 'is_staff'), ('is_active', 'is_active'), ('data_joined', 'data_joined')])), + ('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()), + ('type', models.TextField(unique=True)), + ('enabled', models.BooleanField(default=True)), + ], + options={ + 'abstract': False, + }, + bases=('passbook_core.policymodel',), + ), + migrations.CreateModel( + name='FieldMatcherPolicy', + fields=[ + ('policy_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Policy')), + ('user_field', models.TextField(choices=[('username', 'Username'), ('first_name', 'First Name'), ('last_name', 'Last Name'), ('email', 'E-Mail'), ('is_staff', 'Is staff'), ('is_active', 'Is active'), ('data_joined', 'Date joined')])), ('match_action', models.CharField(choices=[('startswith', 'Starts with'), ('endswith', 'Ends with'), ('endswith', 'Contains'), ('regexp', 'Regexp'), ('exact', 'Exact')], max_length=50)), ('value', models.TextField()), ], options={ - 'verbose_name': 'Field matcher Rule', - 'verbose_name_plural': 'Field matcher Rules', + 'verbose_name': 'Field matcher Policy', + 'verbose_name_plural': 'Field matcher Policys', }, - bases=('passbook_core.rule',), + bases=('passbook_core.policy',), + ), + migrations.CreateModel( + name='PasswordPolicyPolicy', + fields=[ + ('policy_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Policy')), + ('amount_uppercase', models.IntegerField(default=0)), + ('amount_lowercase', models.IntegerField(default=0)), + ('amount_symbols', models.IntegerField(default=0)), + ('length_min', models.IntegerField(default=0)), + ('symbol_charset', models.TextField(default='!\\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ')), + ], + options={ + 'verbose_name': 'Password Policy Policy', + 'verbose_name_plural': 'Password Policy Policys', + }, + bases=('passbook_core.policy',), ), migrations.CreateModel( name='Source', fields=[ - ('rulemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.RuleModel')), + ('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)), @@ -163,12 +194,12 @@ class Migration(migrations.Migration): options={ 'abstract': False, }, - bases=('passbook_core.rulemodel',), + bases=('passbook_core.policymodel',), ), migrations.CreateModel( - name='WebhookRule', + name='WebhookPolicy', fields=[ - ('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Rule')), + ('policy_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Policy')), ('url', models.URLField()), ('method', models.CharField(choices=[('GET', 'GET'), ('POST', 'POST'), ('PATCH', 'PATCH'), ('DELETE', 'DELETE'), ('PUT', 'PUT')], max_length=10)), ('json_body', models.TextField()), @@ -177,15 +208,15 @@ class Migration(migrations.Migration): ('result_json_value', models.TextField()), ], options={ - 'verbose_name': 'Webhook Rule', - 'verbose_name_plural': 'Webhook Rules', + 'verbose_name': 'Webhook Policy', + 'verbose_name_plural': 'Webhook Policys', }, - bases=('passbook_core.rule',), + bases=('passbook_core.policy',), ), migrations.AddField( - model_name='rulemodel', - name='rules', - field=models.ManyToManyField(blank=True, to='passbook_core.Rule'), + model_name='policymodel', + name='policies', + field=models.ManyToManyField(blank=True, to='passbook_core.Policy'), ), migrations.AddField( model_name='user', diff --git a/passbook/core/migrations/0002_auto_20190208_1514.py b/passbook/core/migrations/0002_auto_20190208_1514.py deleted file mode 100644 index 1280d5a46..000000000 --- a/passbook/core/migrations/0002_auto_20190208_1514.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-08 15:14 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_core', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='PasswordPolicyRule', - fields=[ - ('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Rule')), - ('amount_uppercase', models.IntegerField(default=0)), - ('amount_lowercase', models.IntegerField(default=0)), - ('amount_symbols', models.IntegerField(default=0)), - ('length_min', models.IntegerField(default=0)), - ('symbol_charset', models.TextField(default='!\\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ')), - ], - options={ - 'verbose_name': 'Password Policy Rule', - 'verbose_name_plural': 'Password Policy Rules', - }, - bases=('passbook_core.rule',), - ), - migrations.AlterField( - model_name='fieldmatcherrule', - name='user_field', - field=models.TextField(choices=[('username', 'Username'), ('first_name', 'First Name'), ('last_name', 'Last Name'), ('email', 'E-Mail'), ('is_staff', 'Is staff'), ('is_active', 'Is active'), ('data_joined', 'Date joined')]), - ), - ] diff --git a/passbook/core/migrations/0003_factor.py b/passbook/core/migrations/0003_factor.py deleted file mode 100644 index b9da82781..000000000 --- a/passbook/core/migrations/0003_factor.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.1.7 on 2019-02-14 15:41 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_core', '0002_auto_20190208_1514'), - ] - - operations = [ - migrations.CreateModel( - name='Factor', - fields=[ - ('rulemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.RuleModel')), - ('name', models.TextField()), - ('slug', models.SlugField(unique=True)), - ('order', models.IntegerField()), - ('type', models.TextField()), - ], - options={ - 'abstract': False, - }, - bases=('passbook_core.rulemodel',), - ), - ] diff --git a/passbook/core/migrations/0004_auto_20190215_1534.py b/passbook/core/migrations/0004_auto_20190215_1534.py deleted file mode 100644 index d31c8de23..000000000 --- a/passbook/core/migrations/0004_auto_20190215_1534.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.1.7 on 2019-02-15 15:34 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_core', '0003_factor'), - ] - - operations = [ - migrations.AddField( - model_name='factor', - name='enabled', - field=models.BooleanField(default=True), - ), - migrations.AlterField( - model_name='application', - name='provider', - field=models.OneToOneField(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='passbook_core.Provider'), - ), - ] diff --git a/passbook/core/migrations/0005_auto_20190216_0853.py b/passbook/core/migrations/0005_auto_20190216_0853.py deleted file mode 100644 index 15fd936bd..000000000 --- a/passbook/core/migrations/0005_auto_20190216_0853.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.7 on 2019-02-16 08:53 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_core', '0004_auto_20190215_1534'), - ] - - operations = [ - migrations.AlterField( - model_name='factor', - name='type', - field=models.TextField(unique=True), - ), - ] diff --git a/passbook/core/models.py b/passbook/core/models.py index 78c6dbbee..82ed89976 100644 --- a/passbook/core/models.py +++ b/passbook/core/models.py @@ -49,19 +49,19 @@ class Provider(models.Model): return getattr(self, 'name') return super().__str__() -class RuleModel(UUIDModel, CreatedUpdatedModel): - """Base model which can have rules applied to it""" +class PolicyModel(UUIDModel, CreatedUpdatedModel): + """Base model which can have policies applied to it""" - rules = models.ManyToManyField('Rule', blank=True) + policies = models.ManyToManyField('Policy', blank=True) def passes(self, user: User) -> bool: """Return true if user passes, otherwise False or raise Exception""" - for rule in self.rules: - if not rule.passes(user): + for policy in self.policies: + if not policy.passes(user): return False return True -class Factor(RuleModel): +class Factor(PolicyModel): """Authentication factor, multiple instances of the same Factor can be used""" name = models.TextField() @@ -73,7 +73,7 @@ class Factor(RuleModel): def __str__(self): return "Factor %s" % self.slug -class Application(RuleModel): +class 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""" @@ -90,13 +90,13 @@ class Application(RuleModel): def user_is_authorized(self, user: User) -> bool: """Check if user is authorized to use this application""" - from passbook.core.rules import RuleEngine - return RuleEngine(self.rules.all()).for_user(user).result + from passbook.core.policies import PolicyEngine + return PolicyEngine(self.policies.all()).for_user(user).result def __str__(self): return self.name -class Source(RuleModel): +class Source(PolicyModel): """Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server""" name = models.TextField() @@ -129,8 +129,8 @@ class UserSourceConnection(CreatedUpdatedModel): unique_together = (('user', 'source'),) -class Rule(UUIDModel, CreatedUpdatedModel): - """Rules which specify if a user is authorized to use an Application. Can be overridden by +class Policy(UUIDModel, CreatedUpdatedModel): + """Policys which specify if a user is authorized to use an Application. Can be overridden by other types to add other fields, more logic, etc.""" ACTION_ALLOW = 'allow' @@ -153,11 +153,11 @@ class Rule(UUIDModel, CreatedUpdatedModel): return "%s action %s" % (self.name, self.action) def passes(self, user: User) -> bool: - """Check if user instance passes this rule""" + """Check if user instance passes this policy""" raise NotImplementedError() -class FieldMatcherRule(Rule): - """Rule which checks if a field of the User model matches/doesn't match a +class FieldMatcherPolicy(Policy): + """Policy which checks if a field of the User model matches/doesn't match a certain pattern""" MATCH_STARTSWITH = 'startswith' @@ -188,7 +188,7 @@ class FieldMatcherRule(Rule): match_action = models.CharField(max_length=50, choices=MATCHES) value = models.TextField() - form = 'passbook.core.forms.rules.FieldMatcherRuleForm' + form = 'passbook.core.forms.policies.FieldMatcherPolicyForm' def __str__(self): description = "%s, user.%s %s '%s'" % (self.name, self.user_field, @@ -205,13 +205,13 @@ class FieldMatcherRule(Rule): LOGGER.debug("Checked '%s' %s with '%s'...", user_field_value, self.match_action, self.value) passes = False - if self.match_action == FieldMatcherRule.MATCH_STARTSWITH: + if self.match_action == FieldMatcherPolicy.MATCH_STARTSWITH: passes = user_field_value.startswith(self.value) - if self.match_action == FieldMatcherRule.MATCH_ENDSWITH: + if self.match_action == FieldMatcherPolicy.MATCH_ENDSWITH: passes = user_field_value.endswith(self.value) - if self.match_action == FieldMatcherRule.MATCH_CONTAINS: + if self.match_action == FieldMatcherPolicy.MATCH_CONTAINS: passes = self.value in user_field_value - if self.match_action == FieldMatcherRule.MATCH_REGEXP: + if self.match_action == FieldMatcherPolicy.MATCH_REGEXP: pattern = re.compile(self.value) passes = bool(pattern.match(user_field_value)) if self.negate: @@ -221,11 +221,11 @@ class FieldMatcherRule(Rule): class Meta: - verbose_name = _('Field matcher Rule') - verbose_name_plural = _('Field matcher Rules') + verbose_name = _('Field matcher Policy') + verbose_name_plural = _('Field matcher Policys') -class PasswordPolicyRule(Rule): - """Rule to make sure passwords have certain properties""" +class PasswordPolicyPolicy(Policy): + """Policy to make sure passwords have certain properties""" amount_uppercase = models.IntegerField(default=0) amount_lowercase = models.IntegerField(default=0) @@ -233,7 +233,7 @@ class PasswordPolicyRule(Rule): length_min = models.IntegerField(default=0) symbol_charset = models.TextField(default=r"!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ") - form = 'passbook.core.forms.rules.PasswordPolicyRuleForm' + form = 'passbook.core.forms.policies.PasswordPolicyPolicyForm' def passes(self, user: User) -> bool: # Only check if password is being set @@ -254,12 +254,12 @@ class PasswordPolicyRule(Rule): class Meta: - verbose_name = _('Password Policy Rule') - verbose_name_plural = _('Password Policy Rules') + verbose_name = _('Password Policy Policy') + verbose_name_plural = _('Password Policy Policys') -class WebhookRule(Rule): - """Rule that asks webhook""" +class WebhookPolicy(Policy): + """Policy that asks webhook""" METHOD_GET = 'GET' METHOD_POST = 'POST' @@ -282,7 +282,7 @@ class WebhookRule(Rule): result_jsonpath = models.TextField() result_json_value = models.TextField() - form = 'passbook.core.forms.rules.WebhookRuleForm' + form = 'passbook.core.forms.policies.WebhookPolicyForm' def passes(self, user: User): """Call webhook asynchronously and report back""" @@ -290,30 +290,30 @@ class WebhookRule(Rule): class Meta: - verbose_name = _('Webhook Rule') - verbose_name_plural = _('Webhook Rules') + verbose_name = _('Webhook Policy') + verbose_name_plural = _('Webhook Policys') -class DebugRule(Rule): - """Rule used for debugging the RuleEngine. Returns a fixed result, +class DebugPolicy(Policy): + """Policy used for debugging the PolicyEngine. Returns a fixed result, but takes a random time to process.""" result = models.BooleanField(default=False) wait_min = models.IntegerField(default=5) wait_max = models.IntegerField(default=30) - form = 'passbook.core.forms.rules.DebugRuleForm' + form = 'passbook.core.forms.policies.DebugPolicyForm' def passes(self, user: User): """Wait random time then return result""" wait = SystemRandom().randrange(self.wait_min, self.wait_max) - LOGGER.debug("Rule '%s' waiting for %ds", self.name, wait) + LOGGER.debug("Policy '%s' waiting for %ds", self.name, wait) sleep(wait) return self.result class Meta: - verbose_name = _('Debug Rule') - verbose_name_plural = _('Debug Rules') + verbose_name = _('Debug Policy') + verbose_name_plural = _('Debug Policys') class Invitation(UUIDModel): """Single-use invitation link""" diff --git a/passbook/core/policies.py b/passbook/core/policies.py new file mode 100644 index 000000000..b501ea97f --- /dev/null +++ b/passbook/core/policies.py @@ -0,0 +1,48 @@ +"""passbook core policy engine""" +from logging import getLogger + +from celery import group + +from passbook.core.celery import CELERY_APP +from passbook.core.models import Policy, User + +LOGGER = getLogger(__name__) + +@CELERY_APP.task() +def _policy_engine_task(user_pk, policy_pk, **kwargs): + """Task wrapper to run policy checking""" + policy_obj = Policy.objects.filter(pk=policy_pk).select_subclasses().first() + user_obj = User.objects.get(pk=user_pk) + for key, value in kwargs.items(): + setattr(user_obj, key, value) + LOGGER.debug("Running policy `%s`#%s for user %s...", policy_obj.name, + policy_obj.pk.hex, user_obj) + return policy_obj.passes(user_obj) + +class PolicyEngine: + """Orchestrate policy checking, launch tasks and return result""" + + policies = None + _group = None + + def __init__(self, policies): + self.policies = policies + + def for_user(self, user): + """Check policies for user""" + signatures = [] + kwargs = { + '__password__': getattr(user, '__password__') + } + for policy in self.policies: + signatures.append(_policy_engine_task.s(user.pk, policy.pk.hex, **kwargs)) + self._group = group(signatures)() + return self + + @property + def result(self): + """Get policy-checking result""" + for policy_result in self._group.get(): + if policy_result is False: + return False + return True diff --git a/passbook/core/rules.py b/passbook/core/rules.py deleted file mode 100644 index 29376fc09..000000000 --- a/passbook/core/rules.py +++ /dev/null @@ -1,47 +0,0 @@ -"""passbook core rule engine""" -from logging import getLogger - -from celery import group - -from passbook.core.celery import CELERY_APP -from passbook.core.models import Rule, User - -LOGGER = getLogger(__name__) - -@CELERY_APP.task() -def _rule_engine_task(user_pk, rule_pk, **kwargs): - """Task wrapper to run rule checking""" - rule_obj = Rule.objects.filter(pk=rule_pk).select_subclasses().first() - user_obj = User.objects.get(pk=user_pk) - for key, value in kwargs.items(): - setattr(user_obj, key, value) - LOGGER.debug("Running rule `%s`#%s for user %s...", rule_obj.name, rule_obj.pk.hex, user_obj) - return rule_obj.passes(user_obj) - -class RuleEngine: - """Orchestrate rule checking, launch tasks and return result""" - - rules = None - _group = None - - def __init__(self, rules): - self.rules = rules - - def for_user(self, user): - """Check rules for user""" - signatures = [] - kwargs = { - '__password__': getattr(user, '__password__') - } - for rule in self.rules: - signatures.append(_rule_engine_task.s(user.pk, rule.pk.hex, **kwargs)) - self._group = group(signatures)() - return self - - @property - def result(self): - """Get rule-checking result""" - for rule_result in self._group.get(): - if rule_result is False: - return False - return True diff --git a/passbook/ldap/forms.py b/passbook/ldap/forms.py index c963ae024..fbe6e55c3 100644 --- a/passbook/ldap/forms.py +++ b/passbook/ldap/forms.py @@ -14,7 +14,7 @@ class LDAPSourceForm(forms.ModelForm): model = LDAPSource fields = SOURCE_FORM_FIELDS + ['server_uri', 'bind_cn', 'bind_password', 'type', 'domain', 'base_dn', 'create_user', - 'reset_password', 'rules'] + 'reset_password', 'policies'] widgets = { 'name': forms.TextInput(), 'server_uri': forms.TextInput(), diff --git a/passbook/ldap/migrations/0001_initial.py b/passbook/ldap/migrations/0001_initial.py index 22b8e928d..4d432c79a 100644 --- a/passbook/ldap/migrations/0001_initial.py +++ b/passbook/ldap/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.4 on 2018-12-10 09:16 +# Generated by Django 2.1.7 on 2019-02-16 09:13 import django.db.models.deletion from django.db import migrations, models diff --git a/passbook/oauth_client/migrations/0001_initial.py b/passbook/oauth_client/migrations/0001_initial.py index 7894cad5f..5642bec33 100644 --- a/passbook/oauth_client/migrations/0001_initial.py +++ b/passbook/oauth_client/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.4 on 2018-12-10 09:16 +# Generated by Django 2.1.7 on 2019-02-16 09:13 import django.db.models.deletion from django.db import migrations, models @@ -26,8 +26,8 @@ class Migration(migrations.Migration): ('consumer_secret', models.TextField()), ], options={ - 'verbose_name': 'OAuth Source', - 'verbose_name_plural': 'OAuth Sources', + 'verbose_name': 'Generic OAuth Source', + 'verbose_name_plural': 'Generic OAuth Sources', }, bases=('passbook_core.source',), ), diff --git a/passbook/oauth_client/migrations/0002_auto_20181218_1019.py b/passbook/oauth_client/migrations/0002_auto_20181218_1019.py deleted file mode 100644 index e276234b4..000000000 --- a/passbook/oauth_client/migrations/0002_auto_20181218_1019.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.1.4 on 2018-12-18 10:19 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_oauth_client', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='oauthsource', - options={'verbose_name': 'Generic OAuth Source', 'verbose_name_plural': 'Generic OAuth Sources'}, - ), - ] diff --git a/passbook/oauth_provider/migrations/0001_initial.py b/passbook/oauth_provider/migrations/0001_initial.py index 783c536a3..b25fedbca 100644 --- a/passbook/oauth_provider/migrations/0001_initial.py +++ b/passbook/oauth_provider/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.3 on 2018-11-25 10:39 +# Generated by Django 2.1.7 on 2019-02-16 09:13 import django.db.models.deletion import oauth2_provider.generators @@ -15,8 +15,8 @@ class Migration(migrations.Migration): ] dependencies = [ - ('passbook_core', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('passbook_core', '0001_initial'), ] operations = [ @@ -36,7 +36,8 @@ class Migration(migrations.Migration): ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='passbook_oauth_provider_oauth2provider', to=settings.AUTH_USER_MODEL)), ], options={ - 'abstract': False, + 'verbose_name': 'OAuth2 Provider', + 'verbose_name_plural': 'OAuth2 Providers', }, bases=('passbook_core.provider', models.Model), ), diff --git a/passbook/oauth_provider/migrations/0002_auto_20181126_1514.py b/passbook/oauth_provider/migrations/0002_auto_20181126_1514.py deleted file mode 100644 index ec85f7878..000000000 --- a/passbook/oauth_provider/migrations/0002_auto_20181126_1514.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.1.3 on 2018-11-26 15:14 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('passbook_oauth_provider', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='oauth2provider', - options={'verbose_name': 'OAuth2 Provider', 'verbose_name_plural': 'OAuth2 Providers'}, - ), - ] diff --git a/passbook/oauth_provider/views/oauth2.py b/passbook/oauth_provider/views/oauth2.py index 99d2e271e..f30d14e12 100644 --- a/passbook/oauth_provider/views/oauth2.py +++ b/passbook/oauth_provider/views/oauth2.py @@ -29,7 +29,7 @@ class OAuthPermissionDenied(PermissionDeniedView): class PassbookAuthorizationView(AccessMixin, AuthorizationView): - """Custom OAuth2 Authorization View which checks rules, etc""" + """Custom OAuth2 Authorization View which checks policies, etc""" _application = None diff --git a/passbook/saml_idp/migrations/0001_initial.py b/passbook/saml_idp/migrations/0001_initial.py index 91878da0e..4a210df76 100644 --- a/passbook/saml_idp/migrations/0001_initial.py +++ b/passbook/saml_idp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.4 on 2018-12-10 09:16 +# Generated by Django 2.1.7 on 2019-02-16 09:13 import django.db.models.deletion from django.db import migrations, models