web: add more related links, add policy/user/group support for bindings
This commit is contained in:
parent
6bcdf36ca6
commit
f8ba623fc1
|
@ -11,7 +11,7 @@ from authentik.lib.sentry import SentryIgnoredException
|
|||
def get_attrs(obj: SerializerModel) -> Dict[str, Any]:
|
||||
"""Get object's attributes via their serializer, and covert it to a normal dict"""
|
||||
data = dict(obj.serializer(obj).data)
|
||||
to_remove = ("policies", "stages", "pk", "background")
|
||||
to_remove = ("policies", "stages", "pk", "background", "group", "user")
|
||||
for to_remove_name in to_remove:
|
||||
if to_remove_name in data:
|
||||
data.pop(to_remove_name)
|
||||
|
|
|
@ -82,6 +82,8 @@ class FlowImporter:
|
|||
main_query = Q(pk=attrs["pk"])
|
||||
sub_query = Q()
|
||||
for identifier, value in attrs.items():
|
||||
if isinstance(value, dict):
|
||||
continue
|
||||
if identifier == "pk":
|
||||
continue
|
||||
sub_query &= Q(**{identifier: value})
|
||||
|
|
|
@ -99,15 +99,12 @@ class PolicyBindingSerializer(ModelSerializer):
|
|||
required=True,
|
||||
)
|
||||
|
||||
policy_obj = PolicySerializer(read_only=True, source="policy")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = PolicyBinding
|
||||
fields = [
|
||||
"pk",
|
||||
"policy",
|
||||
"policy_obj",
|
||||
"group",
|
||||
"user",
|
||||
"target",
|
||||
|
@ -115,12 +112,13 @@ class PolicyBindingSerializer(ModelSerializer):
|
|||
"order",
|
||||
"timeout",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class PolicyBindingViewSet(ModelViewSet):
|
||||
"""PolicyBinding Viewset"""
|
||||
|
||||
queryset = PolicyBinding.objects.all()
|
||||
queryset = PolicyBinding.objects.all().select_related("policy", "target", "group", "user")
|
||||
serializer_class = PolicyBindingSerializer
|
||||
filterset_fields = ["policy", "target", "enabled", "order", "timeout"]
|
||||
search_fields = ["policy__name"]
|
||||
|
|
320
swagger.yaml
320
swagger.yaml
|
@ -8643,21 +8643,327 @@ definitions:
|
|||
format: uuid
|
||||
readOnly: true
|
||||
policy:
|
||||
title: Policy
|
||||
description: Policies which specify if a user is authorized to use an Application.
|
||||
Can be overridden by other types to add other fields, more logic, etc.
|
||||
type: object
|
||||
properties:
|
||||
policy_uuid:
|
||||
title: Policy uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
created:
|
||||
title: Created
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
last_updated:
|
||||
title: Last updated
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
x-nullable: true
|
||||
policy_obj:
|
||||
$ref: '#/definitions/Policy'
|
||||
execution_logging:
|
||||
title: Execution logging
|
||||
description: When this option is enabled, all executions of this policy
|
||||
will be logged. By default, only execution errors are logged.
|
||||
type: boolean
|
||||
readOnly: true
|
||||
group:
|
||||
title: Group
|
||||
description: Custom Group model which supports a basic hierarchy
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
group_uuid:
|
||||
title: Group uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 80
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
description: Users added to this group will be superusers.
|
||||
type: boolean
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
parent:
|
||||
description: Custom Group model which supports a basic hierarchy
|
||||
required:
|
||||
- name
|
||||
- parent
|
||||
type: object
|
||||
properties:
|
||||
group_uuid:
|
||||
title: Group uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 80
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
description: Users added to this group will be superusers.
|
||||
type: boolean
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
parent:
|
||||
title: Parent
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
readOnly: true
|
||||
user:
|
||||
description: Custom User model to allow easier adding o f user-based settings
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
password:
|
||||
title: Password
|
||||
type: string
|
||||
maxLength: 128
|
||||
minLength: 1
|
||||
last_login:
|
||||
title: Last login
|
||||
type: string
|
||||
format: date-time
|
||||
x-nullable: true
|
||||
username:
|
||||
title: Username
|
||||
description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_
|
||||
only.
|
||||
type: string
|
||||
pattern: ^[\w.@+-]+$
|
||||
maxLength: 150
|
||||
minLength: 1
|
||||
first_name:
|
||||
title: First name
|
||||
type: string
|
||||
maxLength: 150
|
||||
last_name:
|
||||
title: Last name
|
||||
type: string
|
||||
maxLength: 150
|
||||
email:
|
||||
title: Email address
|
||||
type: string
|
||||
format: email
|
||||
maxLength: 254
|
||||
is_active:
|
||||
title: Active
|
||||
description: Designates whether this user should be treated as active.
|
||||
Unselect this instead of deleting accounts.
|
||||
type: boolean
|
||||
date_joined:
|
||||
title: Date joined
|
||||
type: string
|
||||
format: date-time
|
||||
uuid:
|
||||
title: Uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
description: User's display name.
|
||||
type: string
|
||||
minLength: 1
|
||||
password_change_date:
|
||||
title: Password change date
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
groups:
|
||||
description: ''
|
||||
type: array
|
||||
items:
|
||||
description: Groups are a generic way of categorizing users to apply
|
||||
permissions, or some other label, to those users. A user can belong
|
||||
to any number of groups. A user in a group automatically has all the
|
||||
permissions granted to that group. For example, if the group 'Site
|
||||
editors' has the permission can_edit_home_page, any user in that group
|
||||
will have that permission. Beyond permissions, groups are a convenient
|
||||
way to categorize users to apply some label, or extended functionality,
|
||||
to them. For example, you could create a group 'Special users', and
|
||||
you could write code that would do special things to those users --
|
||||
such as giving them access to a members-only portion of your site,
|
||||
or sending them members-only email messages.
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 150
|
||||
minLength: 1
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
user_permissions:
|
||||
description: ''
|
||||
type: array
|
||||
items:
|
||||
description: "The permissions system provides a way to assign permissions\
|
||||
\ to specific users and groups of users. The permission system is\
|
||||
\ used by the Django admin site, but may also be useful in your own\
|
||||
\ code. The Django admin site uses permissions as follows: - The \"\
|
||||
add\" permission limits the user's ability to view the \"add\" form\
|
||||
\ and add an object. - The \"change\" permission limits a user's ability\
|
||||
\ to view the change list, view the \"change\" form and change an\
|
||||
\ object. - The \"delete\" permission limits the ability to delete\
|
||||
\ an object. - The \"view\" permission limits the ability to view\
|
||||
\ an object. Permissions are set globally per type of object, not\
|
||||
\ per specific object instance. It is possible to say \"Mary may change\
|
||||
\ news stories,\" but it's not currently possible to say \"Mary may\
|
||||
\ change news stories, but only the ones she created herself\" or\
|
||||
\ \"Mary may only change news stories that have a certain status or\
|
||||
\ publication date.\" The permissions listed above are automatically\
|
||||
\ created for each model."
|
||||
required:
|
||||
- name
|
||||
- codename
|
||||
- content_type
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
codename:
|
||||
title: Codename
|
||||
type: string
|
||||
maxLength: 100
|
||||
minLength: 1
|
||||
content_type:
|
||||
title: Content type
|
||||
type: integer
|
||||
readOnly: true
|
||||
sources:
|
||||
description: ''
|
||||
type: array
|
||||
items:
|
||||
description: Base Authentication source, i.e. an OAuth Provider, SAML
|
||||
Remote or LDAP Server
|
||||
required:
|
||||
- name
|
||||
- slug
|
||||
type: object
|
||||
properties:
|
||||
pbm_uuid:
|
||||
title: Pbm uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
description: Source's display Name.
|
||||
type: string
|
||||
minLength: 1
|
||||
slug:
|
||||
title: Slug
|
||||
description: Internal source name, used in URLs.
|
||||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+$
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
enabled:
|
||||
title: Enabled
|
||||
type: boolean
|
||||
authentication_flow:
|
||||
title: Authentication flow
|
||||
description: Flow to use when authenticating existing users.
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
user:
|
||||
title: User
|
||||
type: integer
|
||||
enrollment_flow:
|
||||
title: Enrollment flow
|
||||
description: Flow to use when enrolling new users.
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
policies:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
uniqueItems: true
|
||||
property_mappings:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
ak_groups:
|
||||
description: ''
|
||||
type: array
|
||||
items:
|
||||
description: Custom Group model which supports a basic hierarchy
|
||||
required:
|
||||
- name
|
||||
- parent
|
||||
type: object
|
||||
properties:
|
||||
group_uuid:
|
||||
title: Group uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 80
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
description: Users added to this group will be superusers.
|
||||
type: boolean
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
parent:
|
||||
title: Parent
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
readOnly: true
|
||||
target:
|
||||
title: Target
|
||||
type: string
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Group } from "./Groups";
|
||||
import { Policy } from "./Policies";
|
||||
import { User } from "./Users";
|
||||
|
||||
export class PolicyBinding {
|
||||
pk: string;
|
||||
policy: string;
|
||||
policy_obj: Policy;
|
||||
policy_obj?: Policy;
|
||||
group?: Group;
|
||||
user?: User;
|
||||
target: string;
|
||||
enabled: boolean;
|
||||
order: number;
|
||||
|
|
|
@ -24,7 +24,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||
|
||||
columns(): TableColumn[] {
|
||||
return [
|
||||
new TableColumn("Policy"),
|
||||
new TableColumn("Policy / User / Group"),
|
||||
new TableColumn("Enabled", "enabled"),
|
||||
new TableColumn("Order", "order"),
|
||||
new TableColumn("Timeout", "timeout"),
|
||||
|
@ -32,9 +32,21 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||
];
|
||||
}
|
||||
|
||||
getPolicyUserGroupRow(item: PolicyBinding): string {
|
||||
if (item.policy_obj) {
|
||||
return gettext(`Policy ${item.policy_obj.name}`);
|
||||
} else if (item.group) {
|
||||
return gettext(`Group ${item.group.name}`);
|
||||
} else if (item.user) {
|
||||
return gettext(`User ${item.user.name}`);
|
||||
} else {
|
||||
return gettext(``);
|
||||
}
|
||||
}
|
||||
|
||||
row(item: PolicyBinding): TemplateResult[] {
|
||||
return [
|
||||
html`${item.policy_obj.name}`,
|
||||
html`${this.getPolicyUserGroupRow(item)}`,
|
||||
html`${item.enabled ? "Yes" : "No"}`,
|
||||
html`${item.order}`,
|
||||
html`${item.timeout}`,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { commands } from "codemirror";
|
||||
import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||
import { COMMON_STYLES } from "../../common/styles";
|
||||
import { SpinnerSize } from "../Spinner";
|
||||
|
||||
@customElement("ak-loading-state")
|
||||
export class LoadingState extends LitElement {
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return COMMON_STYLES;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-l-bullseye__item">
|
||||
<ak-spinner size="${SpinnerSize.XLarge}"></ak-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import "../../elements/AdminLoginsChart";
|
|||
import "../../elements/buttons/ModalButton";
|
||||
import "../../elements/buttons/SpinnerButton";
|
||||
import "../../elements/policies/BoundPoliciesList";
|
||||
import "../../elements/utils/LoadingState";
|
||||
|
||||
@customElement("ak-application-view")
|
||||
export class ApplicationViewPage extends LitElement {
|
||||
|
@ -37,7 +38,7 @@ export class ApplicationViewPage extends LitElement {
|
|||
|
||||
render(): TemplateResult {
|
||||
if (!this.application) {
|
||||
return html``;
|
||||
return html`<ak-loading-state></ak-loading-state>`;;
|
||||
}
|
||||
return html`<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
|
@ -49,7 +50,7 @@ export class ApplicationViewPage extends LitElement {
|
|||
</div>
|
||||
</section>
|
||||
<ak-tabs>
|
||||
<section slot="page-1" data-tab-title="${gettext("Users")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<section slot="page-1" data-tab-title="${gettext("Overview")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-l-gallery pf-m-gutter">
|
||||
<div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 3;grid-row-end: span 2;">
|
||||
<div class="pf-c-card__header">
|
||||
|
@ -64,6 +65,31 @@ export class ApplicationViewPage extends LitElement {
|
|||
</ak-admin-logins-chart>`: ""}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-2-col">
|
||||
<div class="pf-c-card__header">
|
||||
<div class="pf-c-card__header-main">
|
||||
<i class="fas fa-external-link-alt"></i> ${gettext("Related")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<dl class="pf-c-description-list pf-m-horizontal">
|
||||
${this.application.provider ?
|
||||
html`<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text">${gettext("Provider")}</span>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<a href="#/providers/${this.application.provider.pk}">
|
||||
${this.application.provider.name}
|
||||
</a>
|
||||
</div>
|
||||
</dd>
|
||||
</div>`:
|
||||
html``}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div slot="page-2" data-tab-title="${gettext("Policy Bindings")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
|
|
|
@ -13,11 +13,6 @@ import "./FlowDiagram";
|
|||
|
||||
@customElement("ak-flow-view")
|
||||
export class FlowViewPage extends LitElement {
|
||||
@property()
|
||||
set args(value: { [key: string]: string }) {
|
||||
this.flowSlug = value.slug;
|
||||
}
|
||||
|
||||
@property()
|
||||
set flowSlug(value: string) {
|
||||
Flow.get(value).then((flow) => (this.flow = flow));
|
||||
|
|
|
@ -4,7 +4,6 @@ import { COMMON_STYLES } from "../../common/styles";
|
|||
|
||||
import "../../elements/buttons/ModalButton";
|
||||
import "../../elements/buttons/SpinnerButton";
|
||||
import { SpinnerSize } from "../../elements/Spinner";
|
||||
|
||||
import "./SAMLProviderViewPage";
|
||||
import "./OAuth2ProviderViewPage";
|
||||
|
@ -27,15 +26,7 @@ export class ProviderViewPage extends LitElement {
|
|||
|
||||
render(): TemplateResult {
|
||||
if (!this.provider) {
|
||||
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-l-bullseye__item">
|
||||
<ak-spinner size="${SpinnerSize.XLarge}"></ak-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
return html`<ak-loading-state></ak-loading-state>`;;
|
||||
}
|
||||
switch (this.provider?.object_type) {
|
||||
case "saml":
|
||||
|
|
|
@ -36,7 +36,7 @@ export const ROUTES: Route[] = [
|
|||
return html`<ak-source-view .args=${args}></ak-source-view>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||
return html`<ak-flow-view .args=${args}></ak-flow-view>`;
|
||||
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/events/log$"), html`<ak-event-list></ak-event-list>`),
|
||||
new Route(new RegExp(`^/events/log/(?<id>${UUID_REGEX})$`)).then((args) => {
|
||||
|
|
|
@ -47,15 +47,7 @@ export function htmlFromString(...strings: string[]): TemplateResult {
|
|||
|
||||
export function loading<T>(v: T, actual: TemplateResult): TemplateResult {
|
||||
if (!v) {
|
||||
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-l-bullseye__item">
|
||||
<ak-spinner size="${SpinnerSize.XLarge}"></ak-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
return html`<ak-loading-state></ak-loading-state>`;
|
||||
}
|
||||
return actual;
|
||||
}
|
||||
|
|
Reference in New Issue