core: app entitlements (#12090)

* core: initial app entitlements

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* base off of pbm

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add tests and oauth2

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add to proxy

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* rewrite to use bindings

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make policy bindings form and list more customizable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* double fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* refine permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add missing rbac modal to app entitlements

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* separate scope for app entitlements

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* include entitlements mapping in proxy

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add API validation to prevent policies from being bound to entitlements

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make preview

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add initial docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove duplicate docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2024-12-18 14:32:44 +01:00
committed by GitHub
parent 675a4a6788
commit 40a7135c0c
39 changed files with 1246 additions and 94 deletions

View File

@ -1,6 +1,7 @@
import "@goauthentik/admin/applications/ApplicationAuthorizeChart";
import "@goauthentik/admin/applications/ApplicationCheckAccessForm";
import "@goauthentik/admin/applications/ApplicationForm";
import "@goauthentik/admin/applications/entitlements/ApplicationEntitlementPage";
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
@ -301,6 +302,28 @@ export class ApplicationViewPage extends AKElement {
</div>
</div>
</section>
<section
slot="page-app-entitlements"
data-tab-title="${msg("Application entitlements")}"
>
<div slot="header" class="pf-c-banner pf-m-info">
${msg("Application entitlements are in preview.")}
<a href="mailto:hello+feature/app-ent@goauthentik.io"
>${msg("Send us feedback!")}</a
>
</div>
<div class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">
<div class="pf-c-card__title">
${msg(
"These entitlements can be used to configure user access in this application.",
)}
</div>
<ak-application-entitlements-list .app=${this.application.pk}>
</ak-application-entitlements-list>
</div>
</div>
</section>
<section
slot="page-policy-bindings"
data-tab-title="${msg("Policy / Group / User Bindings")}"

View File

@ -0,0 +1,89 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { msg } from "@lit/localize";
import { CSSResult } from "lit";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import { ApplicationEntitlement, CoreApi } from "@goauthentik/api";
@customElement("ak-application-entitlement-form")
export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement, string> {
async loadInstance(pk: string): Promise<ApplicationEntitlement> {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsRetrieve({
pbmUuid: pk,
});
}
@property()
targetPk?: string;
getSuccessMessage(): string {
if (this.instance?.pbmUuid) {
return msg("Successfully updated entitlement.");
} else {
return msg("Successfully created entitlement.");
}
}
static get styles(): CSSResult[] {
return [...super.styles, PFContent];
}
send(data: ApplicationEntitlement): Promise<unknown> {
if (this.targetPk) {
data.app = this.targetPk;
}
if (this.instance?.pbmUuid) {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsUpdate({
pbmUuid: this.instance.pbmUuid || "",
applicationEntitlementRequest: data,
});
} else {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsCreate({
applicationEntitlementRequest: data,
});
}
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"
value="${first(this.instance?.name, "")}"
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Attributes")}
?required=${false}
name="attributes"
>
<ak-codemirror
mode=${CodeMirrorMode.YAML}
value="${YAML.stringify(first(this.instance?.attributes, {}))}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Set custom attributes using YAML or JSON.")}
</p>
</ak-form-element-horizontal>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-application-entitlement-form": ApplicationEntitlementForm;
}
}

View File

@ -0,0 +1,152 @@
import "@goauthentik/admin/applications/entitlements/ApplicationEntitlementForm";
import "@goauthentik/admin/policies/BoundPoliciesList";
import { PolicyBindingCheckTarget } from "@goauthentik/admin/policies/utils";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFSize } from "@goauthentik/common/enums";
import "@goauthentik/components/ak-status-label";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import "@goauthentik/elements/forms/ProxyForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { Table, TableColumn } from "@goauthentik/elements/table/Table";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import {
ApplicationEntitlement,
CoreApi,
RbacPermissionsAssignedByUsersListModelEnum,
} from "@goauthentik/api";
@customElement("ak-application-entitlements-list")
export class ApplicationEntitlementsPage extends Table<ApplicationEntitlement> {
@property()
app?: string;
checkbox = true;
clearOnRefresh = true;
expandable = true;
order = "order";
async apiEndpoint(): Promise<PaginatedResponse<ApplicationEntitlement>> {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsList({
...(await this.defaultEndpointConfig()),
app: this.app || "",
});
}
columns(): TableColumn[] {
return [new TableColumn(msg("Name"), "name"), new TableColumn(msg("Actions"))];
}
renderToolbarSelected(): TemplateResult {
const disabled = this.selectedElements.length < 1;
return html`<ak-forms-delete-bulk
objectLabel=${msg("Application entitlement(s)")}
.objects=${this.selectedElements}
.usedBy=${(item: ApplicationEntitlement) => {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsUsedByList({
pbmUuid: item.pbmUuid || "",
});
}}
.delete=${(item: ApplicationEntitlement) => {
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsDestroy({
pbmUuid: item.pbmUuid || "",
});
}}
>
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
${msg("Delete")}
</button>
</ak-forms-delete-bulk>`;
}
row(item: ApplicationEntitlement): TemplateResult[] {
return [
html`${item.name}`,
html`<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit"> ${msg("Update")} </span>
<span slot="header"> ${msg("Update Entitlement")} </span>
<ak-application-entitlement-form
slot="form"
.instancePk=${item.pbmUuid}
targetPk=${ifDefined(this.app)}
>
</ak-application-entitlement-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
<i class="fas fa-edit"></i>
</pf-tooltip>
</button>
</ak-forms-modal>
<ak-rbac-object-permission-modal
model=${RbacPermissionsAssignedByUsersListModelEnum.CoreApplicationentitlement}
objectPk=${item.pbmUuid}
>
</ak-rbac-object-permission-modal>`,
];
}
renderExpanded(item: ApplicationEntitlement): TemplateResult {
return html` <td></td>
<td role="cell" colspan="4">
<div class="pf-c-table__expandable-row-content">
<div class="pf-c-content">
<p>
${msg(
"These bindings control which users have access to this entitlement.",
)}
</p>
<ak-bound-policies-list
.target=${item.pbmUuid}
.allowedTypes=${[
PolicyBindingCheckTarget.group,
PolicyBindingCheckTarget.user,
]}
>
</ak-bound-policies-list>
</div>
</div>
</td>`;
}
renderEmpty(): TemplateResult {
return super.renderEmpty(
html`<ak-empty-state
header=${msg("No app entitlements created.")}
icon="pf-icon-module"
>
<div slot="body">
${msg(
"This application does currently not have any application entitlement defined.",
)}
</div>
<div slot="primary"></div>
</ak-empty-state>`,
);
}
renderToolbar(): TemplateResult {
return html`<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create Entitlement")} </span>
<ak-application-entitlement-form slot="form" targetPk=${ifDefined(this.app)}>
</ak-application-entitlement-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Create entitlement")}
</button>
</ak-forms-modal> `;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-application-roles-list": ApplicationEntitlementsPage;
}
}

View File

@ -1,6 +1,11 @@
import "@goauthentik/admin/groups/GroupForm";
import "@goauthentik/admin/policies/PolicyBindingForm";
import { PolicyBindingNotice } from "@goauthentik/admin/policies/PolicyBindingForm";
import "@goauthentik/admin/policies/PolicyWizard";
import {
PolicyBindingCheckTarget,
PolicyBindingCheckTargetToLabel,
} from "@goauthentik/admin/policies/utils";
import "@goauthentik/admin/users/UserForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFSize } from "@goauthentik/common/enums.js";
@ -13,7 +18,7 @@ import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { Table, TableColumn } from "@goauthentik/elements/table/Table";
import { msg, str } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { TemplateResult, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@ -24,14 +29,25 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
@property()
target?: string;
@property({ type: Boolean })
policyOnly = false;
@property({ type: Array })
allowedTypes: PolicyBindingCheckTarget[] = [
PolicyBindingCheckTarget.group,
PolicyBindingCheckTarget.user,
PolicyBindingCheckTarget.policy,
];
@property({ type: Array })
typeNotices: PolicyBindingNotice[] = [];
checkbox = true;
clearOnRefresh = true;
order = "order";
get allowedTypesLabel(): string {
return this.allowedTypes.map((ct) => PolicyBindingCheckTargetToLabel(ct)).join(" / ");
}
async apiEndpoint(): Promise<PaginatedResponse<PolicyBinding>> {
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsList({
...(await this.defaultEndpointConfig()),
@ -42,7 +58,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
columns(): TableColumn[] {
return [
new TableColumn(msg("Order"), "order"),
new TableColumn(msg("Policy / User / Group")),
new TableColumn(this.allowedTypesLabel),
new TableColumn(msg("Enabled"), "enabled"),
new TableColumn(msg("Timeout"), "timeout"),
new TableColumn(msg("Actions")),
@ -121,7 +137,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
return [
{ key: msg("Order"), value: item.order.toString() },
{
key: msg("Policy / User / Group"),
key: this.allowedTypesLabel,
value: this.getPolicyUserGroupRowLabel(item),
},
];
@ -156,8 +172,9 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
<ak-policy-binding-form
slot="form"
.instancePk=${item.pk}
.allowedTypes=${this.allowedTypes}
.typeNotices=${this.typeNotices}
targetPk=${ifDefined(this.target)}
?policyOnly=${this.policyOnly}
>
</ak-policy-binding-form>
<button slot="trigger" class="pf-c-button pf-m-secondary">
@ -183,7 +200,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
<ak-policy-binding-form
slot="form"
targetPk=${ifDefined(this.target)}
?policyOnly=${this.policyOnly}
.allowedTypes=${this.allowedTypes}
.typeNotices=${this.typeNotices}
>
</ak-policy-binding-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
@ -196,22 +214,25 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
}
renderToolbar(): TemplateResult {
return html`<ak-policy-wizard
createText=${msg("Create and bind Policy")}
?showBindingPage=${true}
bindingTarget=${ifDefined(this.target)}
></ak-policy-wizard>
return html`${this.allowedTypes.includes(PolicyBindingCheckTarget.policy)
? html`<ak-policy-wizard
createText=${msg("Create and bind Policy")}
?showBindingPage=${true}
bindingTarget=${ifDefined(this.target)}
></ak-policy-wizard>`
: nothing}
<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create Binding")} </span>
<ak-policy-binding-form
slot="form"
targetPk=${ifDefined(this.target)}
?policyOnly=${this.policyOnly}
.allowedTypes=${this.allowedTypes}
.typeNotices=${this.typeNotices}
>
</ak-policy-binding-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Bind existing policy/group/user")}
${msg(str`Bind existing ${this.allowedTypesLabel}`)}
</button>
</ak-forms-modal> `;
}

View File

@ -1,3 +1,7 @@
import {
PolicyBindingCheckTarget,
PolicyBindingCheckTargetToLabel,
} from "@goauthentik/admin/policies/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-toggle-group";
@ -7,7 +11,7 @@ import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize";
import { CSSResult } from "lit";
import { CSSResult, nothing } from "lit";
import { TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
@ -25,11 +29,7 @@ import {
User,
} from "@goauthentik/api";
enum target {
policy = "policy",
group = "group",
user = "user",
}
export type PolicyBindingNotice = { type: PolicyBindingCheckTarget; notice: string };
@customElement("ak-policy-binding-form")
export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
@ -38,13 +38,13 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
policyBindingUuid: pk,
});
if (binding?.policyObj) {
this.policyGroupUser = target.policy;
this.policyGroupUser = PolicyBindingCheckTarget.policy;
}
if (binding?.groupObj) {
this.policyGroupUser = target.group;
this.policyGroupUser = PolicyBindingCheckTarget.group;
}
if (binding?.userObj) {
this.policyGroupUser = target.user;
this.policyGroupUser = PolicyBindingCheckTarget.user;
}
this.defaultOrder = await this.getOrder();
return binding;
@ -54,10 +54,17 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
targetPk?: string;
@state()
policyGroupUser: target = target.policy;
policyGroupUser: PolicyBindingCheckTarget = PolicyBindingCheckTarget.policy;
@property({ type: Boolean })
policyOnly = false;
@property({ type: Array })
allowedTypes: PolicyBindingCheckTarget[] = [
PolicyBindingCheckTarget.group,
PolicyBindingCheckTarget.user,
PolicyBindingCheckTarget.policy,
];
@property({ type: Array })
typeNotices: PolicyBindingNotice[] = [];
@state()
defaultOrder = 0;
@ -74,20 +81,26 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
return [...super.styles, PFContent];
}
async load(): Promise<void> {
// Overwrite the default for policyGroupUser with the first allowed type,
// as this function is called when the correct parameters are set
this.policyGroupUser = this.allowedTypes[0];
}
send(data: PolicyBinding): Promise<unknown> {
if (this.targetPk) {
data.target = this.targetPk;
}
switch (this.policyGroupUser) {
case target.policy:
case PolicyBindingCheckTarget.policy:
data.user = null;
data.group = null;
break;
case target.group:
case PolicyBindingCheckTarget.group:
data.policy = null;
data.user = null;
break;
case target.user:
case PolicyBindingCheckTarget.user:
data.policy = null;
data.group = null;
break;
@ -122,13 +135,18 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
renderModeSelector(): TemplateResult {
return html` <ak-toggle-group
value=${this.policyGroupUser}
@ak-toggle=${(ev: CustomEvent<{ value: target }>) => {
@ak-toggle=${(ev: CustomEvent<{ value: PolicyBindingCheckTarget }>) => {
this.policyGroupUser = ev.detail.value;
}}
>
<option value=${target.policy}>${msg("Policy")}</option>
<option value=${target.group}>${msg("Group")}</option>
<option value=${target.user}>${msg("User")}</option>
${Object.keys(PolicyBindingCheckTarget).map((ct) => {
if (this.allowedTypes.includes(ct as PolicyBindingCheckTarget)) {
return html`<option value=${ct}>
${PolicyBindingCheckTargetToLabel(ct as PolicyBindingCheckTarget)}
</option>`;
}
return nothing;
})}
</ak-toggle-group>`;
}
@ -139,7 +157,7 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
<ak-form-element-horizontal
label=${msg("Policy")}
name="policy"
?hidden=${this.policyGroupUser !== target.policy}
?hidden=${this.policyGroupUser !== PolicyBindingCheckTarget.policy}
>
<ak-search-select
.groupBy=${(items: Policy[]) => {
@ -169,11 +187,16 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
?blankable=${true}
>
</ak-search-select>
${this.typeNotices
.filter(({ type }) => type === PolicyBindingCheckTarget.policy)
.map((msg) => {
return html`<p class="pf-c-form__helper-text">${msg.notice}</p>`;
})}
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Group")}
name="group"
?hidden=${this.policyGroupUser !== target.group}
?hidden=${this.policyGroupUser !== PolicyBindingCheckTarget.group}
>
<ak-search-select
.fetchObjects=${async (query?: string): Promise<Group[]> => {
@ -201,18 +224,16 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
?blankable=${true}
>
</ak-search-select>
${this.policyOnly
? html`<p class="pf-c-form__helper-text">
${msg(
"Group mappings can only be checked if a user is already logged in when trying to access this source.",
)}
</p>`
: html``}
${this.typeNotices
.filter(({ type }) => type === PolicyBindingCheckTarget.group)
.map((msg) => {
return html`<p class="pf-c-form__helper-text">${msg.notice}</p>`;
})}
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("User")}
name="user"
?hidden=${this.policyGroupUser !== target.user}
?hidden=${this.policyGroupUser !== PolicyBindingCheckTarget.user}
>
<ak-search-select
.fetchObjects=${async (query?: string): Promise<User[]> => {
@ -240,13 +261,11 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
?blankable=${true}
>
</ak-search-select>
${this.policyOnly
? html`<p class="pf-c-form__helper-text">
${msg(
"User mappings can only be checked if a user is already logged in when trying to access this source.",
)}
</p>`
: html``}
${this.typeNotices
.filter(({ type }) => type === PolicyBindingCheckTarget.user)
.map((msg) => {
return html`<p class="pf-c-form__helper-text">${msg.notice}</p>`;
})}
</ak-form-element-horizontal>
</div>
</div>

View File

@ -0,0 +1,18 @@
import { msg } from "@lit/localize";
export enum PolicyBindingCheckTarget {
policy = "policy",
group = "group",
user = "user",
}
export function PolicyBindingCheckTargetToLabel(ct: PolicyBindingCheckTarget): string {
switch (ct) {
case PolicyBindingCheckTarget.group:
return msg("Group");
case PolicyBindingCheckTarget.user:
return msg("User");
case PolicyBindingCheckTarget.policy:
return msg("Policy");
}
}

View File

@ -2,6 +2,7 @@ import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/sources/oauth/OAuthSourceDiagram";
import "@goauthentik/admin/sources/oauth/OAuthSourceForm";
import { sourceBindingTypeNotices } from "@goauthentik/admin/sources/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -240,7 +241,10 @@ export class OAuthSourceViewPage extends AKElement {
)}
</div>
<div class="pf-c-card__body">
<ak-bound-policies-list .target=${this.source.pk} ?policyOnly=${true}>
<ak-bound-policies-list
.target=${this.source.pk}
.typeNotices=${sourceBindingTypeNotices()}
>
</ak-bound-policies-list>
</div>
</div>

View File

@ -1,6 +1,7 @@
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/sources/plex/PlexSourceForm";
import { sourceBindingTypeNotices } from "@goauthentik/admin/sources/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -130,7 +131,10 @@ export class PlexSourceViewPage extends AKElement {
)}
</div>
<div class="pf-c-card__body">
<ak-bound-policies-list .target=${this.source.pk} ?policyOnly=${true}>
<ak-bound-policies-list
.target=${this.source.pk}
.typeNotices=${sourceBindingTypeNotices()}
>
</ak-bound-policies-list>
</div>
</div>

View File

@ -1,6 +1,7 @@
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/sources/saml/SAMLSourceForm";
import { sourceBindingTypeNotices } from "@goauthentik/admin/sources/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -207,7 +208,10 @@ export class SAMLSourceViewPage extends AKElement {
)}
</div>
<div class="pf-c-card__body">
<ak-bound-policies-list .target=${this.source.pk} ?policyOnly=${true}>
<ak-bound-policies-list
.target=${this.source.pk}
.typeNotices=${sourceBindingTypeNotices()}
>
</ak-bound-policies-list>
</div>
</div>

View File

@ -1,3 +1,6 @@
import { PolicyBindingCheckTarget } from "@goauthentik/admin/policies/utils";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
export function renderSourceIcon(name: string, iconUrl: string | undefined | null): TemplateResult {
@ -11,3 +14,20 @@ export function renderSourceIcon(name: string, iconUrl: string | undefined | nul
}
return icon;
}
export function sourceBindingTypeNotices() {
return [
{
type: PolicyBindingCheckTarget.group,
notice: msg(
"Group mappings can only be checked if a user is already logged in when trying to access this source.",
),
},
{
type: PolicyBindingCheckTarget.user,
notice: msg(
"User mappings can only be checked if a user is already logged in when trying to access this source.",
),
},
];
}