diff --git a/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java index b141d3d1f70..d9b74d0a670 100644 --- a/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java @@ -28,6 +28,7 @@ public class ComponentTypeRepresentation { protected String id; protected String helpText; protected List properties; + protected List clientProperties; protected Map metadata = new HashMap<>(); @@ -56,6 +57,14 @@ public class ComponentTypeRepresentation { this.properties = properties; } + public List getClientProperties() { + return clientProperties; + } + + public void setClientProperties(List clientProperties) { + this.clientProperties = clientProperties; + } + /** * Extra information about the component * that might come from annotations or interfaces that the component implements. diff --git a/js/apps/admin-ui/src/clients/credentials/Credentials.tsx b/js/apps/admin-ui/src/clients/credentials/Credentials.tsx index 76479a4e7b9..7c58f03301e 100644 --- a/js/apps/admin-ui/src/clients/credentials/Credentials.tsx +++ b/js/apps/admin-ui/src/clients/credentials/Credentials.tsx @@ -34,6 +34,7 @@ import { FormFields } from "../ClientDetails"; import { ClientSecret } from "./ClientSecret"; import { SignedJWT } from "./SignedJWT"; import { X509 } from "./X509"; +import { convertAttributeNameToForm } from "../../util"; type AccessToken = { registrationAccessToken: string; @@ -80,7 +81,7 @@ export const Credentials = ({ client, save, refresh }: CredentialsProps) => { () => componentTypes?.["org.keycloak.authentication.ClientAuthenticator"]?.find( (p) => p.id === clientAuthenticatorType, - )?.properties, + )?.clientProperties, [clientAuthenticatorType, componentTypes], ); @@ -186,7 +187,9 @@ export const Credentials = ({ client, save, refresh }: CredentialsProps) => {
`attributes.${name}`} + convertToName={(name) => + convertAttributeNameToForm(`attributes.${name}`) + } /> )} diff --git a/js/libs/keycloak-admin-client/src/defs/componentTypeRepresentation.ts b/js/libs/keycloak-admin-client/src/defs/componentTypeRepresentation.ts index 36ebfb8b7e4..d858a7fb4a4 100644 --- a/js/libs/keycloak-admin-client/src/defs/componentTypeRepresentation.ts +++ b/js/libs/keycloak-admin-client/src/defs/componentTypeRepresentation.ts @@ -7,5 +7,6 @@ export default interface ComponentTypeRepresentation { id: string; helpText: string; properties: ConfigPropertyRepresentation[]; + clientProperties: ConfigPropertyRepresentation[]; metadata: { [index: string]: any }; } diff --git a/server-spi-private/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java b/server-spi-private/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java index d8539f8f202..8d6dcd9b4fe 100644 --- a/server-spi-private/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java +++ b/server-spi-private/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java @@ -18,10 +18,9 @@ package org.keycloak.authentication; import org.keycloak.models.ClientModel; -import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.provider.ConfiguredPerClientProvider; import org.keycloak.provider.ProviderFactory; -import java.util.List; import java.util.Map; import java.util.Set; @@ -34,7 +33,7 @@ import java.util.Set; * * @author Marek Posolda */ -public interface ClientAuthenticatorFactory extends ProviderFactory, ConfigurableAuthenticatorFactory { +public interface ClientAuthenticatorFactory extends ProviderFactory, ConfigurableAuthenticatorFactory, ConfiguredPerClientProvider { ClientAuthenticator create(); /** @@ -45,14 +44,6 @@ public interface ClientAuthenticatorFactory extends ProviderFactory getConfigPropertiesPerClient(); - /** * Get configuration, which needs to be used for adapter ( keycloak.json ) of particular client. Some implementations * may return just template and user needs to edit the values according to his environment (For example fill the location of keystore file) diff --git a/server-spi/src/main/java/org/keycloak/provider/ConfiguredPerClientProvider.java b/server-spi/src/main/java/org/keycloak/provider/ConfiguredPerClientProvider.java new file mode 100755 index 00000000000..fa386244158 --- /dev/null +++ b/server-spi/src/main/java/org/keycloak/provider/ConfiguredPerClientProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 2025 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.provider; + +import java.util.List; + +/** + * @author Giuseppe Graziano + */ +public interface ConfiguredPerClientProvider extends ConfiguredProvider { + + /** + * List of config properties for this client implementation. Those will be shown in admin console in clients credentials tab and can be configured per client. + * + * @return + */ + List getConfigPropertiesPerClient(); +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java index da6b6217467..6c7e65c0020 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java @@ -21,6 +21,7 @@ import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.extensions.Extension; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.resteasy.reactive.NoCache; +import org.keycloak.provider.ConfiguredPerClientProvider; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; import org.keycloak.broker.social.SocialIdentityProvider; @@ -184,6 +185,10 @@ public class ServerInfoAdminResource { if (pi instanceof ComponentFactory) { rep.setMetadata(((ComponentFactory)pi).getTypeMetadata()); } + if (pi instanceof ConfiguredPerClientProvider) { + List configClientProperties = ((ConfiguredPerClientProvider) pi).getConfigPropertiesPerClient(); + rep.setClientProperties(ModelToRepresentation.toRepresentation(configClientProperties)); + } List reps = info.getComponentTypes().get(spi.getProviderClass().getName()); if (reps == null) { reps = new LinkedList<>();