diff --git a/js/apps/admin-ui/src/clients/credentials/Credentials.tsx b/js/apps/admin-ui/src/clients/credentials/Credentials.tsx index 34f5b8c9cb..895f132727 100644 --- a/js/apps/admin-ui/src/clients/credentials/Credentials.tsx +++ b/js/apps/admin-ui/src/clients/credentials/Credentials.tsx @@ -67,6 +67,10 @@ export const Credentials = ({ client, save, refresh }: CredentialsProps) => { const [accessToken, setAccessToken] = useState(""); const [open, isOpen] = useState(false); + const selectedProvider = providers.find( + (provider) => provider.id === clientAuthenticatorType, + ); + useFetch( () => Promise.all([ @@ -200,17 +204,17 @@ export const Credentials = ({ client, save, refresh }: CredentialsProps) => { - {(clientAuthenticatorType === "client-secret" || - clientAuthenticatorType === "client-secret-jwt") && } - {(clientAuthenticatorType === "client-secret" || - clientAuthenticatorType === "client-secret-jwt") && ( - - - + {selectedProvider?.supportsSecret && ( + <> + + + + + )} diff --git a/js/libs/keycloak-admin-client/src/defs/authenticatorConfigRepresentation.ts b/js/libs/keycloak-admin-client/src/defs/authenticatorConfigRepresentation.ts index 00830a86a4..a46ca76246 100644 --- a/js/libs/keycloak-admin-client/src/defs/authenticatorConfigRepresentation.ts +++ b/js/libs/keycloak-admin-client/src/defs/authenticatorConfigRepresentation.ts @@ -13,4 +13,5 @@ export interface AuthenticationProviderRepresentation { id?: string; displayName?: string; description?: string; + supportsSecret?: boolean; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java index 4fadf64571..5438a01845 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java @@ -158,17 +158,27 @@ public class AuthenticationManagementResource { @Operation( summary = "Get client authenticator providers Returns a stream of client authenticator providers.") public Stream> getClientAuthenticatorProviders() { auth.realm().requireViewClientAuthenticatorProviders(); + Stream factories = session.getKeycloakSessionFactory().getProviderFactoriesStream(ClientAuthenticator.class); - return buildProviderMetadata(session.getKeycloakSessionFactory().getProviderFactoriesStream(ClientAuthenticator.class)); + return factories.map(factory -> { + Map data = new HashMap<>(); + buildProviderMetadataHelper(data, factory); + data.put("supportsSecret", ((ClientAuthenticatorFactory) factory).supportsSecret()); + return data; + }); + } + + private void buildProviderMetadataHelper(Map data, ProviderFactory factory) { + data.put("id", factory.getId()); + ConfigurableAuthenticatorFactory configured = (ConfigurableAuthenticatorFactory) factory; + data.put("description", configured.getHelpText()); + data.put("displayName", configured.getDisplayType()); } public Stream> buildProviderMetadata(Stream factories) { return factories.map(factory -> { Map data = new HashMap<>(); - data.put("id", factory.getId()); - ConfigurableAuthenticatorFactory configured = (ConfigurableAuthenticatorFactory)factory; - data.put("description", configured.getHelpText()); - data.put("displayName", configured.getDisplayType()); + buildProviderMetadataHelper(data, factory); return data; }); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java index fff1c85e03..7b0c0cb28c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java @@ -80,20 +80,20 @@ public class ProvidersTest extends AbstractAuthenticationTest { List> result = authMgmtResource.getClientAuthenticatorProviders(); List> expected = new LinkedList<>(); - addProviderInfo(expected, "client-jwt", "Signed Jwt", - "Validates client based on signed JWT issued by client and signed with the Client private key"); - addProviderInfo(expected, "client-secret", "Client Id and Secret", "Validates client based on 'client_id' and " + - "'client_secret' sent either in request parameters or in 'Authorization: Basic' header"); - addProviderInfo(expected, "testsuite-client-passthrough", "Testsuite Dummy Client Validation", "Testsuite dummy authenticator, " + - "which automatically authenticates hardcoded client (like 'test-app' )"); - addProviderInfo(expected, "testsuite-client-dummy", "Testsuite ClientId Dummy", - "Dummy client authenticator, which authenticates the client with clientId only"); - addProviderInfo(expected, "client-x509", "X509 Certificate", - "Validates client based on a X509 Certificate"); - addProviderInfo(expected, "client-secret-jwt", "Signed Jwt with Client Secret", - "Validates client based on signed JWT issued by client and signed with the Client Secret"); - addProviderInfo(expected, "testsuite-client-id-required", "Signed Jwt", - "Validates client based on signed JWT issued by client and signed with the Client private key"); + addClientAuthenticatorProviderInfo(expected, "client-jwt", "Signed Jwt", + "Validates client based on signed JWT issued by client and signed with the Client private key", false); + addClientAuthenticatorProviderInfo(expected, "client-secret", "Client Id and Secret", "Validates client based on 'client_id' and " + + "'client_secret' sent either in request parameters or in 'Authorization: Basic' header", true); + addClientAuthenticatorProviderInfo(expected, "testsuite-client-id-required", "Signed Jwt", "Validates client based on signed JWT issued by client " + + "and signed with the Client private key", false); + addClientAuthenticatorProviderInfo(expected, "testsuite-client-passthrough", "Testsuite Dummy Client Validation", "Testsuite dummy authenticator, " + + "which automatically authenticates hardcoded client (like 'test-app' )", false); + addClientAuthenticatorProviderInfo(expected, "testsuite-client-dummy", "Testsuite ClientId Dummy", + "Dummy client authenticator, which authenticates the client with clientId only", false); + addClientAuthenticatorProviderInfo(expected, "client-x509", "X509 Certificate", + "Validates client based on a X509 Certificate", false); + addClientAuthenticatorProviderInfo(expected, "client-secret-jwt", "Signed Jwt with Client Secret", + "Validates client based on signed JWT issued by client and signed with the Client Secret", true); compareProviders(expected, result); } @@ -259,12 +259,20 @@ public class ProvidersTest extends AbstractAuthenticationTest { list.add(item); } + private void addClientAuthenticatorProviderInfo(List> list, String id, String displayName, String description, boolean supportsSecret) { + HashMap item = new HashMap<>(); + item.put("id", id); + item.put("displayName", displayName); + item.put("description", description); + item.put("supportsSecret", supportsSecret); + list.add(item); + } + private static class ProviderComparator implements Comparator> { @Override public int compare(Map o1, Map o2) { return String.valueOf(o1.get("id")).compareTo(String.valueOf(o2.get("id"))); } + } - - }