keycloak-aplcache

Details

diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index e2d97ec..99faf6b 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -1689,7 +1690,7 @@ public class RepresentationToModel {
         model.setName(rep.getName());
         model.setIdentityProviderAlias(rep.getIdentityProviderAlias());
         model.setIdentityProviderMapper(rep.getIdentityProviderMapper());
-        model.setConfig(rep.getConfig());
+        model.setConfig(removeEmptyString(rep.getConfig()));
         return model;
     }
 
@@ -2437,4 +2438,20 @@ public class RepresentationToModel {
 
         }
     }
+
+    private static Map<String, String> removeEmptyString(Map<String, String> map) {
+        if (map == null) {
+            return null;
+        }
+
+        Map<String, String> m = new HashMap<>(map);
+        for (Iterator<Map.Entry<String, String>> itr = m.entrySet().iterator(); itr.hasNext(); ) {
+            Map.Entry<String, String> e = itr.next();
+            if (e.getValue() == null || e.getValue().equals("")) {
+                itr.remove();
+            }
+        }
+        return m;
+    }
+
 }
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 d953847..fdf0c14 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
@@ -23,6 +23,7 @@ import org.keycloak.admin.client.resource.IdentityProviderResource;
 import org.keycloak.dom.saml.v2.metadata.EndpointType;
 import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
 import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
+import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
 import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
 import org.keycloak.events.admin.OperationType;
@@ -30,7 +31,6 @@ 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;
@@ -39,10 +39,12 @@ import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntityDescriptorParser;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.util.AdminEventPaths;
+import org.w3c.dom.NodeList;
 
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.xml.crypto.dsig.XMLSignature;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.URI;
@@ -57,16 +59,17 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import javax.xml.crypto.dsig.XMLSignature;
 
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.hamcrest.Matchers.*;
-import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
-import org.w3c.dom.NodeList;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -449,6 +452,40 @@ public class IdentityProviderTest extends AbstractAdminTest {
         }
     }
 
+    // KEYCLOAK-4962
+    @Test
+    public void testUpdateProtocolMappers() {
+        create(createRep("google", "google"));
+
+        IdentityProviderResource provider = realm.identityProviders().get("google");
+
+        IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation();
+        mapper.setIdentityProviderAlias("google");
+        mapper.setName("my_mapper");
+        mapper.setIdentityProviderMapper("oidc-hardcoded-role-idp-mapper");
+        Map<String, String> config = new HashMap<>();
+        config.put("role", "");
+        mapper.setConfig(config);
+
+        Response response = provider.addMapper(mapper);
+        String mapperId = ApiUtil.getCreatedId(response);
+
+
+        List<IdentityProviderMapperRepresentation> mappers = provider.getMappers();
+        assertEquals(1, mappers.size());
+        assertEquals(0, mappers.get(0).getConfig().size());
+
+        mapper = provider.getMapperById(mapperId);
+        mapper.getConfig().put("role", "offline_access");
+
+        provider.update(mapperId, mapper);
+
+        mappers = provider.getMappers();
+        assertEquals(1, mappers.size());
+        assertEquals(1, mappers.get(0).getConfig().size());
+        assertEquals("offline_access", mappers.get(0).getConfig().get("role"));
+    }
+
     @Test
     public void testInstalledIdentityProviders() {
         Response response = realm.identityProviders().getIdentityProviders("oidc");