events: allow setting a mapping for webhook transport to customise request payloads

closes #1383

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-09-12 01:02:51 +02:00
parent c779ad2e3b
commit 9a7fa39de4
14 changed files with 552 additions and 13 deletions

View File

@ -24,6 +24,7 @@ from authentik.core.api.users import UserViewSet
from authentik.crypto.api import CertificateKeyPairViewSet from authentik.crypto.api import CertificateKeyPairViewSet
from authentik.events.api.event import EventViewSet from authentik.events.api.event import EventViewSet
from authentik.events.api.notification import NotificationViewSet from authentik.events.api.notification import NotificationViewSet
from authentik.events.api.notification_mapping import NotificationWebhookMappingViewSet
from authentik.events.api.notification_rule import NotificationRuleViewSet from authentik.events.api.notification_rule import NotificationRuleViewSet
from authentik.events.api.notification_transport import NotificationTransportViewSet from authentik.events.api.notification_transport import NotificationTransportViewSet
from authentik.flows.api.bindings import FlowStageBindingViewSet from authentik.flows.api.bindings import FlowStageBindingViewSet
@ -159,6 +160,7 @@ router.register("propertymappings/all", PropertyMappingViewSet)
router.register("propertymappings/ldap", LDAPPropertyMappingViewSet) router.register("propertymappings/ldap", LDAPPropertyMappingViewSet)
router.register("propertymappings/saml", SAMLPropertyMappingViewSet) router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
router.register("propertymappings/scope", ScopeMappingViewSet) router.register("propertymappings/scope", ScopeMappingViewSet)
router.register("propertymappings/notification", NotificationWebhookMappingViewSet)
router.register("authenticators/duo", DuoDeviceViewSet) router.register("authenticators/duo", DuoDeviceViewSet)
router.register("authenticators/static", StaticDeviceViewSet) router.register("authenticators/static", StaticDeviceViewSet)

View File

@ -0,0 +1,28 @@
"""NotificationWebhookMapping API Views"""
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin
from authentik.events.models import NotificationWebhookMapping
class NotificationWebhookMappingSerializer(ModelSerializer):
"""NotificationWebhookMapping Serializer"""
class Meta:
model = NotificationWebhookMapping
fields = [
"pk",
"name",
"expression",
]
class NotificationWebhookMappingViewSet(UsedByMixin, ModelViewSet):
"""NotificationWebhookMapping Viewset"""
queryset = NotificationWebhookMapping.objects.all()
serializer_class = NotificationWebhookMappingSerializer
filterset_fields = ["name"]
ordering = ["name"]

View File

@ -38,6 +38,7 @@ class NotificationTransportSerializer(ModelSerializer):
"mode", "mode",
"mode_verbose", "mode_verbose",
"webhook_url", "webhook_url",
"webhook_mapping",
"send_once", "send_once",
] ]

View File

@ -0,0 +1,46 @@
# Generated by Django 3.2.6 on 2021-09-11 22:17
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0028_alter_token_intent"),
("authentik_events", "0017_alter_event_action"),
]
operations = [
migrations.CreateModel(
name="NotificationWebhookMapping",
fields=[
(
"propertymapping_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_core.propertymapping",
),
),
],
options={
"verbose_name": "Notification Webhook Mapping",
"verbose_name_plural": "Notification Webhook Mappings",
},
bases=("authentik_core.propertymapping",),
),
migrations.AddField(
model_name="notificationtransport",
name="webhook_mapping",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_events.notificationwebhookmapping",
),
),
]

View File

@ -2,7 +2,7 @@
from datetime import timedelta from datetime import timedelta
from inspect import getmodule, stack from inspect import getmodule, stack
from smtplib import SMTPException from smtplib import SMTPException
from typing import Optional, Union from typing import TYPE_CHECKING, Optional, Type, Union
from uuid import uuid4 from uuid import uuid4
from django.conf import settings from django.conf import settings
@ -15,7 +15,7 @@ from structlog.stdlib import get_logger
from authentik import __version__ from authentik import __version__
from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER
from authentik.core.models import ExpiringModel, Group, User from authentik.core.models import ExpiringModel, Group, PropertyMapping, User
from authentik.events.geo import GEOIP_READER from authentik.events.geo import GEOIP_READER
from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
from authentik.lib.sentry import SentryIgnoredException from authentik.lib.sentry import SentryIgnoredException
@ -27,6 +27,8 @@ from authentik.tenants.models import Tenant
from authentik.tenants.utils import DEFAULT_TENANT from authentik.tenants.utils import DEFAULT_TENANT
LOGGER = get_logger("authentik.events") LOGGER = get_logger("authentik.events")
if TYPE_CHECKING:
from rest_framework.serializers import Serializer
def default_event_duration(): def default_event_duration():
@ -220,6 +222,9 @@ class NotificationTransport(models.Model):
mode = models.TextField(choices=TransportMode.choices) mode = models.TextField(choices=TransportMode.choices)
webhook_url = models.TextField(blank=True) webhook_url = models.TextField(blank=True)
webhook_mapping = models.ForeignKey(
"NotificationWebhookMapping", on_delete=models.SET_DEFAULT, null=True, default=None
)
send_once = models.BooleanField( send_once = models.BooleanField(
default=False, default=False,
help_text=_( help_text=_(
@ -239,15 +244,22 @@ class NotificationTransport(models.Model):
def send_webhook(self, notification: "Notification") -> list[str]: def send_webhook(self, notification: "Notification") -> list[str]:
"""Send notification to generic webhook""" """Send notification to generic webhook"""
default_body = {
"body": notification.body,
"severity": notification.severity,
"user_email": notification.user.email,
"user_username": notification.user.username,
}
if self.webhook_mapping:
default_body = self.webhook_mapping.evaluate(
user=notification.user,
request=None,
notification=notification,
)
try: try:
response = get_http_session().post( response = get_http_session().post(
self.webhook_url, self.webhook_url,
json={ json=default_body,
"body": notification.body,
"severity": notification.severity,
"user_email": notification.user.email,
"user_username": notification.user.username,
},
) )
response.raise_for_status() response.raise_for_status()
except RequestException as exc: except RequestException as exc:
@ -414,3 +426,25 @@ class NotificationRule(PolicyBindingModel):
verbose_name = _("Notification Rule") verbose_name = _("Notification Rule")
verbose_name_plural = _("Notification Rules") verbose_name_plural = _("Notification Rules")
class NotificationWebhookMapping(PropertyMapping):
"""Modify the schema and layout of the webhook being sent"""
@property
def component(self) -> str:
return "ak-property-mapping-notification-form"
@property
def serializer(self) -> Type["Serializer"]:
from authentik.events.api.notification_mapping import NotificationWebhookMappingSerializer
return NotificationWebhookMappingSerializer
def __str__(self):
return f"Notification Webhook Mapping {self.name}"
class Meta:
verbose_name = _("Notification Webhook Mapping")
verbose_name_plural = _("Notification Webhook Mappings")

View File

@ -9388,6 +9388,219 @@ paths:
$ref: '#/components/schemas/ValidationError' $ref: '#/components/schemas/ValidationError'
'403': '403':
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
/propertymappings/notification/:
get:
operationId: propertymappings_notification_list
description: NotificationWebhookMapping Viewset
parameters:
- in: query
name: name
schema:
type: string
- name: ordering
required: false
in: query
description: Which field to use when ordering the results.
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- name: search
required: false
in: query
description: A search term.
schema:
type: string
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedNotificationWebhookMappingList'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
post:
operationId: propertymappings_notification_create
description: NotificationWebhookMapping Viewset
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMappingRequest'
required: true
security:
- authentik: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMapping'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/propertymappings/notification/{pm_uuid}/:
get:
operationId: propertymappings_notification_retrieve
description: NotificationWebhookMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Notification Webhook Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMapping'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
put:
operationId: propertymappings_notification_update
description: NotificationWebhookMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Notification Webhook Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMappingRequest'
required: true
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMapping'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
patch:
operationId: propertymappings_notification_partial_update
description: NotificationWebhookMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Notification Webhook Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedNotificationWebhookMappingRequest'
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationWebhookMapping'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
delete:
operationId: propertymappings_notification_destroy
description: NotificationWebhookMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Notification Webhook Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'204':
description: No response body
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/propertymappings/notification/{pm_uuid}/used_by/:
get:
operationId: propertymappings_notification_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Notification Webhook Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/propertymappings/saml/: /propertymappings/saml/:
get: get:
operationId: propertymappings_saml_list operationId: propertymappings_saml_list
@ -21368,6 +21581,10 @@ components:
readOnly: true readOnly: true
webhook_url: webhook_url:
type: string type: string
webhook_mapping:
type: string
format: uuid
nullable: true
send_once: send_once:
type: boolean type: boolean
description: Only send notification once, for example when sending a webhook description: Only send notification once, for example when sending a webhook
@ -21393,6 +21610,10 @@ components:
$ref: '#/components/schemas/NotificationTransportModeEnum' $ref: '#/components/schemas/NotificationTransportModeEnum'
webhook_url: webhook_url:
type: string type: string
webhook_mapping:
type: string
format: uuid
nullable: true
send_once: send_once:
type: boolean type: boolean
description: Only send notification once, for example when sending a webhook description: Only send notification once, for example when sending a webhook
@ -21410,6 +21631,34 @@ components:
type: string type: string
required: required:
- messages - messages
NotificationWebhookMapping:
type: object
description: NotificationWebhookMapping Serializer
properties:
pk:
type: string
format: uuid
readOnly: true
title: Pm uuid
name:
type: string
expression:
type: string
required:
- expression
- name
- pk
NotificationWebhookMappingRequest:
type: object
description: NotificationWebhookMapping Serializer
properties:
name:
type: string
expression:
type: string
required:
- expression
- name
OAuth2Provider: OAuth2Provider:
type: object type: object
description: OAuth2Provider Serializer description: OAuth2Provider Serializer
@ -23183,6 +23432,41 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedNotificationWebhookMappingList:
type: object
properties:
pagination:
type: object
properties:
next:
type: number
previous:
type: number
count:
type: number
current:
type: number
total_pages:
type: number
start_index:
type: number
end_index:
type: number
required:
- next
- previous
- count
- current
- total_pages
- start_index
- end_index
results:
type: array
items:
$ref: '#/components/schemas/NotificationWebhookMapping'
required:
- pagination
- results
PaginatedOAuth2ProviderList: PaginatedOAuth2ProviderList:
type: object type: object
properties: properties:
@ -25525,10 +25809,22 @@ components:
$ref: '#/components/schemas/NotificationTransportModeEnum' $ref: '#/components/schemas/NotificationTransportModeEnum'
webhook_url: webhook_url:
type: string type: string
webhook_mapping:
type: string
format: uuid
nullable: true
send_once: send_once:
type: boolean type: boolean
description: Only send notification once, for example when sending a webhook description: Only send notification once, for example when sending a webhook
into a chat channel. into a chat channel.
PatchedNotificationWebhookMappingRequest:
type: object
description: NotificationWebhookMapping Serializer
properties:
name:
type: string
expression:
type: string
PatchedOAuth2ProviderRequest: PatchedOAuth2ProviderRequest:
type: object type: object
description: OAuth2Provider Serializer description: OAuth2Provider Serializer

View File

@ -15,9 +15,9 @@ import AKGlobal from "../../authentik.css";
import { configureSentry } from "../../api/Sentry"; import { configureSentry } from "../../api/Sentry";
import { CurrentTenant } from "@goauthentik/api"; import { CurrentTenant } from "@goauthentik/api";
import { ifDefined } from "lit-html/directives/if-defined";
import { EVENT_SIDEBAR_TOGGLE } from "../../constants"; import { EVENT_SIDEBAR_TOGGLE } from "../../constants";
import { tenant } from "../../api/Config"; import { tenant } from "../../api/Config";
import { first } from "../../utils";
// If the viewport is wider than MIN_WIDTH, the sidebar // If the viewport is wider than MIN_WIDTH, the sidebar
// is shown besides the content, and not overlayed. // is shown besides the content, and not overlayed.
@ -99,7 +99,7 @@ export class SidebarBrand extends LitElement {
<a href="#/" class="pf-c-page__header-brand-link"> <a href="#/" class="pf-c-page__header-brand-link">
<div class="pf-c-brand ak-brand"> <div class="pf-c-brand ak-brand">
<img <img
src="${ifDefined(this.tenant.brandingLogo)}" src="${first(this.tenant.brandingLogo, DefaultTenant.brandingLogo)}"
alt="authentik icon" alt="authentik icon"
loading="lazy" loading="lazy"
/> />

View File

@ -45,11 +45,12 @@ import {
ShellChallenge, ShellChallenge,
} from "@goauthentik/api"; } from "@goauthentik/api";
import { DEFAULT_CONFIG, tenant } from "../api/Config"; import { DEFAULT_CONFIG, tenant } from "../api/Config";
import { ifDefined } from "lit-html/directives/if-defined";
import { until } from "lit-html/directives/until"; import { until } from "lit-html/directives/until";
import { TITLE_DEFAULT } from "../constants"; import { TITLE_DEFAULT } from "../constants";
import { configureSentry } from "../api/Sentry"; import { configureSentry } from "../api/Sentry";
import { WebsocketClient } from "../common/ws"; import { WebsocketClient } from "../common/ws";
import { first } from "../utils";
import { DefaultTenant } from "../elements/sidebar/SidebarBrand";
@customElement("ak-flow-executor") @customElement("ak-flow-executor")
export class FlowExecutor extends LitElement implements StageHost { export class FlowExecutor extends LitElement implements StageHost {
@ -342,7 +343,10 @@ export class FlowExecutor extends LitElement implements StageHost {
<header class="pf-c-login__header"> <header class="pf-c-login__header">
<div class="pf-c-brand ak-brand"> <div class="pf-c-brand ak-brand">
<img <img
src="${ifDefined(this.tenant?.brandingLogo)}" src="${first(
this.tenant?.brandingLogo,
DefaultTenant.brandingLogo,
)}"
alt="authentik icon" alt="authentik icon"
/> />
</div> </div>

View File

@ -1646,6 +1646,7 @@ msgstr "Export flow"
#: src/pages/events/EventInfo.ts #: src/pages/events/EventInfo.ts
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Expression" msgid "Expression"
@ -1653,6 +1654,7 @@ msgstr "Expression"
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Expression using Python." msgid "Expression using Python."
@ -2316,6 +2318,7 @@ msgstr "Loading"
#: src/pages/applications/ApplicationForm.ts #: src/pages/applications/ApplicationForm.ts
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/events/TransportForm.ts
#: src/pages/flows/StageBindingForm.ts #: src/pages/flows/StageBindingForm.ts
#: src/pages/flows/StageBindingForm.ts #: src/pages/flows/StageBindingForm.ts
#: src/pages/groups/GroupForm.ts #: src/pages/groups/GroupForm.ts
@ -2564,6 +2567,7 @@ msgstr "My Applications"
#: src/pages/policies/reputation/ReputationPolicyForm.ts #: src/pages/policies/reputation/ReputationPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingListPage.ts #: src/pages/property-mappings/PropertyMappingListPage.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
#: src/pages/providers/ProviderListPage.ts #: src/pages/providers/ProviderListPage.ts
@ -3530,6 +3534,7 @@ msgstr "Secret:"
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "See documentation for a list of all variables." msgid "See documentation for a list of all variables."
@ -3968,6 +3973,7 @@ msgid "Successfully created invitation."
msgstr "Successfully created invitation." msgstr "Successfully created invitation."
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Successfully created mapping." msgid "Successfully created mapping."
@ -4124,6 +4130,7 @@ msgid "Successfully updated invitation."
msgstr "Successfully updated invitation." msgstr "Successfully updated invitation."
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Successfully updated mapping." msgid "Successfully updated mapping."
@ -5071,6 +5078,10 @@ msgstr "Webhook (Slack/Discord)"
msgid "Webhook (generic)" msgid "Webhook (generic)"
msgstr "Webhook (generic)" msgstr "Webhook (generic)"
#: src/pages/events/TransportForm.ts
msgid "Webhook Mapping"
msgstr "Webhook Mapping"
#: src/pages/events/TransportForm.ts #: src/pages/events/TransportForm.ts
msgid "Webhook URL" msgid "Webhook URL"
msgstr "Webhook URL" msgstr "Webhook URL"

View File

@ -1638,6 +1638,7 @@ msgstr ""
#: src/pages/events/EventInfo.ts #: src/pages/events/EventInfo.ts
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Expression" msgid "Expression"
@ -1645,6 +1646,7 @@ msgstr ""
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Expression using Python." msgid "Expression using Python."
@ -2308,6 +2310,7 @@ msgstr ""
#: src/pages/applications/ApplicationForm.ts #: src/pages/applications/ApplicationForm.ts
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/events/TransportForm.ts
#: src/pages/flows/StageBindingForm.ts #: src/pages/flows/StageBindingForm.ts
#: src/pages/flows/StageBindingForm.ts #: src/pages/flows/StageBindingForm.ts
#: src/pages/groups/GroupForm.ts #: src/pages/groups/GroupForm.ts
@ -2556,6 +2559,7 @@ msgstr ""
#: src/pages/policies/reputation/ReputationPolicyForm.ts #: src/pages/policies/reputation/ReputationPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingListPage.ts #: src/pages/property-mappings/PropertyMappingListPage.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
#: src/pages/providers/ProviderListPage.ts #: src/pages/providers/ProviderListPage.ts
@ -3522,6 +3526,7 @@ msgstr ""
#: src/pages/policies/expression/ExpressionPolicyForm.ts #: src/pages/policies/expression/ExpressionPolicyForm.ts
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "See documentation for a list of all variables." msgid "See documentation for a list of all variables."
@ -3960,6 +3965,7 @@ msgid "Successfully created invitation."
msgstr "" msgstr ""
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Successfully created mapping." msgid "Successfully created mapping."
@ -4116,6 +4122,7 @@ msgid "Successfully updated invitation."
msgstr "" msgstr ""
#: src/pages/property-mappings/PropertyMappingLDAPForm.ts #: src/pages/property-mappings/PropertyMappingLDAPForm.ts
#: src/pages/property-mappings/PropertyMappingNotification.ts
#: src/pages/property-mappings/PropertyMappingSAMLForm.ts #: src/pages/property-mappings/PropertyMappingSAMLForm.ts
#: src/pages/property-mappings/PropertyMappingScopeForm.ts #: src/pages/property-mappings/PropertyMappingScopeForm.ts
msgid "Successfully updated mapping." msgid "Successfully updated mapping."
@ -5056,6 +5063,10 @@ msgstr ""
msgid "Webhook (generic)" msgid "Webhook (generic)"
msgstr "" msgstr ""
#: src/pages/events/TransportForm.ts
msgid "Webhook Mapping"
msgstr ""
#: src/pages/events/TransportForm.ts #: src/pages/events/TransportForm.ts
msgid "Webhook URL" msgid "Webhook URL"
msgstr "" msgstr ""

View File

@ -1,4 +1,9 @@
import { EventsApi, NotificationTransport, NotificationTransportModeEnum } from "@goauthentik/api"; import {
EventsApi,
NotificationTransport,
NotificationTransportModeEnum,
PropertymappingsApi,
} from "@goauthentik/api";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { customElement, property } from "lit-element"; import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html"; import { html, TemplateResult } from "lit-html";
@ -7,6 +12,7 @@ import { ifDefined } from "lit-html/directives/if-defined";
import "../../elements/forms/HorizontalFormElement"; import "../../elements/forms/HorizontalFormElement";
import { first } from "../../utils"; import { first } from "../../utils";
import { ModelForm } from "../../elements/forms/ModelForm"; import { ModelForm } from "../../elements/forms/ModelForm";
import { until } from "lit-html/directives/until";
@customElement("ak-event-transport-form") @customElement("ak-event-transport-form")
export class TransportForm extends ModelForm<NotificationTransport, string> { export class TransportForm extends ModelForm<NotificationTransport, string> {
@ -112,6 +118,32 @@ export class TransportForm extends ModelForm<NotificationTransport, string> {
class="pf-c-form-control" class="pf-c-form-control"
/> />
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal
?hidden=${!this.showWebhook}
label=${t`Webhook Mapping`}
name="webhookMapping"
>
<select class="pf-c-form-control">
<option value="" ?selected=${this.instance?.webhookMapping === undefined}>
---------
</option>
${until(
new PropertymappingsApi(DEFAULT_CONFIG)
.propertymappingsNotificationList({})
.then((mappings) => {
return mappings.results.map((mapping) => {
return html`<option
value=${ifDefined(mapping.pk)}
?selected=${this.instance?.webhookMapping === mapping.pk}
>
${mapping.name}
</option>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</select>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="sendOnce"> <ak-form-element-horizontal name="sendOnce">
<div class="pf-c-check"> <div class="pf-c-check">
<input <input

View File

@ -12,6 +12,7 @@ import "./PropertyMappingTestForm";
import "./PropertyMappingScopeForm"; import "./PropertyMappingScopeForm";
import "./PropertyMappingLDAPForm"; import "./PropertyMappingLDAPForm";
import "./PropertyMappingSAMLForm"; import "./PropertyMappingSAMLForm";
import "./PropertyMappingNotification";
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";

View File

@ -0,0 +1,65 @@
import { NotificationWebhookMapping, PropertymappingsApi } from "@goauthentik/api";
import { t } from "@lingui/macro";
import { customElement } from "lit-element";
import { html, TemplateResult } from "lit-html";
import { DEFAULT_CONFIG } from "../../api/Config";
import { ifDefined } from "lit-html/directives/if-defined";
import "../../elements/forms/HorizontalFormElement";
import "../../elements/CodeMirror";
import { ModelForm } from "../../elements/forms/ModelForm";
@customElement("ak-property-mapping-notification-form")
export class PropertyMappingNotification extends ModelForm<NotificationWebhookMapping, string> {
loadInstance(pk: string): Promise<NotificationWebhookMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsNotificationRetrieveRaw({
pmUuid: pk,
});
}
getSuccessMessage(): string {
if (this.instance) {
return t`Successfully updated mapping.`;
} else {
return t`Successfully created mapping.`;
}
}
send = (data: NotificationWebhookMapping): Promise<NotificationWebhookMapping> => {
if (this.instance) {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsNotificationUpdate({
pmUuid: this.instance.pk || "",
notificationWebhookMappingRequest: data,
});
} else {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsNotificationCreate({
notificationWebhookMappingRequest: data,
});
}
};
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
<input
type="text"
value="${ifDefined(this.instance?.name)}"
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Expression`} ?required=${true} name="expression">
<ak-codemirror mode="python" value="${ifDefined(this.instance?.expression)}">
</ak-codemirror>
<p class="pf-c-form__helper-text">
${t`Expression using Python.`}
<a
target="_blank"
href="https://goauthentik.io/docs/property-mappings/expression/"
>
${t`See documentation for a list of all variables.`}
</a>
</p>
</ak-form-element-horizontal>
</form>`;
}
}

View File

@ -19,6 +19,14 @@ This will send a POST request to the given URL with the following contents:
The `Content-Type` header is set to `text/json`. The `Content-Type` header is set to `text/json`.
Starting in 2021.10, you can also select a Notification mapping. This allows you to freely configure the request's payload. For example:
```python
return {
"foo": context['notification'].body,
}
```
## Slack Webhook ## Slack Webhook
This sends a request using the Slack-specific format. This is also compatible with Discord's webhooks by appending `/slack` to the Discord webhook URL. This sends a request using the Slack-specific format. This is also compatible with Discord's webhooks by appending `/slack` to the Discord webhook URL.