web/admin: migrate property mapping test to web

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-03-30 17:53:43 +02:00
parent b1fb2982ef
commit 58a7d67922
9 changed files with 89 additions and 195 deletions

View File

@ -1,12 +0,0 @@
"""authentik administration forms"""
from django import forms
from authentik.admin.fields import CodeMirrorWidget, YAMLField
from authentik.core.models import User
class PolicyTestForm(forms.Form):
"""Form to test policies against user"""
user = forms.ModelChoiceField(queryset=User.objects.all())
context = YAMLField(widget=CodeMirrorWidget(), required=False, initial=dict)

View File

@ -1,46 +0,0 @@
{% extends 'generic/form.html' %}
{% load i18n %}
{% block above_form %}
<h1>{% blocktrans with policy=policy %}Test {{ policy }}{% endblocktrans %}</h1>
{% endblock %}
{% block beneath_form %}
{% if result %}
<div class="pf-c-form__group ">
<div class="pf-c-form__group-label">
<label class="pf-c-form__label" for="context-1">
<span class="pf-c-form__label-text">{% trans 'Passing' %}</span>
</label>
</div>
<div class="pf-c-form__group-label">
<div class="c-form__horizontal-group">
<span class="pf-c-form__label-text">{{ result.passing|yesno:"Yes,No" }}</span>
</div>
</div>
</div>
<div class="pf-c-form__group ">
<div class="pf-c-form__group-label">
<label class="pf-c-form__label" for="context-1">
<span class="pf-c-form__label-text">{% trans 'Messages' %}</span>
</label>
</div>
<div class="pf-c-form__group-label">
<div class="c-form__horizontal-group">
<ul>
{% for m in result.messages %}
<li><span class="pf-c-form__label-text">{{ m }}</span></li>
{% empty %}
<li><span class="pf-c-form__label-text">-</span></li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% block action %}
{% trans 'Test' %}
{% endblock %}

View File

@ -1,28 +0,0 @@
{% extends 'generic/form.html' %}
{% load i18n %}
{% block above_form %}
<h1>{% blocktrans with property_mapping=property_mapping %}Test {{ property_mapping }}{% endblocktrans %}</h1>
{% endblock %}
{% block beneath_form %}
{% if result %}
<div class="pf-c-form__group ">
<div class="pf-c-form__group-label">
<label class="pf-c-form__label" for="context-1">
<span class="pf-c-form__label-text">{% trans 'Result' %}</span>
</label>
</div>
<div class="pf-c-form__group-control">
<div class="c-form__horizontal-group">
<ak-codemirror mode="javascript"><textarea class="pf-c-form-control">{{ result }}</textarea></ak-codemirror>
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% block action %}
{% trans 'Test' %}
{% endblock %}

View File

@ -30,11 +30,6 @@ urlpatterns = [
policies.PolicyUpdateView.as_view(), policies.PolicyUpdateView.as_view(),
name="policy-update", name="policy-update",
), ),
path(
"policies/<uuid:pk>/test/",
policies.PolicyTestView.as_view(),
name="policy-test",
),
# Policy bindings # Policy bindings
path( path(
"policies/bindings/create/", "policies/bindings/create/",
@ -108,11 +103,6 @@ urlpatterns = [
property_mappings.PropertyMappingUpdateView.as_view(), property_mappings.PropertyMappingUpdateView.as_view(),
name="property-mapping-update", name="property-mapping-update",
), ),
path(
"property-mappings/<uuid:pk>/test/",
property_mappings.PropertyMappingTestView.as_view(),
name="property-mapping-test",
),
# Outpost Service Connections # Outpost Service Connections
path( path(
"outpost_service_connections/create/", "outpost_service_connections/create/",

View File

@ -1,22 +1,15 @@
"""authentik Policy administration""" """authentik Policy administration"""
from typing import Any
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import ( from django.contrib.auth.mixins import (
PermissionRequiredMixin as DjangoPermissionRequiredMixin, PermissionRequiredMixin as DjangoPermissionRequiredMixin,
) )
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponse
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views.generic import FormView
from django.views.generic.detail import DetailView
from guardian.mixins import PermissionRequiredMixin from guardian.mixins import PermissionRequiredMixin
from authentik.admin.forms.policies import PolicyTestForm
from authentik.admin.views.utils import InheritanceCreateView, InheritanceUpdateView from authentik.admin.views.utils import InheritanceCreateView, InheritanceUpdateView
from authentik.policies.models import Policy, PolicyBinding from authentik.policies.models import Policy
from authentik.policies.process import PolicyProcess, PolicyRequest
class PolicyCreateView( class PolicyCreateView(
@ -49,41 +42,3 @@ class PolicyUpdateView(
template_name = "generic/update.html" template_name = "generic/update.html"
success_url = reverse_lazy("authentik_core:if-admin") success_url = reverse_lazy("authentik_core:if-admin")
success_message = _("Successfully updated Policy") success_message = _("Successfully updated Policy")
class PolicyTestView(LoginRequiredMixin, DetailView, PermissionRequiredMixin, FormView):
"""View to test policy(s)"""
model = Policy
form_class = PolicyTestForm
permission_required = "authentik_policies.view_policy"
template_name = "administration/policy/test.html"
object = None
def get_object(self, queryset=None) -> Policy:
return (
Policy.objects.filter(pk=self.kwargs.get("pk")).select_subclasses().first()
)
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
kwargs["policy"] = self.get_object()
return super().get_context_data(**kwargs)
def post(self, *args, **kwargs) -> HttpResponse:
self.object = self.get_object()
return super().post(*args, **kwargs)
def form_valid(self, form: PolicyTestForm) -> HttpResponse:
policy = self.get_object()
user = form.cleaned_data.get("user")
p_request = PolicyRequest(user)
p_request.debug = True
p_request.set_http_request(self.request)
p_request.context = form.cleaned_data.get("context", {})
proc = PolicyProcess(PolicyBinding(policy=policy), p_request, None)
result = proc.execute()
context = self.get_context_data(form=form)
context["result"] = result
return self.render_to_response(context)

View File

@ -1,19 +1,12 @@
"""authentik PropertyMapping administration""" """authentik PropertyMapping administration"""
from json import dumps
from typing import Any
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import ( from django.contrib.auth.mixins import (
PermissionRequiredMixin as DjangoPermissionRequiredMixin, PermissionRequiredMixin as DjangoPermissionRequiredMixin,
) )
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views.generic import FormView
from django.views.generic.detail import DetailView
from guardian.mixins import PermissionRequiredMixin from guardian.mixins import PermissionRequiredMixin
from authentik.admin.forms.policies import PolicyTestForm
from authentik.admin.views.utils import InheritanceCreateView, InheritanceUpdateView from authentik.admin.views.utils import InheritanceCreateView, InheritanceUpdateView
from authentik.core.models import PropertyMapping from authentik.core.models import PropertyMapping
@ -46,44 +39,3 @@ class PropertyMappingUpdateView(
success_url = "/" success_url = "/"
template_name = "generic/update.html" template_name = "generic/update.html"
success_message = _("Successfully updated Property Mapping") success_message = _("Successfully updated Property Mapping")
class PropertyMappingTestView(
LoginRequiredMixin, DetailView, PermissionRequiredMixin, FormView
):
"""View to test property mappings"""
model = PropertyMapping
form_class = PolicyTestForm
permission_required = "authentik_core.view_propertymapping"
template_name = "administration/property_mapping/test.html"
object = None
def get_object(self, queryset=None) -> PropertyMapping:
return (
PropertyMapping.objects.filter(pk=self.kwargs.get("pk"))
.select_subclasses()
.first()
)
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
kwargs["property_mapping"] = self.get_object()
return super().get_context_data(**kwargs)
def post(self, *args, **kwargs) -> HttpResponse:
self.object = self.get_object()
return super().post(*args, **kwargs)
def form_valid(self, form: PolicyTestForm) -> HttpResponse:
mapping = self.get_object()
user = form.cleaned_data.get("user")
context = self.get_context_data(form=form)
try:
result = mapping.evaluate(
user, self.request, **form.cleaned_data.get("context", {})
)
context["result"] = dumps(result, indent=4)
except Exception as exc: # pylint: disable=broad-except
context["result"] = str(exc)
return self.render_to_response(context)

View File

@ -7,6 +7,8 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown"; import "../../elements/buttons/Dropdown";
import "../../elements/buttons/SpinnerButton"; import "../../elements/buttons/SpinnerButton";
import "../../elements/forms/DeleteForm"; import "../../elements/forms/DeleteForm";
import "../../elements/forms/ModalForm";
import "./PropertyMappingTestForm";
import { TableColumn } from "../../elements/table/Table"; import { TableColumn } from "../../elements/table/Table";
import { until } from "lit-html/directives/until"; import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants"; import { PAGE_SIZE } from "../../constants";
@ -64,12 +66,19 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
</ak-spinner-button> </ak-spinner-button>
<div slot="modal"></div> <div slot="modal"></div>
</ak-modal-button> </ak-modal-button>
<ak-modal-button href="${AdminURLManager.propertyMappings(`${item.pk}/test/`)}"> <ak-forms-modal .closeAfterSuccessfulSubmit=${false}>
<ak-spinner-button slot="trigger" class="pf-m-secondary"> <span slot="submit">
${gettext("Test")} ${gettext("Test")}
</ak-spinner-button> </span>
<div slot="modal"></div> <span slot="header">
</ak-modal-button> ${gettext("Test Property Mapping")}
</span>
<ak-property-mapping-test-form slot="form" .mapping=${item}>
</ak-property-mapping-test-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
${gettext("Test")}
</button>
</ak-forms-modal>
<ak-forms-delete <ak-forms-delete
.obj=${item} .obj=${item}
objectLabel=${gettext("Property Mapping")} objectLabel=${gettext("Property Mapping")}

View File

@ -0,0 +1,74 @@
import { CoreApi, PropertyMapping, PropertymappingsApi, PropertyMappingTestResult } from "authentik-api";
import { gettext } from "django";
import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html";
import { DEFAULT_CONFIG } from "../../api/Config";
import { Form } from "../../elements/forms/Form";
import { until } from "lit-html/directives/until";
import { ifDefined } from "lit-html/directives/if-defined";
import "../../elements/forms/HorizontalFormElement";
import "../../elements/CodeMirror";
import { PolicyTest } from "authentik-api/src";
@customElement("ak-property-mapping-test-form")
export class PolicyTestForm extends Form<PolicyTest> {
@property({attribute: false})
mapping?: PropertyMapping;
@property({ attribute: false})
result?: PropertyMappingTestResult;
getSuccessMessage(): string {
return gettext("Successfully sent test-request.");
}
send = (data: PolicyTest): Promise<PropertyMappingTestResult> => {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTest({
pmUuid: this.mapping?.pk || "",
data: data
}).then(result => this.result = result);
};
renderResult(): TemplateResult {
return html`<ak-form-element-horizontal
label=${gettext("Result")}>
${this.result?.successful ?
html`<ak-codemirror mode="javascript" ?readOnly=${true} value="${this.result?.result}">
</ak-codemirror>`:
html`
<div class="pf-c-form__group-label">
<div class="c-form__horizontal-group">
<span class="pf-c-form__label-text">${this.result?.result}</span>
</div>
</div>`}
</ak-form-element-horizontal>`;
}
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal
label=${gettext("User")}
?required=${true}
name="user">
<select class="pf-c-form-control">
${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({
ordering: "username",
}).then(users => {
return users.results.map(user => {
return html`<option value=${ifDefined(user.pk)}>${user.username}</option>`;
});
}), html``)}
</select>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${gettext("Context")}
name="context">
<ak-codemirror mode="yaml">
</ak-codemirror>
</ak-form-element-horizontal>
${this.result ? this.renderResult(): html``}
</form>`;
}
}