Refactored StripSecretsUtils in order to make it unit-testable, added unit tests for it
Don't mask secrets at realm export Closes #21562 Signed-off-by: Joerg Matysiak <joerg.matysiak@bosch.com>
This commit is contained in:
parent
7483bae130
commit
76a5a27082
13 changed files with 359 additions and 147 deletions
|
@ -62,7 +62,6 @@ import java.util.stream.Collectors;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
|
||||
import static org.keycloak.models.utils.StripSecretsUtils.stripSecrets;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -256,7 +255,7 @@ public class ExportUtils {
|
|||
// Message Bundle
|
||||
rep.setLocalizationTexts(realm.getRealmLocalizationTexts());
|
||||
|
||||
return stripSecrets(session, rep);
|
||||
return rep;
|
||||
}
|
||||
|
||||
public static MultivaluedHashMap<String, ComponentExportRepresentation> exportComponents(RealmModel realm, String parentId) {
|
||||
|
|
|
@ -123,6 +123,7 @@ import static org.keycloak.models.utils.RepresentationToModel.createGroups;
|
|||
import static org.keycloak.models.utils.RepresentationToModel.createRoleMappings;
|
||||
import static org.keycloak.models.utils.RepresentationToModel.importGroup;
|
||||
import static org.keycloak.models.utils.RepresentationToModel.importRoles;
|
||||
import static org.keycloak.models.utils.StripSecretsUtils.stripSecrets;
|
||||
|
||||
/**
|
||||
* This wraps the functionality about export/import for the storage.
|
||||
|
@ -142,6 +143,7 @@ public class DefaultExportImportManager implements ExportImportManager {
|
|||
callback.setType(MediaType.APPLICATION_JSON);
|
||||
callback.writeToOutputStream(outputStream -> {
|
||||
RealmRepresentation rep = ExportUtils.exportRealm(session, realm, options, false);
|
||||
stripSecrets(session, rep);
|
||||
JsonSerialization.writeValueToStream(outputStream, rep);
|
||||
outputStream.close();
|
||||
});
|
||||
|
|
|
@ -498,7 +498,7 @@ public class ModelToRepresentation {
|
|||
}
|
||||
|
||||
List<IdentityProviderRepresentation> identityProviders = realm.getIdentityProvidersStream()
|
||||
.map(provider -> toRepresentation(session, realm, provider)).collect(Collectors.toList());
|
||||
.map(provider -> toRepresentation(realm, provider)).collect(Collectors.toList());
|
||||
rep.setIdentityProviders(identityProviders);
|
||||
|
||||
List<IdentityProviderMapperRepresentation> identityProviderMappers = realm.getIdentityProviderMappersStream()
|
||||
|
@ -784,7 +784,7 @@ public class ModelToRepresentation {
|
|||
return providerRep;
|
||||
}
|
||||
|
||||
public static IdentityProviderRepresentation toRepresentation(KeycloakSession session, RealmModel realm, IdentityProviderModel identityProviderModel) {
|
||||
public static IdentityProviderRepresentation toRepresentation(RealmModel realm, IdentityProviderModel identityProviderModel) {
|
||||
IdentityProviderRepresentation providerRep = toBriefRepresentation(realm, identityProviderModel);
|
||||
|
||||
providerRep.setLinkOnly(identityProviderModel.isLinkOnly());
|
||||
|
@ -818,7 +818,7 @@ public class ModelToRepresentation {
|
|||
providerRep.setPostBrokerLoginFlowAlias(flow.getAlias());
|
||||
}
|
||||
|
||||
return stripSecrets(session, providerRep);
|
||||
return providerRep;
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation toRepresentation(ProtocolMapperModel model) {
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -46,6 +47,12 @@ public class StripSecretsUtils {
|
|||
|
||||
private static final Map<Class<?>, BiConsumer<KeycloakSession, Object>> REPRESENTATION_FORMATTER = new HashMap<>();
|
||||
|
||||
/** interface to encapsulate the getComponentProperties() function in order to make the code unit-testable
|
||||
*/
|
||||
protected interface GetComponentPropertiesFn {
|
||||
Map<String, ProviderConfigProperty> getComponentProperties(KeycloakSession session, String providerType, String providerId);
|
||||
}
|
||||
|
||||
static {
|
||||
REPRESENTATION_FORMATTER.put(RealmRepresentation.class, (session, o) -> StripSecretsUtils.stripRealm(session, (RealmRepresentation) o));
|
||||
REPRESENTATION_FORMATTER.put(UserRepresentation.class, (session, o) -> StripSecretsUtils.stripUser((UserRepresentation) o));
|
||||
|
@ -77,11 +84,18 @@ public class StripSecretsUtils {
|
|||
|
||||
private static ComponentRepresentation stripComponent(KeycloakSession session, ComponentRepresentation rep) {
|
||||
Map<String, ProviderConfigProperty> configProperties = ComponentUtil.getComponentConfigProperties(session, rep);
|
||||
if (rep.getConfig() == null) {
|
||||
return rep;
|
||||
return stripComponent(configProperties, rep);
|
||||
}
|
||||
|
||||
Iterator<Map.Entry<String, List<String>>> itr = rep.getConfig().entrySet().iterator();
|
||||
protected static ComponentRepresentation stripComponent( Map<String, ProviderConfigProperty> configProperties, ComponentRepresentation rep) {
|
||||
if (rep.getConfig() != null) {
|
||||
stripComponentConfigMap(rep.getConfig(), configProperties);
|
||||
}
|
||||
return rep;
|
||||
|
||||
}
|
||||
private static void stripComponentConfigMap(MultivaluedHashMap<String, String> configMap, Map<String, ProviderConfigProperty> configProperties) {
|
||||
Iterator<Map.Entry<String, List<String>>> itr = configMap.entrySet().iterator();
|
||||
while (itr.hasNext()) {
|
||||
Map.Entry<String, List<String>> next = itr.next();
|
||||
ProviderConfigProperty configProperty = configProperties.get(next.getKey());
|
||||
|
@ -97,110 +111,76 @@ public class StripSecretsUtils {
|
|||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> stripFromMap(Map<String, String> map, String key) {
|
||||
if ((map != null) && map.containsKey(key)) {
|
||||
map.put(key, maskNonVaultValue(map.get(key)));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
protected static IdentityProviderRepresentation stripBroker(IdentityProviderRepresentation rep) {
|
||||
stripFromMap(rep.getConfig(), "clientSecret");
|
||||
return rep;
|
||||
}
|
||||
|
||||
private static RealmRepresentation stripRealm(RealmRepresentation rep) {
|
||||
if (rep.getSmtpServer() != null && rep.getSmtpServer().containsKey("password")) {
|
||||
rep.getSmtpServer().put("password", maskNonVaultValue(rep.getSmtpServer().get("password")));
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
private static IdentityProviderRepresentation stripBroker(IdentityProviderRepresentation rep) {
|
||||
if (rep.getConfig() != null && rep.getConfig().containsKey("clientSecret")) {
|
||||
rep.getConfig().put("clientSecret", maskNonVaultValue(rep.getConfig().get("clientSecret")));
|
||||
}
|
||||
stripFromMap(rep.getSmtpServer(), "password");
|
||||
return rep;
|
||||
}
|
||||
|
||||
private static void stripRealm(KeycloakSession session, RealmRepresentation rep) {
|
||||
stripRealm(session, rep, ComponentUtil::getComponentConfigProperties);
|
||||
}
|
||||
protected static void stripRealm(KeycloakSession session, RealmRepresentation rep, GetComponentPropertiesFn fnGetConfigProperties) {
|
||||
stripRealm(rep);
|
||||
|
||||
List<ClientRepresentation> clients = rep.getClients();
|
||||
if (clients != null) {
|
||||
for (ClientRepresentation c : clients) {
|
||||
stripClient(c);
|
||||
}
|
||||
}
|
||||
List<IdentityProviderRepresentation> providers = rep.getIdentityProviders();
|
||||
if (providers != null) {
|
||||
for (IdentityProviderRepresentation r : providers) {
|
||||
stripBroker(r);
|
||||
}
|
||||
Optional.ofNullable(rep.getClients())
|
||||
.ifPresent(clients -> clients.forEach(StripSecretsUtils::stripClient));
|
||||
|
||||
Optional.ofNullable(rep.getIdentityProviders())
|
||||
.ifPresent(providers -> providers.forEach(StripSecretsUtils::stripBroker));
|
||||
|
||||
Optional.ofNullable(rep.getComponents())
|
||||
.ifPresent(components -> components
|
||||
.forEach((providerType, componentList)-> componentList
|
||||
.forEach(component -> stripComponentExport(session, providerType, component, fnGetConfigProperties))));
|
||||
|
||||
Optional.ofNullable(rep.getUsers())
|
||||
.ifPresent(users -> users.forEach(StripSecretsUtils::stripUser));
|
||||
|
||||
Optional.ofNullable(rep.getFederatedUsers())
|
||||
.ifPresent(users -> users.forEach(StripSecretsUtils::stripUser));
|
||||
}
|
||||
|
||||
MultivaluedHashMap<String, ComponentExportRepresentation> components = rep.getComponents();
|
||||
if (components != null) {
|
||||
for (Map.Entry<String, List<ComponentExportRepresentation>> ent : components.entrySet()) {
|
||||
for (ComponentExportRepresentation c : ent.getValue()) {
|
||||
stripComponentExport(session, ent.getKey(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<UserRepresentation> users = rep.getUsers();
|
||||
if (users != null) {
|
||||
for (UserRepresentation u: users) {
|
||||
stripUser(u);
|
||||
}
|
||||
}
|
||||
|
||||
users = rep.getFederatedUsers();
|
||||
if (users != null) {
|
||||
for (UserRepresentation u: users) {
|
||||
stripUser(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UserRepresentation stripUser(UserRepresentation user) {
|
||||
protected static UserRepresentation stripUser(UserRepresentation user) {
|
||||
user.setCredentials(null);
|
||||
return user;
|
||||
}
|
||||
|
||||
private static ClientRepresentation stripClient(ClientRepresentation rep) {
|
||||
protected static ClientRepresentation stripClient(ClientRepresentation rep) {
|
||||
if (rep.getSecret() != null) {
|
||||
rep.setSecret(maskNonVaultValue(rep.getSecret()));
|
||||
}
|
||||
if (rep.getAttributes() != null && rep.getAttributes().containsKey(ClientSecretConstants.CLIENT_ROTATED_SECRET)) {
|
||||
rep.getAttributes().put(
|
||||
ClientSecretConstants.CLIENT_ROTATED_SECRET,
|
||||
maskNonVaultValue(rep.getAttributes().get(ClientSecretConstants.CLIENT_ROTATED_SECRET))
|
||||
);
|
||||
}
|
||||
|
||||
stripFromMap(rep.getAttributes(), ClientSecretConstants.CLIENT_ROTATED_SECRET);
|
||||
return rep;
|
||||
}
|
||||
|
||||
private static ComponentExportRepresentation stripComponentExport(KeycloakSession session, String providerType, ComponentExportRepresentation rep) {
|
||||
Map<String, ProviderConfigProperty> configProperties = ComponentUtil.getComponentConfigProperties(session, providerType, rep.getProviderId());
|
||||
if (rep.getConfig() == null) {
|
||||
return rep;
|
||||
return stripComponentExport(session, providerType, rep, ComponentUtil::getComponentConfigProperties);
|
||||
}
|
||||
private static ComponentExportRepresentation stripComponentExport(KeycloakSession session, String providerType, ComponentExportRepresentation rep, GetComponentPropertiesFn fnGetConfigProperties) {
|
||||
Map<String, ProviderConfigProperty> configProperties = fnGetConfigProperties.getComponentProperties(session, providerType, rep.getProviderId());
|
||||
|
||||
if (rep.getConfig() != null) {
|
||||
stripComponentConfigMap(rep.getConfig(), configProperties);
|
||||
}
|
||||
|
||||
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()) {
|
||||
if (next.getValue() == null || next.getValue().isEmpty()) {
|
||||
next.setValue(Collections.singletonList(ComponentRepresentation.SECRET_VALUE));
|
||||
} else {
|
||||
next.setValue(next.getValue().stream().map(StripSecretsUtils::maskNonVaultValue).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
MultivaluedHashMap<String, ComponentExportRepresentation> sub = rep.getSubComponents();
|
||||
for (Map.Entry<String, List<ComponentExportRepresentation>> ent: sub.entrySet()) {
|
||||
for (ComponentExportRepresentation c: ent.getValue()) {
|
||||
stripComponentExport(session, ent.getKey(), c);
|
||||
}
|
||||
}
|
||||
rep.getSubComponents()
|
||||
.forEach((subCompProviderType, subCompProviders) ->
|
||||
subCompProviders.forEach(subComp -> stripComponentExport(session, subCompProviderType, subComp)));
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.utils.StripSecretsUtils;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class StripSecretsUtilsTest {
|
||||
|
||||
@Test
|
||||
public void checkStrippedRotatedSecret() {
|
||||
ClientRepresentation stripped = StripSecretsUtils.stripSecrets(null, createClient("unmasked_secret"));
|
||||
assertEquals(ComponentRepresentation.SECRET_VALUE, getRotatedSecret(stripped));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStrippedRotatedSecretVaultUnaffected() {
|
||||
String rotatedSecret = "${vault.key}";
|
||||
ClientRepresentation stripped = StripSecretsUtils.stripSecrets(null, createClient(rotatedSecret));
|
||||
assertEquals(rotatedSecret, getRotatedSecret(stripped));
|
||||
}
|
||||
|
||||
private ClientRepresentation createClient(String rotatedSecret) {
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
Map<String, String> attrs = new HashMap<>();
|
||||
attrs.put(ClientSecretConstants.CLIENT_ROTATED_SECRET, rotatedSecret);
|
||||
client.setAttributes(attrs);
|
||||
return client;
|
||||
}
|
||||
|
||||
private String getRotatedSecret(ClientRepresentation clientRepresentation) {
|
||||
return clientRepresentation.getAttributes().get(ClientSecretConstants.CLIENT_ROTATED_SECRET);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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.junit.Test;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.ClientSecretConstants;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.representations.idm.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class StripSecretsUtilsTest {
|
||||
|
||||
@Test
|
||||
public void checkStrippedRotatedSecret() {
|
||||
ClientRepresentation stripped = StripSecretsUtils.stripSecrets(null, createClient("unmasked_secret"));
|
||||
assertEquals(ComponentRepresentation.SECRET_VALUE, getRotatedSecret(stripped));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStrippedRotatedSecretVaultUnaffected() {
|
||||
String rotatedSecret = "${vault.key}";
|
||||
ClientRepresentation stripped = StripSecretsUtils.stripSecrets(null, createClient(rotatedSecret));
|
||||
assertEquals(rotatedSecret, getRotatedSecret(stripped));
|
||||
}
|
||||
|
||||
private ClientRepresentation createClient(String rotatedSecret) {
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
Map<String, String> attrs = new HashMap<>();
|
||||
attrs.put(ClientSecretConstants.CLIENT_ROTATED_SECRET, rotatedSecret);
|
||||
client.setAttributes(attrs);
|
||||
return client;
|
||||
}
|
||||
|
||||
private String getRotatedSecret(ClientRepresentation clientRepresentation) {
|
||||
return clientRepresentation.getAttributes().get(ClientSecretConstants.CLIENT_ROTATED_SECRET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripUser() {
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
rep.setId("userId");
|
||||
CredentialRepresentation credentialRepresentation = new CredentialRepresentation();
|
||||
credentialRepresentation.setType("password");
|
||||
credentialRepresentation.setSecretData("myPassword");
|
||||
rep.setCredentials(Arrays.asList(credentialRepresentation));
|
||||
rep.setEnabled(true);
|
||||
|
||||
StripSecretsUtils.stripUser(rep);
|
||||
|
||||
assertEquals("userId", rep.getId());
|
||||
assertNull(rep.getCredentials());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripClient() {
|
||||
ClientRepresentation rep = new ClientRepresentation();
|
||||
rep.setId("clientId");
|
||||
rep.setSecret("clientSecret");
|
||||
rep.setAttributes(new HashMap<>());
|
||||
rep.getAttributes().put("clientAttr1", "clientAttr1Value");
|
||||
rep.getAttributes().put("client.secret.rotated", "rotatedSecret");
|
||||
|
||||
StripSecretsUtils.stripClient(rep);
|
||||
assertEquals("clientId", rep.getId());
|
||||
assertEquals("**********", rep.getSecret());
|
||||
assertEquals(2, rep.getAttributes().size());
|
||||
assertEquals("clientAttr1Value", rep.getAttributes().get("clientAttr1"));
|
||||
assertEquals("**********", rep.getAttributes().get("client.secret.rotated"));
|
||||
}
|
||||
@Test
|
||||
public void stripClientSecretsFromVault() {
|
||||
ClientRepresentation rep = new ClientRepresentation();
|
||||
rep.setId("clientId");
|
||||
rep.setSecret("${vault.clientSecret}");
|
||||
rep.setAttributes(new HashMap<>());
|
||||
rep.getAttributes().put("clientAttr1", "clientAttr1Value");
|
||||
rep.getAttributes().put("client.secret.rotated", "${vault.rotatedSecret}");
|
||||
|
||||
StripSecretsUtils.stripClient(rep);
|
||||
assertEquals("clientId", rep.getId());
|
||||
assertEquals("${vault.clientSecret}", rep.getSecret());
|
||||
assertEquals(2, rep.getAttributes().size());
|
||||
assertEquals("clientAttr1Value", rep.getAttributes().get("clientAttr1"));
|
||||
assertEquals("${vault.rotatedSecret}", rep.getAttributes().get("client.secret.rotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripBroker() {
|
||||
IdentityProviderRepresentation rep = new IdentityProviderRepresentation();
|
||||
rep.setInternalId("brokerId");
|
||||
rep.setConfig(new HashMap<>());
|
||||
rep.getConfig().put("clientSecret", "secret");
|
||||
rep.getConfig().put("configParam1", "configValue1");
|
||||
|
||||
StripSecretsUtils.stripBroker(rep);
|
||||
assertEquals("brokerId", rep.getInternalId());
|
||||
assertEquals(2, rep.getConfig().size());
|
||||
assertEquals("**********", rep.getConfig().get("clientSecret"));
|
||||
assertEquals("configValue1", rep.getConfig().get("configParam1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripComponent() {
|
||||
ComponentRepresentation rep = new ComponentRepresentation();
|
||||
rep.setId("componentId");
|
||||
rep.setName("componentName");
|
||||
rep.setProviderId("componentProviderId");
|
||||
rep.setProviderType("componentProviderType");
|
||||
rep.setParentId("componentParentId");
|
||||
rep.setSubType("componentSubType");
|
||||
|
||||
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
|
||||
config.put("secret", Arrays.asList("secretValue1", "secretValue2"));
|
||||
config.put("secretWithoutValues", Arrays.asList());
|
||||
config.put("nonSecret", Arrays.asList("nonSecretValue1", "nonSecretValue2"));
|
||||
rep.setConfig(config);
|
||||
|
||||
Map<String, ProviderConfigProperty> configProperties = new HashMap<>();
|
||||
configProperties.put("secret", new ProviderConfigProperty("secret", "secretLabel", "secretHelpText", "secretType", "defaultValue", true));
|
||||
configProperties.put("secretWithoutValues", new ProviderConfigProperty("secretWithoutValues", "secretLabel", "secretHelpText", "secretType", "defaultValue", true));
|
||||
configProperties.put("nonSecret", new ProviderConfigProperty("nonSecret", "nonSecretLabel", "nonSecretHelpText", "secretType", "defaultValue", false));
|
||||
|
||||
StripSecretsUtils.stripComponent(configProperties, rep);
|
||||
|
||||
assertEquals("componentId", rep.getId());
|
||||
assertEquals("componentName", rep.getName());
|
||||
assertEquals(2, rep.getConfig().get("secret").size());
|
||||
assertEquals("**********", rep.getConfig().get("secret").get(0));
|
||||
assertEquals("**********", rep.getConfig().get("secret").get(1));
|
||||
assertEquals(1, rep.getConfig().get("secretWithoutValues").size());
|
||||
assertEquals("**********", rep.getConfig().get("secretWithoutValues").get(0));
|
||||
assertEquals(2, rep.getConfig().get("nonSecret").size());
|
||||
assertEquals("nonSecretValue1", rep.getConfig().get("nonSecret").get(0));
|
||||
assertEquals("nonSecretValue2", rep.getConfig().get("nonSecret").get(1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripRealm() throws IOException {
|
||||
RealmRepresentation rep = new RealmRepresentation();
|
||||
rep.setRealm("Master");
|
||||
rep.setId("realmId");
|
||||
|
||||
rep.setSmtpServer(new HashMap<>());
|
||||
rep.getSmtpServer().put("password", "secret");
|
||||
rep.getSmtpServer().put("user", "smtpUser");
|
||||
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
client.setId("clientId");
|
||||
client.setSecret("clientSecret");
|
||||
client.setAttributes(new HashMap<>());
|
||||
client.getAttributes().put("clientAttr1", "clientAttr1Value");
|
||||
client.getAttributes().put("client.secret.rotated", "rotatedSecret");
|
||||
rep.setClients(Arrays.asList(client));
|
||||
|
||||
IdentityProviderRepresentation idp = new IdentityProviderRepresentation();
|
||||
idp.setProviderId("idpProviderId");
|
||||
idp.setAlias("idpAlias");
|
||||
idp.setConfig(new HashMap<>());
|
||||
idp.getConfig().put("idpConfig1", "idpConfig1Value");
|
||||
idp.getConfig().put("clientSecret", "ipdClientSecret");
|
||||
rep.setIdentityProviders(Arrays.asList(idp));
|
||||
|
||||
UserRepresentation user = new UserRepresentation();
|
||||
user.setId("userId");
|
||||
user.setEnabled(true);
|
||||
CredentialRepresentation userCreds = new CredentialRepresentation();
|
||||
userCreds.setType(CredentialRepresentation.PASSWORD);
|
||||
userCreds.setValue("userPassword");
|
||||
user.setCredentials(Arrays.asList(userCreds));
|
||||
rep.setUsers(Arrays.asList(user));
|
||||
|
||||
UserRepresentation fedUser = new UserRepresentation();
|
||||
fedUser.setId("fedUserId");
|
||||
fedUser.setEnabled(true);
|
||||
CredentialRepresentation fedUserCreds = new CredentialRepresentation();
|
||||
fedUserCreds.setType(CredentialRepresentation.PASSWORD);
|
||||
fedUserCreds.setValue("fedUserPassword");
|
||||
fedUser.setCredentials(Arrays.asList(fedUserCreds));
|
||||
rep.setFederatedUsers(Arrays.asList(fedUser));
|
||||
|
||||
ComponentExportRepresentation component = new ComponentExportRepresentation();
|
||||
component.setId("componentId");
|
||||
component.setProviderId("componentProviderId");
|
||||
component.setConfig(new MultivaluedHashMap<>());
|
||||
component.getConfig().put("secret", Arrays.asList("secret1", "secret2"));
|
||||
component.getConfig().put("secretWithoutValues", Collections.emptyList());
|
||||
component.getConfig().put("nonSecret", Arrays.asList("nonSecret1", "nonSecret2"));
|
||||
|
||||
rep.setComponents(new MultivaluedHashMap<>());
|
||||
rep.getComponents().put("componentExport", Arrays.asList(component));
|
||||
|
||||
Map<String, ProviderConfigProperty> componentConfigProperties = new HashMap<>();
|
||||
componentConfigProperties.put("secret", new ProviderConfigProperty("secret", "secretLabel", "secretHelpText", "secretType", "defaultValue", true));
|
||||
componentConfigProperties.put("secretWithoutValues", new ProviderConfigProperty("secretWithoutValues", "secretLabel", "secretHelpText", "secretType", "defaultValue", true));
|
||||
componentConfigProperties.put("nonSecret", new ProviderConfigProperty("nonSecret", "nonSecretLabel", "nonSecretHelpText", "secretType", "defaultValue", false));
|
||||
StripSecretsUtils.GetComponentPropertiesFn fnGetComponentConfigProperties = (session, providerType, providerId) -> componentConfigProperties;
|
||||
|
||||
StripSecretsUtils.stripRealm(null, rep, fnGetComponentConfigProperties);
|
||||
|
||||
assertEquals("Master", rep.getRealm());
|
||||
assertEquals("realmId", rep.getId());
|
||||
assertEquals(2, rep.getSmtpServer().size());
|
||||
assertEquals("**********", rep.getSmtpServer().get("password"));
|
||||
assertEquals("smtpUser", rep.getSmtpServer().get("user"));
|
||||
|
||||
assertEquals(1, rep.getClients().size());
|
||||
assertEquals("clientId", rep.getClients().get(0).getId());
|
||||
assertEquals("**********", rep.getClients().get(0).getSecret());
|
||||
assertEquals(2, rep.getClients().get(0).getAttributes().size());
|
||||
assertEquals("clientAttr1Value", rep.getClients().get(0).getAttributes().get("clientAttr1"));
|
||||
assertEquals("**********", rep.getClients().get(0).getAttributes().get("client.secret.rotated"));
|
||||
|
||||
assertEquals(1, rep.getIdentityProviders().size());
|
||||
assertEquals(2, rep.getIdentityProviders().get(0).getConfig().size());
|
||||
assertEquals("idpConfig1Value", rep.getIdentityProviders().get(0).getConfig().get("idpConfig1"));
|
||||
assertEquals("**********", rep.getIdentityProviders().get(0).getConfig().get("clientSecret"));
|
||||
|
||||
|
||||
assertEquals(1, rep.getUsers().size());
|
||||
assertEquals("userId", rep.getUsers().get(0).getId());
|
||||
assertNull(rep.getUsers().get(0).getCredentials());
|
||||
|
||||
assertEquals(1, rep.getFederatedUsers().size());
|
||||
assertEquals("fedUserId", rep.getFederatedUsers().get(0).getId());
|
||||
assertNull(rep.getFederatedUsers().get(0).getCredentials());
|
||||
|
||||
assertEquals(1, rep.getComponents().size());
|
||||
assertEquals(1, rep.getComponents().get("componentExport").size());
|
||||
MultivaluedHashMap<String, String> componentExportConfig = rep.getComponents().get("componentExport").get(0).getConfig();
|
||||
assertNotNull(componentExportConfig);
|
||||
assertEquals(2, componentExportConfig.get("secret").size());
|
||||
assertEquals("**********", componentExportConfig.get("secret").get(0));
|
||||
assertEquals("**********", componentExportConfig.get("secret").get(1));
|
||||
assertEquals(1, componentExportConfig.get("secretWithoutValues").size());
|
||||
assertEquals("**********", componentExportConfig.get("secretWithoutValues").get(0));
|
||||
assertEquals(2, componentExportConfig.get("nonSecret").size());
|
||||
assertEquals("nonSecret1", componentExportConfig.get("nonSecret").get(0));
|
||||
assertEquals("nonSecret2", componentExportConfig.get("nonSecret").get(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ public class IdentityProviderResource {
|
|||
throw new jakarta.ws.rs.NotFoundException();
|
||||
}
|
||||
|
||||
return ModelToRepresentation.toRepresentation(session, realm, this.identityProviderModel);
|
||||
return StripSecretsUtils.stripSecrets(session, ModelToRepresentation.toRepresentation(realm, this.identityProviderModel));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -191,7 +191,7 @@ public class IdentityProvidersResource {
|
|||
|
||||
Function<IdentityProviderModel, IdentityProviderRepresentation> toRepresentation = briefRepresentation != null && briefRepresentation
|
||||
? m -> ModelToRepresentation.toBriefRepresentation(realm, m)
|
||||
: m -> ModelToRepresentation.toRepresentation(session, realm, m);
|
||||
: m -> StripSecretsUtils.stripSecrets(session, ModelToRepresentation.toRepresentation(realm, m));
|
||||
|
||||
Stream<IdentityProviderModel> stream = realm.getIdentityProvidersStream().sorted(new IdPComparator());
|
||||
if (!StringUtil.isBlank(search)) {
|
||||
|
@ -240,7 +240,7 @@ public class IdentityProvidersResource {
|
|||
|
||||
representation.setInternalId(identityProvider.getInternalId());
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), identityProvider.getAlias())
|
||||
.representation(representation).success();
|
||||
.representation(StripSecretsUtils.stripSecrets(session, representation)).success();
|
||||
|
||||
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(representation.getAlias()).build()).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
|
|
@ -482,6 +482,8 @@ public class ClientTest extends AbstractAdminTest {
|
|||
|
||||
realm.clients().get(client.getId()).update(newClient);
|
||||
|
||||
newClient.setSecret("**********"); // secrets are masked in events
|
||||
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient, ResourceType.CLIENT);
|
||||
|
||||
storedClient = realm.clients().get(client.getId()).toRepresentation();
|
||||
|
@ -540,6 +542,7 @@ public class ClientTest extends AbstractAdminTest {
|
|||
getCleanup().addClientUuid(id);
|
||||
response.close();
|
||||
|
||||
client.setSecret("**********"); // secrets are masked in events
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), client, ResourceType.CLIENT);
|
||||
|
||||
client.setId(id);
|
||||
|
|
|
@ -258,7 +258,7 @@ public class UserTest extends AbstractAdminTest {
|
|||
private void updateUser(UserResource user, UserRepresentation userRep) {
|
||||
user.update(userRep);
|
||||
List<CredentialRepresentation> credentials = userRep.getCredentials();
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(userRep.getId()), StripSecretsUtils.strip(userRep), ResourceType.USER);
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(userRep.getId()), StripSecretsUtils.stripSecrets(null, userRep), ResourceType.USER);
|
||||
userRep.setCredentials(credentials);
|
||||
}
|
||||
|
||||
|
|
|
@ -1055,6 +1055,8 @@ public class RealmTest extends AbstractAdminTest {
|
|||
String clientDbId = ApiUtil.getCreatedId(resp);
|
||||
getCleanup().addClientUuid(clientDbId);
|
||||
resp.close();
|
||||
|
||||
client.setSecret("**********"); // secrets are masked in events
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client, ResourceType.CLIENT);
|
||||
|
||||
oauth.realm(REALM_NAME);
|
||||
|
@ -1086,6 +1088,8 @@ public class RealmTest extends AbstractAdminTest {
|
|||
String clientDbId = ApiUtil.getCreatedId(resp);
|
||||
getCleanup().addClientUuid(clientDbId);
|
||||
resp.close();
|
||||
|
||||
client.setSecret("**********"); // secrets are masked in events
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client, ResourceType.CLIENT);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,11 @@ import org.keycloak.exportimport.Strategy;
|
|||
import org.keycloak.exportimport.dir.DirExportProvider;
|
||||
import org.keycloak.exportimport.dir.DirExportProviderFactory;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||
import org.keycloak.exportimport.util.ImportUtils;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.KeysMetadataRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -50,6 +52,7 @@ import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
|||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
@ -66,6 +69,7 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
|
||||
|
@ -208,6 +212,17 @@ public class ExportImportTest extends AbstractKeycloakTest {
|
|||
testingClient.testing().exportImport().setFile(targetFilePath);
|
||||
|
||||
testFullExportImport();
|
||||
assertExportContainsGoogleClientSecret(targetFilePath);
|
||||
}
|
||||
|
||||
private static void assertExportContainsGoogleClientSecret(String targetFilePath) throws IOException {
|
||||
assertTrue("Expected an export file to exist", new File(targetFilePath).exists());
|
||||
|
||||
Map<String, RealmRepresentation> realms = ImportUtils.getRealmsFromStream(JsonSerialization.mapper, new FileInputStream(new File(targetFilePath)));
|
||||
List<IdentityProviderRepresentation> idps = realms.get("test-realm").getIdentityProviders();
|
||||
IdentityProviderRepresentation googleIdp = idps.stream().filter(idp -> idp.getAlias().equals("google1")).findFirst().get();
|
||||
assertNotNull(googleIdp);
|
||||
assertEquals("googleSecret", googleIdp.getConfig().get("clientSecret"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -293,7 +293,7 @@ public class ExportImportUtil {
|
|||
Assert.assertEquals("google", google.getProviderId());
|
||||
Assert.assertTrue(google.isEnabled());
|
||||
Assert.assertEquals("googleId", google.getConfig().get("clientId"));
|
||||
Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
|
||||
Assert.assertEquals("**********", google.getConfig().get("clientSecret")); // secret is masked in GET call
|
||||
|
||||
//////////////////
|
||||
// Test federation providers
|
||||
|
|
Loading…
Reference in a new issue