Repository navigation
Expose password policy provider help text in the Admin Console #50806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
enoquefcd
wants to merge
1
commit into
keycloak:main
Choose a base branch
from
enoquefcd:password-policy-helptext
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
js/apps/admin-ui/src/authentication/policies/PolicyRow.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { cleanup, render, screen } from "@testing-library/react"; | ||
| import i18n, { type i18n as I18nInstance } from "i18next"; | ||
| import type { ReactNode } from "react"; | ||
| import { FormProvider, useForm } from "react-hook-form"; | ||
| import { I18nextProvider, initReactI18next } from "react-i18next"; | ||
| import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; | ||
|
|
||
| import { PolicyRow } from "./PolicyRow"; | ||
|
|
||
| vi.mock("@keycloak/keycloak-ui-shared", async (importOriginal) => ({ | ||
| ...(await importOriginal()), | ||
| HelpItem: ({ helpText }: { helpText: string }) => ( | ||
| <span data-testid="policy-help-text">{helpText}</span> | ||
| ), | ||
| })); | ||
|
|
||
| let testI18n: I18nInstance; | ||
|
|
||
| afterEach(cleanup); | ||
|
|
||
| beforeAll(async () => { | ||
| testI18n = i18n.createInstance(); | ||
| await testI18n.use(initReactI18next).init({ | ||
| lng: "en", | ||
| resources: { | ||
| en: { | ||
| translation: { | ||
| passwordPoliciesHelp: { | ||
| translatedPolicy: "Translated policy help text.", | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
| }); | ||
|
|
||
| const TestForm = ({ children }: { children: ReactNode }) => { | ||
| const form = useForm(); | ||
| return <FormProvider {...form}>{children}</FormProvider>; | ||
| }; | ||
|
|
||
| const renderPolicy = (id: string, helpText: string) => | ||
| render( | ||
| <I18nextProvider i18n={testI18n}> | ||
| <TestForm> | ||
| <PolicyRow | ||
| policy={{ id, displayName: id, helpText }} | ||
| onRemove={vi.fn()} | ||
| /> | ||
| </TestForm> | ||
| </I18nextProvider>, | ||
| ); | ||
|
|
||
| describe("PolicyRow help text", () => { | ||
| it("falls back to the provider help text when no translation exists", () => { | ||
| renderPolicy("custom-policy", "Provider help text."); | ||
|
|
||
| expect(screen.getByTestId("policy-help-text").textContent).toBe( | ||
| "Provider help text.", | ||
| ); | ||
| }); | ||
|
|
||
| it("prefers an existing translation over the provider help text", () => { | ||
| renderPolicy("translatedPolicy", "Provider help text."); | ||
|
|
||
| expect(screen.getByTestId("policy-help-text").textContent).toBe( | ||
| "Translated policy help text.", | ||
| ); | ||
| }); | ||
|
|
||
| it("falls back to the raw message key when provider help text is empty", () => { | ||
| renderPolicy("empty-help-text-policy", ""); | ||
|
|
||
| expect(screen.getByTestId("policy-help-text").textContent).toBe( | ||
| "passwordPoliciesHelp.empty-help-text-policy", | ||
| ); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
tests/base/src/test/java/org/keycloak/tests/admin/ServerInfoPasswordPolicyTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package org.keycloak.tests.admin; | ||
|
|
||
| import org.keycloak.admin.client.Keycloak; | ||
| import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation; | ||
| import org.keycloak.representations.info.ServerInfoRepresentation; | ||
| import org.keycloak.testframework.annotations.InjectAdminClient; | ||
| import org.keycloak.testframework.annotations.KeycloakIntegrationTest; | ||
| import org.keycloak.tests.common.CustomProvidersServerConfig; | ||
| import org.keycloak.tests.providers.policy.TestConfiguredPasswordPolicyProviderFactory; | ||
|
|
||
| import org.junit.jupiter.api.Assertions; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
|
|
||
| @KeycloakIntegrationTest(config = CustomProvidersServerConfig.class) | ||
| public class ServerInfoPasswordPolicyTest { | ||
|
|
||
| @InjectAdminClient | ||
| Keycloak adminClient; | ||
|
|
||
| @Test | ||
| public void testPasswordPolicyHelpText() { | ||
| ServerInfoRepresentation info = adminClient.serverInfo().getInfo(); | ||
| assertNotNull(info.getPasswordPolicies()); | ||
|
|
||
| PasswordPolicyTypeRepresentation configuredPolicy = findPolicy(info, TestConfiguredPasswordPolicyProviderFactory.ID); | ||
| assertEquals(TestConfiguredPasswordPolicyProviderFactory.HELP_TEXT, configuredPolicy.getHelpText()); | ||
| assertEquals("Test Configured Policy", configuredPolicy.getDisplayName()); | ||
|
|
||
| PasswordPolicyTypeRepresentation lengthPolicy = findPolicy(info, "length"); | ||
| Assertions.assertNull(lengthPolicy.getHelpText()); | ||
| } | ||
|
|
||
| private PasswordPolicyTypeRepresentation findPolicy(ServerInfoRepresentation info, String id) { | ||
| return info.getPasswordPolicies().stream() | ||
| .filter(policy -> id.equals(policy.getId())) | ||
| .findFirst().orElseThrow(() -> new RuntimeException("Not found password policy with ID '" + id + "'")); | ||
| } | ||
| } |
108 changes: 108 additions & 0 deletions
108
...java/org/keycloak/tests/providers/policy/TestConfiguredPasswordPolicyProviderFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| package org.keycloak.tests.providers.policy; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.keycloak.Config; | ||
| import org.keycloak.models.KeycloakSession; | ||
| import org.keycloak.models.KeycloakSessionFactory; | ||
| import org.keycloak.models.RealmModel; | ||
| import org.keycloak.models.UserModel; | ||
| import org.keycloak.policy.PasswordPolicyProvider; | ||
| import org.keycloak.policy.PasswordPolicyProviderFactory; | ||
| import org.keycloak.policy.PolicyError; | ||
| import org.keycloak.provider.ConfiguredProvider; | ||
| import org.keycloak.provider.ProviderConfigProperty; | ||
| import org.keycloak.provider.ProviderConfigurationBuilder; | ||
|
|
||
| /** | ||
| * Custom password policy provider implementing {@link ConfiguredProvider}, used to verify that the | ||
| * provider-supplied help text is exposed through the server info endpoint. | ||
| */ | ||
| public class TestConfiguredPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory, ConfiguredProvider { | ||
|
|
||
| public static final String ID = "test-configured-policy"; | ||
|
|
||
| public static final String HELP_TEXT = "Test policy help text provided by the factory."; | ||
|
|
||
| @Override | ||
| public String getId() { | ||
| return ID; | ||
| } | ||
|
|
||
| @Override | ||
| public PasswordPolicyProvider create(KeycloakSession session) { | ||
| return new TestConfiguredPasswordPolicyProvider(); | ||
| } | ||
|
|
||
| @Override | ||
| public void init(Config.Scope config) { | ||
| } | ||
|
|
||
| @Override | ||
| public void postInit(KeycloakSessionFactory factory) { | ||
| } | ||
|
|
||
| @Override | ||
| public String getDisplayName() { | ||
| return "Test Configured Policy"; | ||
| } | ||
|
|
||
| @Override | ||
| public String getConfigType() { | ||
| return PasswordPolicyProvider.STRING_CONFIG_TYPE; | ||
| } | ||
|
|
||
| @Override | ||
| public String getDefaultConfigValue() { | ||
| return "default-value"; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isMultiplSupported() { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public String getHelpText() { | ||
| return HELP_TEXT; | ||
| } | ||
|
|
||
| @Override | ||
| public List<ProviderConfigProperty> getConfigProperties() { | ||
| return ProviderConfigurationBuilder.create() | ||
| .property() | ||
| .name("value") | ||
| .label("Value") | ||
| .helpText("Value of the test policy.") | ||
| .type(ProviderConfigProperty.STRING_TYPE) | ||
| .defaultValue("default-value") | ||
| .add() | ||
| .build(); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() { | ||
| } | ||
|
|
||
| private static class TestConfiguredPasswordPolicyProvider implements PasswordPolicyProvider { | ||
|
|
||
| @Override | ||
| public PolicyError validate(RealmModel realm, UserModel user, String password) { | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public PolicyError validate(String user, String password) { | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public Object parseConfig(String value) { | ||
| return value; | ||
| } | ||
|
|
||
| @Override | ||
| public void close() { | ||
| } | ||
| } | ||
| } |
1 change: 1 addition & 0 deletions
1
...rs/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| org.keycloak.tests.providers.policy.TestConfiguredPasswordPolicyProviderFactory |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.