stages/user_write: allow setting user type when creating new user (#7293)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
94ad839437
commit
28053059ff
|
@ -15,6 +15,7 @@ class UserWriteStageSerializer(StageSerializer):
|
||||||
"user_creation_mode",
|
"user_creation_mode",
|
||||||
"create_users_as_inactive",
|
"create_users_as_inactive",
|
||||||
"create_users_group",
|
"create_users_group",
|
||||||
|
"user_type",
|
||||||
"user_path_template",
|
"user_path_template",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 4.2.6 on 2023-10-25 15:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("authentik_stages_user_write", "0007_remove_userwritestage_can_create_users_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="userwritestage",
|
||||||
|
name="user_type",
|
||||||
|
field=models.TextField(
|
||||||
|
choices=[
|
||||||
|
("internal", "Internal"),
|
||||||
|
("external", "External"),
|
||||||
|
("service_account", "Service Account"),
|
||||||
|
("internal_service_account", "Internal Service Account"),
|
||||||
|
],
|
||||||
|
default="external",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from rest_framework.serializers import BaseSerializer
|
from rest_framework.serializers import BaseSerializer
|
||||||
|
|
||||||
from authentik.core.models import Group
|
from authentik.core.models import Group, UserTypes
|
||||||
from authentik.flows.models import Stage
|
from authentik.flows.models import Stage
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,10 @@ class UserWriteStage(Stage):
|
||||||
help_text=_("Optionally add newly created users to this group."),
|
help_text=_("Optionally add newly created users to this group."),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
user_type = models.TextField(
|
||||||
|
choices=UserTypes.choices,
|
||||||
|
default=UserTypes.EXTERNAL,
|
||||||
|
)
|
||||||
user_path_template = models.TextField(
|
user_path_template = models.TextField(
|
||||||
default="",
|
default="",
|
||||||
blank=True,
|
blank=True,
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.utils.translation import gettext as _
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from authentik.core.middleware import SESSION_KEY_IMPERSONATE_USER
|
from authentik.core.middleware import SESSION_KEY_IMPERSONATE_USER
|
||||||
from authentik.core.models import USER_ATTRIBUTE_SOURCES, User, UserSourceConnection
|
from authentik.core.models import USER_ATTRIBUTE_SOURCES, User, UserSourceConnection, UserTypes
|
||||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import StageView
|
from authentik.flows.stage import StageView
|
||||||
|
@ -22,6 +22,7 @@ from authentik.stages.user_write.models import UserCreationMode
|
||||||
from authentik.stages.user_write.signals import user_write
|
from authentik.stages.user_write.signals import user_write
|
||||||
|
|
||||||
PLAN_CONTEXT_GROUPS = "groups"
|
PLAN_CONTEXT_GROUPS = "groups"
|
||||||
|
PLAN_CONTEXT_USER_TYPE = "user_type"
|
||||||
PLAN_CONTEXT_USER_PATH = "user_path"
|
PLAN_CONTEXT_USER_PATH = "user_path"
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +56,19 @@ class UserWriteStageView(StageView):
|
||||||
)
|
)
|
||||||
if path == "":
|
if path == "":
|
||||||
path = User.default_path()
|
path = User.default_path()
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_type = UserTypes(
|
||||||
|
self.executor.plan.context.get(
|
||||||
|
PLAN_CONTEXT_USER_TYPE,
|
||||||
|
self.executor.current_stage.user_type,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
user_type = self.executor.current_stage.user_type
|
||||||
|
if user_type == UserTypes.INTERNAL_SERVICE_ACCOUNT:
|
||||||
|
user_type = UserTypes.SERVICE_ACCOUNT
|
||||||
|
|
||||||
if not self.request.user.is_anonymous:
|
if not self.request.user.is_anonymous:
|
||||||
self.executor.plan.context.setdefault(PLAN_CONTEXT_PENDING_USER, self.request.user)
|
self.executor.plan.context.setdefault(PLAN_CONTEXT_PENDING_USER, self.request.user)
|
||||||
if (
|
if (
|
||||||
|
@ -66,6 +80,7 @@ class UserWriteStageView(StageView):
|
||||||
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = User(
|
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = User(
|
||||||
is_active=not self.executor.current_stage.create_users_as_inactive,
|
is_active=not self.executor.current_stage.create_users_as_inactive,
|
||||||
path=path,
|
path=path,
|
||||||
|
type=user_type,
|
||||||
)
|
)
|
||||||
self.executor.plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = BACKEND_INBUILT
|
self.executor.plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = BACKEND_INBUILT
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
|
|
|
@ -8368,6 +8368,16 @@
|
||||||
"title": "Create users group",
|
"title": "Create users group",
|
||||||
"description": "Optionally add newly created users to this group."
|
"description": "Optionally add newly created users to this group."
|
||||||
},
|
},
|
||||||
|
"user_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"internal",
|
||||||
|
"external",
|
||||||
|
"service_account",
|
||||||
|
"internal_service_account"
|
||||||
|
],
|
||||||
|
"title": "User type"
|
||||||
|
},
|
||||||
"user_path_template": {
|
"user_path_template": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "User path template"
|
"title": "User path template"
|
||||||
|
|
20
schema.yml
20
schema.yml
|
@ -27494,6 +27494,20 @@ paths:
|
||||||
name: user_path_template
|
name: user_path_template
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: user_type
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- external
|
||||||
|
- internal
|
||||||
|
- internal_service_account
|
||||||
|
- service_account
|
||||||
|
description: |-
|
||||||
|
* `internal` - Internal
|
||||||
|
* `external` - External
|
||||||
|
* `service_account` - Service Account
|
||||||
|
* `internal_service_account` - Internal Service Account
|
||||||
tags:
|
tags:
|
||||||
- stages
|
- stages
|
||||||
security:
|
security:
|
||||||
|
@ -38052,6 +38066,8 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Optionally add newly created users to this group.
|
description: Optionally add newly created users to this group.
|
||||||
|
user_type:
|
||||||
|
$ref: '#/components/schemas/UserTypeEnum'
|
||||||
user_path_template:
|
user_path_template:
|
||||||
type: string
|
type: string
|
||||||
PatchedWebAuthnDeviceRequest:
|
PatchedWebAuthnDeviceRequest:
|
||||||
|
@ -42422,6 +42438,8 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Optionally add newly created users to this group.
|
description: Optionally add newly created users to this group.
|
||||||
|
user_type:
|
||||||
|
$ref: '#/components/schemas/UserTypeEnum'
|
||||||
user_path_template:
|
user_path_template:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
@ -42452,6 +42470,8 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Optionally add newly created users to this group.
|
description: Optionally add newly created users to this group.
|
||||||
|
user_type:
|
||||||
|
$ref: '#/components/schemas/UserTypeEnum'
|
||||||
user_path_template:
|
user_path_template:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|
|
@ -12,7 +12,14 @@ import { TemplateResult, html } from "lit";
|
||||||
import { customElement } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import { CoreApi, CoreGroupsListRequest, Group, StagesApi, UserWriteStage } from "@goauthentik/api";
|
import {
|
||||||
|
CoreApi,
|
||||||
|
CoreGroupsListRequest,
|
||||||
|
Group,
|
||||||
|
StagesApi,
|
||||||
|
UserTypeEnum,
|
||||||
|
UserWriteStage,
|
||||||
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
@customElement("ak-stage-user-write-form")
|
@customElement("ak-stage-user-write-form")
|
||||||
export class UserWriteStageForm extends ModelForm<UserWriteStage, string> {
|
export class UserWriteStageForm extends ModelForm<UserWriteStage, string> {
|
||||||
|
@ -111,6 +118,42 @@ export class UserWriteStageForm extends ModelForm<UserWriteStage, string> {
|
||||||
${msg("Mark newly created users as inactive.")}
|
${msg("Mark newly created users as inactive.")}
|
||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${msg("User path template")}
|
||||||
|
name="userPathTemplate"
|
||||||
|
>
|
||||||
|
<ak-radio
|
||||||
|
.options=${[
|
||||||
|
{
|
||||||
|
label: "Internal",
|
||||||
|
value: UserTypeEnum.Internal,
|
||||||
|
default: true,
|
||||||
|
description: html`${msg(
|
||||||
|
"Internal users might be users such as company employees, which will get access to the full Enterprise feature set.",
|
||||||
|
)}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "External",
|
||||||
|
value: UserTypeEnum.External,
|
||||||
|
description: html`${msg(
|
||||||
|
"External users might be external consultants or B2C customers. These users don't get access to enterprise features.",
|
||||||
|
)}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Service account",
|
||||||
|
value: UserTypeEnum.ServiceAccount,
|
||||||
|
description: html`${msg(
|
||||||
|
"Service accounts should be used for machine-to-machine authentication or other automations.",
|
||||||
|
)}`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
.value=${this.instance?.userType}
|
||||||
|
>
|
||||||
|
</ak-radio>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg("User type used for newly created users.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("User path template")}
|
label=${msg("User path template")}
|
||||||
name="userPathTemplate"
|
name="userPathTemplate"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import "@goauthentik/admin/users/GroupSelectModal";
|
import "@goauthentik/admin/users/GroupSelectModal";
|
||||||
import { UserTypeEnum } from "@goauthentik/api/dist/models/UserTypeEnum";
|
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
|
@ -14,7 +13,7 @@ import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
import { customElement } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import { CoreApi, User } from "@goauthentik/api";
|
import { CoreApi, User, UserTypeEnum } from "@goauthentik/api";
|
||||||
|
|
||||||
@customElement("ak-user-form")
|
@customElement("ak-user-form")
|
||||||
export class UserForm extends ModelForm<User, number> {
|
export class UserForm extends ModelForm<User, number> {
|
||||||
|
|
|
@ -7930,6 +7930,15 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||||
<trans-unit id="s0924f51b028233a3">
|
<trans-unit id="s0924f51b028233a3">
|
||||||
<source><No name set></source>
|
<source><No name set></source>
|
||||||
<target><No name set></target>
|
<target><No name set></target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s66313b45b69cfc88">
|
||||||
|
<source>Check the release notes</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sb4d7bae2440d9781">
|
||||||
|
<source>User Statistics</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s32babfed740fd3c1">
|
||||||
|
<source>User type used for newly created users.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -120,6 +120,14 @@ If set, this must be a list of group objects and not group names.
|
||||||
|
|
||||||
Path the `pending_user` will be written to. If not set in the flow, falls back to the value set in the user_write stage, and otherwise to the `users` path.
|
Path the `pending_user` will be written to. If not set in the flow, falls back to the value set in the user_write stage, and otherwise to the `users` path.
|
||||||
|
|
||||||
|
##### `user_type` (string)
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Requires authentik 2023.10
|
||||||
|
:::
|
||||||
|
|
||||||
|
Type the `pending_user` will be created as. Must be one of `internal`, `external` or `service_account`.
|
||||||
|
|
||||||
#### Password stage
|
#### Password stage
|
||||||
|
|
||||||
##### `user_backend` (string)
|
##### `user_backend` (string)
|
||||||
|
|
Reference in a new issue