Merge branch 'main' into web/sidebar-with-live-content-3
* main: (42 commits) stages/authenticator_totp: fix API validation error due to choices (#7608) website: fix pricing page inconsistency (#7607) web: bump API Client version (#7602) translate: Updates for file web/xliff/en.xlf in zh_CN (#7603) core: bump goauthentik.io/api/v3 from 3.2023103.2 to 3.2023103.3 (#7606) translate: Updates for file web/xliff/en.xlf in zh-Hans (#7604) Revert "web: bump @lit-labs/context from 0.4.1 to 0.5.1 in /web (#7486)" root: fix API schema for kotlin (#7601) web: bump @lit-labs/context from 0.4.1 to 0.5.1 in /web (#7486) translate: Updates for file web/xliff/en.xlf in zh-Hans (#7583) events: fix missing model_* events when not directly authenticated (#7588) translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW (#7594) providers/scim: fix missing schemas attribute for User and Group (#7477) core: bump pydantic from 2.5.0 to 2.5.1 (#7592) web/admin: contextually add user to group when creating user from group page (#7586) website/blog: title and slug change (#7585) events: sanitize functions (#7587) stages/email: use uuid for email confirmation token instead of username (#7581) website/blog: Blog about zero trust and wireguard (#7567) ci: translation-advice: avoid commenting after make i18n-extract ...
This commit is contained in:
@ -8,10 +8,10 @@ import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
|
||||
import { AdminApi, OutpostsApi, System } from "@goauthentik/api";
|
||||
import { AdminApi, OutpostsApi, SystemInfo } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-admin-status-system")
|
||||
export class SystemStatusCard extends AdminStatusCard<System> {
|
||||
export class SystemStatusCard extends AdminStatusCard<SystemInfo> {
|
||||
now?: Date;
|
||||
|
||||
icon = "pf-icon pf-icon-server";
|
||||
@ -19,7 +19,7 @@ export class SystemStatusCard extends AdminStatusCard<System> {
|
||||
@state()
|
||||
statusSummary?: string;
|
||||
|
||||
async getPrimaryValue(): Promise<System> {
|
||||
async getPrimaryValue(): Promise<SystemInfo> {
|
||||
this.now = new Date();
|
||||
let status = await new AdminApi(DEFAULT_CONFIG).adminSystemRetrieve();
|
||||
if (status.embeddedOutpostHost === "" || !status.embeddedOutpostHost.includes("http")) {
|
||||
@ -50,7 +50,7 @@ export class SystemStatusCard extends AdminStatusCard<System> {
|
||||
});
|
||||
}
|
||||
|
||||
getStatus(value: System): Promise<AdminStatus> {
|
||||
getStatus(value: SystemInfo): Promise<AdminStatus> {
|
||||
if (value.embeddedOutpostHost === "") {
|
||||
this.statusSummary = msg("Warning");
|
||||
return Promise.resolve<AdminStatus>({
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import "@goauthentik/admin/groups/GroupForm";
|
||||
import "@goauthentik/admin/users/RelatedUserList";
|
||||
import "@goauthentik/app/admin/groups/RelatedUserList";
|
||||
import "@goauthentik/app/elements/rbac/ObjectPermissionsPage";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
|
||||
@ -24,7 +24,7 @@ import { UserOption } from "@goauthentik/elements/user/utils";
|
||||
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { CSSResult, TemplateResult, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
@ -402,7 +402,16 @@ export class RelatedUserList extends Table<User> {
|
||||
<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Create")} </span>
|
||||
<span slot="header"> ${msg("Create User")} </span>
|
||||
<ak-user-form slot="form"> </ak-user-form>
|
||||
${this.targetGroup
|
||||
? html`
|
||||
<div class="pf-c-banner pf-m-info" slot="above-form">
|
||||
${msg(
|
||||
str`This user will be added to the group "${this.targetGroup.name}".`,
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<ak-user-form .group=${this.targetGroup} slot="form"> </ak-user-form>
|
||||
<a slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
${msg("Create user")}
|
||||
</a>
|
||||
@ -415,7 +424,17 @@ export class RelatedUserList extends Table<User> {
|
||||
>
|
||||
<span slot="submit"> ${msg("Create")} </span>
|
||||
<span slot="header"> ${msg("Create Service account")} </span>
|
||||
<ak-user-service-account slot="form"> </ak-user-service-account>
|
||||
${this.targetGroup
|
||||
? html`
|
||||
<div class="pf-c-banner pf-m-info" slot="above-form">
|
||||
${msg(
|
||||
str`This user will be added to the group "${this.targetGroup.name}".`,
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<ak-user-service-account-form .group=${this.targetGroup} slot="form">
|
||||
</ak-user-service-account-form>
|
||||
<a slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
${msg("Create Service account")}
|
||||
</a>
|
||||
@ -22,17 +22,14 @@ export class PasswordPolicyForm extends ModelForm<PasswordPolicy, string> {
|
||||
@state()
|
||||
showZxcvbn = false;
|
||||
|
||||
loadInstance(pk: string): Promise<PasswordPolicy> {
|
||||
return new PoliciesApi(DEFAULT_CONFIG)
|
||||
.policiesPasswordRetrieve({
|
||||
policyUuid: pk,
|
||||
})
|
||||
.then((policy) => {
|
||||
this.showStatic = policy.checkStaticRules || false;
|
||||
this.showHIBP = policy.checkHaveIBeenPwned || false;
|
||||
this.showZxcvbn = policy.checkZxcvbn || false;
|
||||
return policy;
|
||||
});
|
||||
async loadInstance(pk: string): Promise<PasswordPolicy> {
|
||||
const policy = await new PoliciesApi(DEFAULT_CONFIG).policiesPasswordRetrieve({
|
||||
policyUuid: pk,
|
||||
});
|
||||
this.showStatic = policy.checkStaticRules || false;
|
||||
this.showHIBP = policy.checkHaveIBeenPwned || false;
|
||||
this.showZxcvbn = policy.checkZxcvbn || false;
|
||||
return policy;
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
@ -200,26 +197,26 @@ export class PasswordPolicyForm extends ModelForm<PasswordPolicy, string> {
|
||||
)}
|
||||
</p>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("0: Too guessable: risky password. (guesses < 10^3)")}
|
||||
${msg("0: Too guessable: risky password. (guesses < 10^3)")}
|
||||
</p>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"1: Very guessable: protection from throttled online attacks. (guesses < 10^6)",
|
||||
"1: Very guessable: protection from throttled online attacks. (guesses < 10^6)",
|
||||
)}
|
||||
</p>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"2: Somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)",
|
||||
"2: Somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)",
|
||||
)}
|
||||
</p>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"3: Safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)",
|
||||
"3: Safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)",
|
||||
)}
|
||||
</p>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"4: Very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)",
|
||||
"4: Very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
@ -184,28 +184,31 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
|
||||
</p>
|
||||
</ak-form-element-horizontal> `
|
||||
: html``}
|
||||
${this.providerType.slug === ProviderTypeEnum.Openidconnect
|
||||
? html`
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("OIDC Well-known URL")}
|
||||
name="oidcWellKnownUrl"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(
|
||||
this.instance?.oidcWellKnownUrl,
|
||||
this.providerType.oidcWellKnownUrl,
|
||||
"",
|
||||
)}"
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"OIDC well-known configuration URL. Can be used to automatically configure the URLs above.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
${this.providerType.slug === ProviderTypeEnum.Openidconnect ||
|
||||
this.providerType.oidcWellKnownUrl !== ""
|
||||
? html`<ak-form-element-horizontal
|
||||
label=${msg("OIDC Well-known URL")}
|
||||
name="oidcWellKnownUrl"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(
|
||||
this.instance?.oidcWellKnownUrl,
|
||||
this.providerType.oidcWellKnownUrl,
|
||||
"",
|
||||
)}"
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"OIDC well-known configuration URL. Can be used to automatically configure the URLs above.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>`
|
||||
: html``}
|
||||
${this.providerType.slug === ProviderTypeEnum.Openidconnect ||
|
||||
this.providerType.oidcJwksUrl !== ""
|
||||
? html`<ak-form-element-horizontal
|
||||
label=${msg("OIDC JWKS URL")}
|
||||
name="oidcJwksUrl"
|
||||
>
|
||||
@ -224,7 +227,6 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-form-element-horizontal label=${msg("OIDC JWKS")} name="oidcJwks">
|
||||
<ak-codemirror
|
||||
mode=${CodeMirrorMode.JavaScript}
|
||||
@ -232,8 +234,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
|
||||
>
|
||||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">${msg("Raw JWKS data.")}</p>
|
||||
</ak-form-element-horizontal>
|
||||
`
|
||||
</ak-form-element-horizontal>`
|
||||
: html``}
|
||||
</div>
|
||||
</ak-form-group>`;
|
||||
|
||||
@ -89,14 +89,14 @@ export class AuthenticatorTOTPStageForm extends ModelForm<AuthenticatorTOTPStage
|
||||
>
|
||||
<select name="users" class="pf-c-form-control">
|
||||
<option
|
||||
value="${DigitsEnum.NUMBER_6}"
|
||||
?selected=${this.instance?.digits === DigitsEnum.NUMBER_6}
|
||||
value="${DigitsEnum._6}"
|
||||
?selected=${this.instance?.digits === DigitsEnum._6}
|
||||
>
|
||||
${msg("6 digits, widely compatible")}
|
||||
</option>
|
||||
<option
|
||||
value="${DigitsEnum.NUMBER_8}"
|
||||
?selected=${this.instance?.digits === DigitsEnum.NUMBER_8}
|
||||
value="${DigitsEnum._8}"
|
||||
?selected=${this.instance?.digits === DigitsEnum._8}
|
||||
>
|
||||
${msg(
|
||||
"8 digits, not compatible with apps like Google Authenticator",
|
||||
|
||||
@ -4,19 +4,30 @@ import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { CoreApi, UserServiceAccountRequest, UserServiceAccountResponse } from "@goauthentik/api";
|
||||
import {
|
||||
CoreApi,
|
||||
Group,
|
||||
UserServiceAccountRequest,
|
||||
UserServiceAccountResponse,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-user-service-account")
|
||||
@customElement("ak-user-service-account-form")
|
||||
export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
|
||||
@property({ attribute: false })
|
||||
result?: UserServiceAccountResponse;
|
||||
|
||||
@property({ attribute: false })
|
||||
group?: Group;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.group) {
|
||||
return msg(str`Successfully created user and added to group ${this.group.name}`);
|
||||
}
|
||||
return msg("Successfully created user.");
|
||||
}
|
||||
|
||||
@ -26,6 +37,14 @@ export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
|
||||
});
|
||||
this.result = result;
|
||||
(this.parentElement as ModalForm).showSubmitButton = false;
|
||||
if (this.group) {
|
||||
await new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
||||
groupUuid: this.group.pk,
|
||||
userAccountRequest: {
|
||||
pk: this.result.userPk,
|
||||
},
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -8,15 +8,18 @@ import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { CoreApi, User, UserTypeEnum } from "@goauthentik/api";
|
||||
import { CoreApi, Group, User, UserTypeEnum } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-user-form")
|
||||
export class UserForm extends ModelForm<User, number> {
|
||||
@property({ attribute: false })
|
||||
group?: Group;
|
||||
|
||||
static get defaultUserAttributes(): { [key: string]: unknown } {
|
||||
return {};
|
||||
}
|
||||
@ -42,6 +45,9 @@ export class UserForm extends ModelForm<User, number> {
|
||||
if (this.instance) {
|
||||
return msg("Successfully updated user.");
|
||||
} else {
|
||||
if (this.group) {
|
||||
return msg(str`Successfully created user and added to group ${this.group.name}`);
|
||||
}
|
||||
return msg("Successfully created user.");
|
||||
}
|
||||
}
|
||||
@ -50,21 +56,31 @@ export class UserForm extends ModelForm<User, number> {
|
||||
if (data.attributes === null) {
|
||||
data.attributes = UserForm.defaultUserAttributes;
|
||||
}
|
||||
let user;
|
||||
if (this.instance?.pk) {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUsersPartialUpdate({
|
||||
user = await new CoreApi(DEFAULT_CONFIG).coreUsersPartialUpdate({
|
||||
id: this.instance.pk,
|
||||
patchedUserRequest: data,
|
||||
});
|
||||
} else {
|
||||
data.groups = [];
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUsersCreate({
|
||||
user = await new CoreApi(DEFAULT_CONFIG).coreUsersCreate({
|
||||
userRequest: data,
|
||||
});
|
||||
}
|
||||
if (this.group) {
|
||||
await new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
||||
groupUuid: this.group.pk,
|
||||
userAccountRequest: {
|
||||
pk: user.pk,
|
||||
},
|
||||
});
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html` <ak-form-element-horizontal
|
||||
return html`<ak-form-element-horizontal
|
||||
label=${msg("Username")}
|
||||
?required=${true}
|
||||
name="username"
|
||||
|
||||
@ -399,7 +399,7 @@ export class UserListPage extends TablePage<User> {
|
||||
<ak-forms-modal .closeAfterSuccessfulSubmit=${false} .cancelText=${msg("Close")}>
|
||||
<span slot="submit"> ${msg("Create")} </span>
|
||||
<span slot="header"> ${msg("Create Service account")} </span>
|
||||
<ak-user-service-account slot="form"> </ak-user-service-account>
|
||||
<ak-user-service-account-form slot="form"> </ak-user-service-account-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${msg("Create Service account")}
|
||||
</button>
|
||||
|
||||
@ -194,7 +194,6 @@ export abstract class Table<T> extends AKElement {
|
||||
this.data = await this.apiEndpoint(this.page);
|
||||
this.error = undefined;
|
||||
this.page = this.data.pagination.current;
|
||||
const newSelected: T[] = [];
|
||||
const newExpanded: T[] = [];
|
||||
this.data.results.forEach((res) => {
|
||||
const jsonRes = JSON.stringify(res);
|
||||
@ -214,18 +213,12 @@ export abstract class Table<T> extends AKElement {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const selectedIndex = this.selectedElements.findIndex(comp);
|
||||
if (selectedIndex > -1) {
|
||||
newSelected.push(res);
|
||||
}
|
||||
const expandedIndex = this.expandedElements.findIndex(comp);
|
||||
if (expandedIndex > -1) {
|
||||
newExpanded.push(res);
|
||||
}
|
||||
});
|
||||
this.isLoading = false;
|
||||
this.selectedElements = newSelected;
|
||||
this.expandedElements = newExpanded;
|
||||
} catch (ex) {
|
||||
this.isLoading = false;
|
||||
|
||||
@ -75,6 +75,8 @@ export class IdentificationStage extends BaseStage<
|
||||
// meaning that without the auto-redirect the user would only have the option
|
||||
// to manually click on the source button
|
||||
if ((this.challenge.userFields || []).length !== 0) return;
|
||||
// we also don't want to auto-redirect if there's a passwordless URL configured
|
||||
if (this.challenge.passwordlessUrl) return;
|
||||
const source = this.challenge.sources[0];
|
||||
this.host.challenge = source.challenge;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user