Ensure list of supported applications is stable (#3646)

This commit is contained in:
Jon Koops 2022-10-25 17:46:16 +02:00 committed by GitHub
parent c401fa6eee
commit 44436f5935
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 30 additions and 18 deletions

View file

@ -20,10 +20,13 @@ describe("Policies", () => {
}); });
it("should change to hotp", () => { it("should change to hotp", () => {
otpPoliciesPage.checkSupportedActions("FreeOTP", "Google Authenticator"); otpPoliciesPage.checkSupportedApplications(
"FreeOTP",
"Google Authenticator"
);
otpPoliciesPage.setPolicyType("hotp").increaseInitialCounter().save(); otpPoliciesPage.setPolicyType("hotp").increaseInitialCounter().save();
masthead.checkNotificationMessage("OTP policy successfully updated"); masthead.checkNotificationMessage("OTP policy successfully updated");
otpPoliciesPage.checkSupportedActions("FreeOTP"); otpPoliciesPage.checkSupportedApplications("FreeOTP");
}); });
}); });

View file

@ -14,10 +14,10 @@ export default class OTPPolicies {
return this; return this;
} }
checkSupportedActions(...supportedActions: string[]) { checkSupportedApplications(...supportedApplications: string[]) {
cy.findByTestId("supportedActions").should( cy.findByTestId("supportedApplications").should(
"have.text", "have.text",
supportedActions.join("") supportedApplications.join("")
); );
return this; return this;
} }

View file

@ -14,7 +14,7 @@
"lookAhead": "How far ahead should the server look just in case the token generator and server are out of time sync or counter sync?", "lookAhead": "How far ahead should the server look just in case the token generator and server are out of time sync or counter sync?",
"otpPolicyPeriod": "How many seconds should an OTP token be valid? Defaults to 30 seconds.", "otpPolicyPeriod": "How many seconds should an OTP token be valid? Defaults to 30 seconds.",
"otpPolicyCodeReusable": "Possibility to use the same OTP code again after successful authentication.", "otpPolicyCodeReusable": "Possibility to use the same OTP code again after successful authentication.",
"supportedActions": "Applications that are known to work with the current OTP policy", "supportedApplications": "Applications that are known to work with the current OTP policy",
"webauthnIntro": "What is this form used for?", "webauthnIntro": "What is this form used for?",
"webAuthnPolicyFormHelp": "Policy for WebAuthn authentication. This one will be used by 'WebAuthn Register' required action and 'WebAuthn Authenticator' authenticator. Typical usage is, when WebAuthn will be used for the two-factor authentication.", "webAuthnPolicyFormHelp": "Policy for WebAuthn authentication. This one will be used by 'WebAuthn Register' required action and 'WebAuthn Authenticator' authenticator. Typical usage is, when WebAuthn will be used for the two-factor authentication.",
"webAuthnPolicyPasswordlessFormHelp": "Policy for passwordless WebAuthn authentication. This one will be used by 'Webauthn Register Passwordless' required action and 'WebAuthn Passwordless Authenticator' authenticator. Typical usage is, when WebAuthn will be used as first-factor authentication. Having both 'WebAuthn Policy' and 'WebAuthn Passwordless Policy' allows to use WebAuthn as both first factor and second factor authenticator in the same realm.", "webAuthnPolicyPasswordlessFormHelp": "Policy for passwordless WebAuthn authentication. This one will be used by 'Webauthn Register Passwordless' required action and 'WebAuthn Passwordless Authenticator' authenticator. Typical usage is, when WebAuthn will be used as first-factor authentication. Having both 'WebAuthn Policy' and 'WebAuthn Passwordless Policy' allows to use WebAuthn as both first factor and second factor authenticator in the same realm.",

View file

@ -27,7 +27,7 @@
"otpPolicyCodeReusable": "Reusable token", "otpPolicyCodeReusable": "Reusable token",
"initialCounter": "Initial counter", "initialCounter": "Initial counter",
"initialCounterErrorHint": "Value needs to be between 1 and 120", "initialCounterErrorHint": "Value needs to be between 1 and 120",
"supportedActions": "Supported actions", "supportedApplications": "Supported applications",
"otpSupportedApplications": { "otpSupportedApplications": {
"totpAppFreeOTPName": "FreeOTP", "totpAppFreeOTPName": "FreeOTP",
"totpAppGoogleName": "Google Authenticator" "totpAppGoogleName": "Google Authenticator"

View file

@ -7,7 +7,7 @@
"otpHashAlgorithm": "OTPを生成するのにどのハッシュ・アルゴリズムを使用するか設定します。", "otpHashAlgorithm": "OTPを生成するのにどのハッシュ・アルゴリズムを使用するか設定します。",
"otpPolicyDigits": "OTPの桁数を設定します。", "otpPolicyDigits": "OTPの桁数を設定します。",
"otpPolicyPeriod": "OTPトークンが有効な秒数を設定します。デフォルトは30秒です。", "otpPolicyPeriod": "OTPトークンが有効な秒数を設定します。デフォルトは30秒です。",
"supportedActions": "現在のOTPポリシーで動作することが分かっているアプリケーション", "supportedApplications": "現在のOTPポリシーで動作することが分かっているアプリケーション",
"webAuthnPolicyFormHelp": "WebAuthn認証のポリシー。これは、「WebAuthn Register」必須アクションと「WebAuthn Authenticator」オーセンティケーターで使用されます。一般的な用途は、2要素認証にWebAuthnを使用する場合です。", "webAuthnPolicyFormHelp": "WebAuthn認証のポリシー。これは、「WebAuthn Register」必須アクションと「WebAuthn Authenticator」オーセンティケーターで使用されます。一般的な用途は、2要素認証にWebAuthnを使用する場合です。",
"webAuthnPolicyPasswordlessFormHelp": "パスワードレスWebAuthn認証のポリシー。これは、「Webauthn Register Passwordless」必須アクションおよび「WebAuthn Passwordless Authenticator」オーセンティケーターによって使用されます。一般的な使用法は、WebAuthnが一要素認証として使用される場合です。「WebAuthnポリシー」と「WebAuthnパスワードレス・ポリシー」の両方を使用すると、WebAuthnを同じレルムの第1要素オーセンティケーターと第2要素オーセンティケーターの両方として使用できます。", "webAuthnPolicyPasswordlessFormHelp": "パスワードレスWebAuthn認証のポリシー。これは、「Webauthn Register Passwordless」必須アクションおよび「WebAuthn Passwordless Authenticator」オーセンティケーターによって使用されます。一般的な使用法は、WebAuthnが一要素認証として使用される場合です。「WebAuthnポリシー」と「WebAuthnパスワードレス・ポリシー」の両方を使用すると、WebAuthnを同じレルムの第1要素オーセンティケーターと第2要素オーセンティケーターの両方として使用できます。",
"webAuthnPolicySignatureAlgorithms": "認証アサーションに使用する署名アルゴリズム。", "webAuthnPolicySignatureAlgorithms": "認証アサーションに使用する署名アルゴリズム。",

View file

@ -15,7 +15,7 @@ import {
SelectVariant, SelectVariant,
Switch, Switch,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useEffect } from "react"; import { useEffect, useMemo } from "react";
import { Controller, useForm, useWatch } from "react-hook-form"; import { Controller, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -25,6 +25,7 @@ import { HelpItem } from "../../components/help-enabler/HelpItem";
import { TimeSelector } from "../../components/time-selector/TimeSelector"; import { TimeSelector } from "../../components/time-selector/TimeSelector";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import useLocaleSort from "../../utils/useLocaleSort";
import useToggle from "../../utils/useToggle"; import useToggle from "../../utils/useToggle";
import "./otp-policy.css"; import "./otp-policy.css";
@ -49,7 +50,7 @@ export const OtpPolicy = ({ realm, realmUpdated }: OtpPolicyProps) => {
const { adminClient } = useAdminClient(); const { adminClient } = useAdminClient();
const { realm: realmName } = useRealm(); const { realm: realmName } = useRealm();
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const localeSort = useLocaleSort();
const [open, toggle] = useToggle(); const [open, toggle] = useToggle();
const otpType = useWatch<typeof POLICY_TYPES[number]>({ const otpType = useWatch<typeof POLICY_TYPES[number]>({
@ -62,6 +63,14 @@ export const OtpPolicy = ({ realm, realmUpdated }: OtpPolicyProps) => {
useEffect(() => setupForm(realm), []); useEffect(() => setupForm(realm), []);
const supportedApplications = useMemo(() => {
const labels = (realm.otpSupportedApplications ?? []).map((key) =>
t(`otpSupportedApplications.${key}`)
);
return localeSort(labels, (label) => label);
}, [realm.otpSupportedApplications]);
const save = async (realm: RealmRepresentation) => { const save = async (realm: RealmRepresentation) => {
try { try {
await adminClient.realms.update({ realm: realmName }, realm); await adminClient.realms.update({ realm: realmName }, realm);
@ -299,18 +308,18 @@ export const OtpPolicy = ({ realm, realmUpdated }: OtpPolicyProps) => {
</FormGroup> </FormGroup>
)} )}
<FormGroup <FormGroup
label={t("supportedActions")} label={t("supportedApplications")}
labelIcon={ labelIcon={
<HelpItem <HelpItem
helpText="authentication-help:supportedActions" helpText="authentication-help:supportedApplications"
fieldLabelId="authentication:supportedActions" fieldLabelId="authentication:supportedApplications"
/> />
} }
> >
<ChipGroup data-testid="supportedActions"> <ChipGroup data-testid="supportedApplications">
{realm.otpSupportedApplications?.map((key) => ( {supportedApplications.map((label) => (
<Chip key={key} isReadOnly> <Chip key={label} isReadOnly>
{t(`otpSupportedApplications.${key}`)} {label}
</Chip> </Chip>
))} ))}
</ChipGroup> </ChipGroup>

View file

@ -10,6 +10,6 @@
@media (min-width: 768px) { @media (min-width: 768px) {
.keycloak__otp_policies_authentication__form .pf-c-form__group { .keycloak__otp_policies_authentication__form .pf-c-form__group {
--pf-c-form--m-horizontal__group-label--md--GridColumnWidth: 10rem; --pf-c-form--m-horizontal__group-label--md--GridColumnWidth: 11rem;
} }
} }