web/admin: migrate property mapping test to web
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
b1fb2982ef
commit
58a7d67922
|
@ -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)
|
|
|
@ -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 %}
|
|
|
@ -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 %}
|
|
|
@ -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/",
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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")}
|
||||||
|
|
|
@ -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>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue