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:
Jens L 2023-10-26 14:33:29 +02:00 committed by GitHub
parent 94ad839437
commit 28053059ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 139 additions and 5 deletions

View file

@ -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",
] ]

View file

@ -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",
),
),
]

View file

@ -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,

View file

@ -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(

View file

@ -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"

View file

@ -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:

View file

@ -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"

View file

@ -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> {

View file

@ -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>&lt;No name set&gt;</source> <source>&lt;No name set&gt;</source>
<target>&lt;No name set&gt;</target> <target>&lt;No name set&gt;</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>

View 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)