keycloak-uncached
Changes
services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java 14(+11 -3)
services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java 5(+3 -2)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java 15(+15 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java 14(+14 -0)
Details
diff --git a/common/src/main/java/org/keycloak/common/util/MultivaluedHashMap.java b/common/src/main/java/org/keycloak/common/util/MultivaluedHashMap.java
index dea1d50..82fede2 100755
--- a/common/src/main/java/org/keycloak/common/util/MultivaluedHashMap.java
+++ b/common/src/main/java/org/keycloak/common/util/MultivaluedHashMap.java
@@ -30,6 +30,13 @@ import java.util.Map;
@SuppressWarnings("serial")
public class MultivaluedHashMap<K, V> extends HashMap<K, List<V>>
{
+ public MultivaluedHashMap() {
+ }
+
+ public MultivaluedHashMap(MultivaluedHashMap<K, V> config) {
+ addAll(config);
+ }
+
public void putSingle(K key, V value)
{
List<V> list = new ArrayList<V>();
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ComponentUtil.java b/server-spi/src/main/java/org/keycloak/models/utils/ComponentUtil.java
index 507bfff..9ebb9cf 100644
--- a/server-spi/src/main/java/org/keycloak/models/utils/ComponentUtil.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ComponentUtil.java
@@ -23,6 +23,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
import java.util.HashMap;
import java.util.List;
@@ -33,9 +34,25 @@ import java.util.Map;
*/
public class ComponentUtil {
+ public static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, ComponentRepresentation component) {
+ return getComponentConfigProperties(session, component.getProviderType(), component.getProviderId());
+ }
+
public static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, ComponentModel component) {
+ return getComponentConfigProperties(session, component.getProviderType(), component.getProviderId());
+ }
+
+ public static ComponentFactory getComponentFactory(KeycloakSession session, ComponentRepresentation component) {
+ return getComponentFactory(session, component.getProviderType(), component.getProviderId());
+ }
+
+ public static ComponentFactory getComponentFactory(KeycloakSession session, ComponentModel component) {
+ return getComponentFactory(session, component.getProviderType(), component.getProviderId());
+ }
+
+ private static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, String providerType, String providerId) {
try {
- List<ProviderConfigProperty> l = getComponentFactory(session, component).getConfigProperties();
+ List<ProviderConfigProperty> l = getComponentFactory(session, providerType, providerId).getConfigProperties();
Map<String, ProviderConfigProperty> properties = new HashMap<>();
for (ProviderConfigProperty p : l) {
properties.put(p.getName(), p);
@@ -46,15 +63,15 @@ public class ComponentUtil {
}
}
- public static ComponentFactory getComponentFactory(KeycloakSession session, ComponentModel component) {
- Class<? extends Provider> provider = session.getProviderClass(component.getProviderType());
+ private static ComponentFactory getComponentFactory(KeycloakSession session, String providerType, String providerId) {
+ Class<? extends Provider> provider = session.getProviderClass(providerType);
if (provider == null) {
- throw new RuntimeException("Invalid provider type '" + component.getProviderType() + "'");
+ throw new RuntimeException("Invalid provider type '" + providerType + "'");
}
- ProviderFactory<? extends Provider> f = session.getKeycloakSessionFactory().getProviderFactory(provider, component.getProviderId());
+ ProviderFactory<? extends Provider> f = session.getKeycloakSessionFactory().getProviderFactory(provider, providerId);
if (f == null) {
- throw new RuntimeException("No such provider '" + component.getProviderId() + "'");
+ throw new RuntimeException("No such provider '" + providerId + "'");
}
ComponentFactory cf = (ComponentFactory) f;
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 2317352..569faf6 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -303,7 +303,7 @@ public class ModelToRepresentation {
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
rep.setAccessCodeLifespanLogin(realm.getAccessCodeLifespanLogin());
- rep.setSmtpServer(realm.getSmtpConfig());
+ rep.setSmtpServer(new HashMap<>(realm.getSmtpConfig()));
rep.setBrowserSecurityHeaders(realm.getBrowserSecurityHeaders());
rep.setAccountTheme(realm.getAccountTheme());
rep.setLoginTheme(realm.getLoginTheme());
@@ -385,6 +385,10 @@ public class ModelToRepresentation {
Map<String, String> attributes = realm.getAttributes();
rep.setAttributes(attributes);
+ if (!internal) {
+ rep = StripSecretsUtils.strip(rep);
+ }
+
return rep;
}
@@ -622,7 +626,7 @@ public class ModelToRepresentation {
providerRep.setStoreToken(identityProviderModel.isStoreToken());
providerRep.setTrustEmail(identityProviderModel.isTrustEmail());
providerRep.setAuthenticateByDefault(identityProviderModel.isAuthenticateByDefault());
- providerRep.setConfig(identityProviderModel.getConfig());
+ providerRep.setConfig(new HashMap<>(identityProviderModel.getConfig()));
providerRep.setAddReadTokenRoleOnCreate(identityProviderModel.isAddReadTokenRoleOnCreate());
String firstBrokerLoginFlowId = identityProviderModel.getFirstBrokerLoginFlowId();
@@ -796,24 +800,9 @@ public class ModelToRepresentation {
rep.setProviderType(component.getProviderType());
rep.setSubType(component.getSubType());
rep.setParentId(component.getParentId());
- if (internal) {
- rep.setConfig(component.getConfig());
- } else {
- Map<String, ProviderConfigProperty> configProperties = ComponentUtil.getComponentConfigProperties(session, component);
- MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
-
- for (Map.Entry<String, List<String>> e : component.getConfig().entrySet()) {
- ProviderConfigProperty configProperty = configProperties.get(e.getKey());
- if (configProperty != null) {
- if (configProperty.isSecret()) {
- config.putSingle(e.getKey(), ComponentRepresentation.SECRET_VALUE);
- } else {
- config.put(e.getKey(), e.getValue());
- }
- }
- }
-
- rep.setConfig(config);
+ rep.setConfig(new MultivaluedHashMap<>(component.getConfig()));
+ if (!internal) {
+ rep = StripSecretsUtils.strip(session, rep);
}
return rep;
}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 8ae1caa..b972cda 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -815,7 +815,12 @@ public class RepresentationToModel {
}
if (rep.getSmtpServer() != null) {
- realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
+ Map<String, String> config = new HashMap(rep.getSmtpServer());
+ if (rep.getSmtpServer().containsKey("password") && ComponentRepresentation.SECRET_VALUE.equals(rep.getSmtpServer().get("password"))) {
+ String passwordValue = realm.getSmtpConfig() != null ? realm.getSmtpConfig().get("password") : null;
+ config.put("password", passwordValue);
+ }
+ realm.setSmtpConfig(config);
}
if (rep.getBrowserSecurityHeaders() != null) {
@@ -1543,7 +1548,7 @@ public class RepresentationToModel {
identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
identityProviderModel.setStoreToken(representation.isStoreToken());
identityProviderModel.setAddReadTokenRoleOnCreate(representation.isAddReadTokenRoleOnCreate());
- identityProviderModel.setConfig(representation.getConfig());
+ identityProviderModel.setConfig(new HashMap<>(representation.getConfig()));
String flowAlias = representation.getFirstBrokerLoginFlowAlias();
if (flowAlias == null) {
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java b/server-spi/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java
new file mode 100644
index 0000000..06989a5
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 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.models.utils;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class StripSecretsUtils {
+
+ public static ComponentRepresentation strip(KeycloakSession session, ComponentRepresentation rep) {
+ Map<String, ProviderConfigProperty> configProperties = ComponentUtil.getComponentConfigProperties(session, rep);
+ Iterator<Map.Entry<String, List<String>>> itr = rep.getConfig().entrySet().iterator();
+ while (itr.hasNext()) {
+ Map.Entry<String, List<String>> next = itr.next();
+ ProviderConfigProperty configProperty = configProperties.get(next.getKey());
+ if (configProperty != null) {
+ if (configProperty.isSecret()) {
+ next.setValue(Collections.singletonList(ComponentRepresentation.SECRET_VALUE));
+ }
+ } else {
+ itr.remove();
+ }
+ }
+ return rep;
+ }
+
+ public static RealmRepresentation strip(RealmRepresentation rep) {
+ if (rep.getSmtpServer() != null && rep.getSmtpServer().containsKey("password")) {
+ rep.getSmtpServer().put("password", ComponentRepresentation.SECRET_VALUE);
+ }
+ return rep;
+ }
+
+ public static IdentityProviderRepresentation strip(IdentityProviderRepresentation rep) {
+ if (rep.getConfig() != null && rep.getConfig().containsKey("clientSecret")) {
+ rep.getConfig().put("clientSecret", ComponentRepresentation.SECRET_VALUE);
+ }
+ return rep;
+ }
+
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
index 5a0e817..31341d3 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
@@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
@@ -119,7 +120,7 @@ public class ComponentResource {
model = realm.addComponentModel(model);
- adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
+ adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(StripSecretsUtils.strip(session, rep)).success();
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
} catch (ComponentValidationException e) {
return localizedErrorResponse(e);
@@ -149,7 +150,7 @@ public class ComponentResource {
throw new NotFoundException("Could not find component");
}
RepresentationToModel.updateComponent(session, rep, model, false);
- adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
+ adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo, model.getId()).representation(StripSecretsUtils.strip(session, rep)).success();
realm.updateComponent(model);
return Response.noContent().build();
} catch (ComponentValidationException e) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index a0e369f..af1a1ec 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -35,8 +35,10 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
@@ -101,7 +103,7 @@ public class IdentityProviderResource {
}
IdentityProviderRepresentation rep = ModelToRepresentation.toRepresentation(realm, this.identityProviderModel);
- return rep;
+ return StripSecretsUtils.strip(rep);
}
/**
@@ -152,12 +154,18 @@ public class IdentityProviderResource {
}
}
- public static void updateIdpFromRep(IdentityProviderRepresentation providerRep, RealmModel realm, KeycloakSession session) {
+ private void updateIdpFromRep(IdentityProviderRepresentation providerRep, RealmModel realm, KeycloakSession session) {
String internalId = providerRep.getInternalId();
String newProviderId = providerRep.getAlias();
String oldProviderId = getProviderIdByInternalId(realm, internalId);
- realm.updateIdentityProvider(RepresentationToModel.toModel(realm, providerRep));
+ IdentityProviderModel updated = RepresentationToModel.toModel(realm, providerRep);
+
+ if (updated.getConfig() != null && ComponentRepresentation.SECRET_VALUE.equals(updated.getConfig().get("clientSecret"))) {
+ updated.getConfig().put("clientSecret", identityProviderModel.getConfig() != null ? identityProviderModel.getConfig().get("clientSecret") : null);
+ }
+
+ realm.updateIdentityProvider(updated);
if (oldProviderId != null && !oldProviderId.equals(newProviderId)) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index 05f1f9e..60e1075 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -33,6 +33,7 @@ import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.ErrorResponse;
@@ -167,7 +168,7 @@ public class IdentityProvidersResource {
List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
- representations.add(ModelToRepresentation.toRepresentation(realm, identityProviderModel));
+ representations.add(StripSecretsUtils.strip(ModelToRepresentation.toRepresentation(realm, identityProviderModel)));
}
return representations;
}
@@ -191,7 +192,7 @@ public class IdentityProvidersResource {
representation.setInternalId(identityProvider.getInternalId());
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, identityProvider.getAlias())
- .representation(representation).success();
+ .representation(StripSecretsUtils.strip(representation)).success();
return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getAlias()).build()).build();
} catch (ModelDuplicateException e) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 47db45e..05b4b9b 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -49,6 +49,7 @@ import org.keycloak.models.cache.UserCache;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.partialimport.PartialImportManager;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.provider.ProviderFactory;
@@ -309,7 +310,7 @@ public class RealmAdminResource {
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, false);
}
- adminEvent.operation(OperationType.UPDATE).representation(rep).success();
+ adminEvent.operation(OperationType.UPDATE).representation(StripSecretsUtils.strip(rep)).success();
return Response.noContent().build();
} catch (PatternSyntaxException e) {
return ErrorResponse.error("Specified regex pattern(s) is invalid.", Response.Status.BAD_REQUEST);
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
index 9798036..24e8b83 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
@@ -37,6 +37,7 @@ import org.keycloak.keys.KeyProviderFactory;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
@@ -638,6 +639,20 @@ public class TestingResourceProvider implements RealmResourceProvider {
return reps;
}
+ @GET
+ @Path("/smtp-config")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, String> getSmtpConfig() {
+ return session.getContext().getRealm().getSmtpConfig();
+ }
+
+ @GET
+ @Path("/identity-config")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, String> getIdentityProviderConfig(@QueryParam("alias") String alias) {
+ return session.getContext().getRealm().getIdentityProviderByAlias(alias).getConfig();
+ }
+
private RealmModel getRealmByName(String realmName) {
RealmProvider realmProvider = session.getProvider(RealmProvider.class);
return realmProvider.getRealmByName(realmName);
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
index 50352d4..e19653a 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
@@ -242,4 +242,14 @@ public interface TestingResource {
@Produces(MediaType.APPLICATION_JSON)
Map<String, TestProvider.DetailsRepresentation> getTestComponentDetails();
+ @GET
+ @Path("/smtp-config")
+ @Produces(MediaType.APPLICATION_JSON)
+ Map<String, String> getSmtpConfig();
+
+ @GET
+ @Path("/identity-config")
+ @Produces(MediaType.APPLICATION_JSON)
+ Map<String, String> getIdentityProviderConfig(@QueryParam("alias") String alias);
+
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
index dba19dd..409a3e1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
@@ -21,6 +21,7 @@ import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ComponentsResource;
import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.testsuite.components.TestProvider;
@@ -155,6 +156,11 @@ public class ComponentsTest extends AbstractAdminTest {
ComponentRepresentation returned = components.component(id).toRepresentation();
assertEquals(ComponentRepresentation.SECRET_VALUE, returned.getConfig().getFirst("secret"));
+ // Check secret not leaked in admin events
+ AdminEventRepresentation event = testingClient.testing().pollAdminEvent();
+ assertFalse(event.getRepresentation().contains("some secret value!!"));
+ assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE));
+
Map<String, TestProvider.DetailsRepresentation> details = testingClient.testing(REALM_NAME).getTestComponentDetails();
// Check value is set correctly
@@ -166,6 +172,11 @@ public class ComponentsTest extends AbstractAdminTest {
ComponentRepresentation returned2 = components.component(id).toRepresentation();
assertEquals(ComponentRepresentation.SECRET_VALUE, returned2.getConfig().getFirst("secret"));
+ // Check secret not leaked in admin events
+ event = testingClient.testing().pollAdminEvent();
+ assertFalse(event.getRepresentation().contains("some secret value!!"));
+ assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE));
+
// Check secret value is not set to '*********'
details = testingClient.testing(REALM_NAME).getTestComponentDetails();
assertEquals("some secret value!!", details.get("mycomponent").getConfig().get("secret").get(0));
@@ -176,6 +187,9 @@ public class ComponentsTest extends AbstractAdminTest {
// Check secret value is updated
details = testingClient.testing(REALM_NAME).getTestComponentDetails();
assertEquals("updated secret value!!", details.get("mycomponent").getConfig().get("secret").get(0));
+
+ ComponentRepresentation returned3 = components.query().stream().filter(c -> c.getId().equals(returned2.getId())).findFirst().get();
+ assertEquals(ComponentRepresentation.SECRET_VALUE, returned3.getConfig().getFirst("secret"));
}
private String createComponent(ComponentRepresentation rep) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
index c9c4191..e3392b3 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
@@ -27,6 +27,10 @@ import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.utils.StripSecretsUtils;
+import org.keycloak.representations.idm.AdminEventRepresentation;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
@@ -78,7 +82,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
IdentityProviderRepresentation newIdentityProvider = createRep("new-identity-provider", "oidc");
newIdentityProvider.getConfig().put("clientId", "clientId");
- newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
+ newIdentityProvider.getConfig().put("clientSecret", "some secret value");
create(newIdentityProvider);
@@ -94,10 +98,17 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertEquals("new-identity-provider", representation.getAlias());
assertEquals("oidc", representation.getProviderId());
assertEquals("clientId", representation.getConfig().get("clientId"));
- assertEquals("clientSecret", representation.getConfig().get("clientSecret"));
+ assertEquals(ComponentRepresentation.SECRET_VALUE, representation.getConfig().get("clientSecret"));
assertTrue(representation.isEnabled());
assertFalse(representation.isStoreToken());
assertFalse(representation.isTrustEmail());
+
+ testingClient.testing("admin-client-test").getSmtpConfig();
+
+ assertEquals("some secret value", testingClient.testing("admin-client-test").getIdentityProviderConfig("new-identity-provider").get("clientSecret"));
+
+ IdentityProviderRepresentation rep = realm.identityProviders().findAll().stream().filter(i -> i.getAlias().equals("new-identity-provider")).findFirst().get();
+ assertEquals(ComponentRepresentation.SECRET_VALUE, rep.getConfig().get("clientSecret"));
}
@Test
@@ -105,7 +116,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
IdentityProviderRepresentation newIdentityProvider = createRep("update-identity-provider", "oidc");
newIdentityProvider.getConfig().put("clientId", "clientId");
- newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
+ newIdentityProvider.getConfig().put("clientSecret", "some secret value");
create(newIdentityProvider);
@@ -125,7 +136,9 @@ public class IdentityProviderTest extends AbstractAdminTest {
representation.getConfig().put("clientId", "changedClientId");
identityProviderResource.update(representation);
- assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderPath("update-identity-provider"), representation, ResourceType.IDENTITY_PROVIDER);
+ AdminEventRepresentation event = assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderPath("update-identity-provider"), representation, ResourceType.IDENTITY_PROVIDER);
+ assertFalse(event.getRepresentation().contains("some secret value"));
+ assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE));
identityProviderResource = realm.identityProviders().get(representation.getInternalId());
@@ -136,6 +149,8 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertFalse(representation.isEnabled());
assertTrue(representation.isStoreToken());
assertEquals("changedClientId", representation.getConfig().get("clientId"));
+
+ assertEquals("some secret value", testingClient.testing("admin-client-test").getIdentityProviderConfig("changed-alias").get("clientSecret"));
}
@Test
@@ -168,7 +183,14 @@ public class IdentityProviderTest extends AbstractAdminTest {
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
+ String secret = idpRep.getConfig() != null ? idpRep.getConfig().get("clientSecret") : null;
+ idpRep = StripSecretsUtils.strip(idpRep);
+
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderPath(idpRep.getAlias()), idpRep, ResourceType.IDENTITY_PROVIDER);
+
+ if (secret != null) {
+ idpRep.getConfig().put("clientSecret", secret);
+ }
}
private IdentityProviderRepresentation createRep(String id, String providerId) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
index 7621f14..d793a8c 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
@@ -31,7 +31,10 @@ import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.Constants;
import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
+import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
@@ -45,6 +48,7 @@ import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.CredentialBuilder;
import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
+import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.util.JsonSerialization;
@@ -125,6 +129,34 @@ public class RealmTest extends AbstractAdminTest {
}
@Test
+ public void smtpPasswordSecret() {
+ RealmRepresentation rep = RealmBuilder.create().testEventListener().testMail().build();
+ rep.setRealm("realm-with-smtp");
+ rep.getSmtpServer().put("user", "user");
+ rep.getSmtpServer().put("password", "secret");
+
+ adminClient.realms().create(rep);
+
+ RealmRepresentation returned = adminClient.realm("realm-with-smtp").toRepresentation();
+ assertEquals(ComponentRepresentation.SECRET_VALUE, returned.getSmtpServer().get("password"));
+
+ assertEquals("secret", testingClient.testing("realm-with-smtp").getSmtpConfig().get("password"));
+
+ adminClient.realm("realm-with-smtp").update(rep);
+
+ AdminEventRepresentation event = testingClient.testing().pollAdminEvent();
+ assertFalse(event.getRepresentation().contains("some secret value!!"));
+ assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE));
+
+ assertEquals("secret", testingClient.testing("realm-with-smtp").getSmtpConfig().get("password"));
+
+ RealmRepresentation realm = adminClient.realms().findAll().stream().filter(r -> r.getRealm().equals("realm-with-smtp")).findFirst().get();
+ assertEquals(ComponentRepresentation.SECRET_VALUE, realm.getSmtpServer().get("password"));
+
+ adminClient.realm("realm-with-smtp").remove();
+ }
+
+ @Test
public void createRealmCheckDefaultPasswordPolicy() {
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm("new-realm");