diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminController.java
index 17c0b8b491aaa597a41ac1897b1da8b2684ca9ce..80f91d109a80057d91d06e070f17646e84884a24 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminController.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminController.java
@@ -121,6 +121,7 @@ public class TruststoreAdminController {
 
     public CertificateRO creatEmptyResponse(String alias, EntityROStatus status, String message) {
         CertificateRO certificateRO = new CertificateRO();
+        certificateRO.setError(true);
         certificateRO.setAlias(alias);
         certificateRO.setActionMessage(message);
         certificateRO.setStatus(status.getStatusNumber());
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java
index 23f8b113645ab57337e38fc5355bf9bb2254b5e1..04b9602d5623b3bbf456a8d7ee8a3318cae5901f 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java
@@ -148,6 +148,12 @@ public class MockMvcUtils {
         return mapper.readValue(result.getResponse().getContentAsByteArray(), clazz);
     }
 
+    public static <T> List<T> getArrayFromResponse(MvcResult result, Class<T> clazz)
+            throws IOException {
+        return mapper.readValue(result.getResponse().getContentAsByteArray(),
+                mapper.getTypeFactory().constructCollectionType(List.class, clazz));
+    }
+
     public static MockMvc initializeMockMvc(WebApplicationContext webAppContext) {
         MockMvc mvc = MockMvcBuilders.webAppContextSetup(webAppContext)
                 .apply(SecurityMockMvcConfigurers.springSecurity())
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2ecfdbf42e18b5f11f199bd2d30b4c8cb3ab608
--- /dev/null
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AbstractControllerTest.java
@@ -0,0 +1,47 @@
+package eu.europa.ec.edelivery.smp.ui;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import eu.europa.ec.edelivery.smp.data.dao.ConfigurationDao;
+import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig;
+import eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils;
+import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.io.IOException;
+
+
+@RunWith(SpringRunner.class)
+@DirtiesContext
+@WebAppConfiguration
+@ContextConfiguration(classes = {SmpTestWebAppConfig.class})
+@Sql(scripts = {
+        "classpath:/cleanup-database.sql",
+        "classpath:/webapp_integration_test_data.sql"})
+abstract public class AbstractControllerTest {
+    protected MockMvc mvc;
+    @Autowired
+    private WebApplicationContext webAppContext;
+    @Autowired
+    private ConfigurationDao configurationDao;
+
+    public void setup() throws IOException {
+        X509CertificateTestUtils.reloadKeystores();
+        mvc = MockMvcUtils.initializeMockMvc(webAppContext);
+        configurationDao.reloadPropertiesFromDatabase();
+    }
+
+    public ObjectMapper getObjectMapper() {
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.registerModule(new JavaTimeModule());
+        return mapper;
+    }
+}
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca2472210c2309f91db5b7ef6ef057956d828d5e
--- /dev/null
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserControllerTest.java
@@ -0,0 +1,105 @@
+package eu.europa.ec.edelivery.smp.ui.external;
+
+import eu.europa.ec.edelivery.smp.data.ui.NavigationTreeNodeRO;
+import eu.europa.ec.edelivery.smp.data.ui.SearchUserRO;
+import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.services.ui.UIUserService;
+import eu.europa.ec.edelivery.smp.ui.AbstractControllerTest;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.test.web.servlet.MvcResult;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils.*;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_USER;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+
+public class UserControllerTest extends AbstractControllerTest {
+    private static final String PATH = CONTEXT_PATH_PUBLIC_USER;
+
+    @Autowired
+    protected UIUserService uiUserService;
+
+    @Before
+    public void setup() throws IOException {
+        super.setup();
+    }
+
+
+    @Test
+    public void testGetUserNavigationTreeForSystemAdmin() throws Exception {
+
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult response = mvc.perform(get(PATH + "/{user-id}/navigation-tree", userRO.getUserId())
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        NavigationTreeNodeRO result = getObjectFromResponse(response, NavigationTreeNodeRO.class);
+
+        Assert.assertNotNull(result);
+        Assert.assertEquals(4, result.getChildren().size());
+        List<String> childrenNames = result.getChildren().stream().map(NavigationTreeNodeRO::getName).collect(Collectors.toList());
+        Assert.assertEquals(Arrays.asList("Search", "Administration", "System settings", "User Settings"), childrenNames);
+    }
+
+    @Test
+    public void testGetUserNavigationTreeForUser() throws Exception {
+
+        MockHttpSession session = loginWithUser2(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult response = mvc.perform(get(PATH + "/{user-id}/navigation-tree", userRO.getUserId())
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        NavigationTreeNodeRO result = getObjectFromResponse(response, NavigationTreeNodeRO.class);
+
+        Assert.assertNotNull(result);
+        Assert.assertEquals(3, result.getChildren().size());
+        List<String> childrenNames = result.getChildren().stream().map(NavigationTreeNodeRO::getName).collect(Collectors.toList());
+        Assert.assertEquals(Arrays.asList("Search", "Administration", "User Settings"), childrenNames);
+    }
+
+    @Test
+    public void testLookupUsers() throws Exception {
+        MockHttpSession session = loginWithUser2(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult response = mvc.perform(get(PATH + "/{user-id}/search", userRO.getUserId())
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        List<SearchUserRO> result = getArrayFromResponse(response, SearchUserRO.class);
+
+        Assert.assertNotNull(result);
+        Assert.assertTrue(result.size()>5);
+    }
+
+    @Test
+    public void testLookupUsersFilter() throws Exception {
+        MockHttpSession session = loginWithUser2(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult response = mvc.perform(get(PATH + "/{user-id}/search", userRO.getUserId()).param("filter", userRO.getUsername())
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        List<SearchUserRO> result = getArrayFromResponse(response, SearchUserRO.class);
+
+        Assert.assertNotNull(result);
+        Assert.assertEquals(1, result.size());
+        Assert.assertEquals(userRO.getUsername(), result.get(0).getUsername());
+    }
+}
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java
index 063478e93ab8469ec6865cafa87c71ed648cd2fa..7bf7eb852f422ad7c258e20d1cb73c046a0c42f8 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java
@@ -4,29 +4,16 @@ package eu.europa.ec.edelivery.smp.ui.internal;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import eu.europa.ec.edelivery.smp.data.dao.ConfigurationDao;
 import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
 import eu.europa.ec.edelivery.smp.data.ui.KeystoreImportResult;
-import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.services.ui.UIKeystoreService;
-import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig;
-import eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils;
-import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils;
+import eu.europa.ec.edelivery.smp.ui.AbstractControllerTest;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mock.web.MockHttpSession;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.context.web.WebAppConfiguration;
-import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
-import org.springframework.web.context.WebApplicationContext;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -39,35 +26,18 @@ import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_INTER
 import static org.junit.Assert.*;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 
-
-@RunWith(SpringRunner.class)
-@DirtiesContext
-@WebAppConfiguration
-@ContextConfiguration(classes = {SmpTestWebAppConfig.class})
-@Sql(scripts = {
-        "classpath:/cleanup-database.sql",
-        "classpath:/webapp_integration_test_data.sql"})
-public class KeystoreResourceIntegrationTest {
+public class KeystoreResourceIntegrationTest extends AbstractControllerTest {
     private static final String PATH = CONTEXT_PATH_INTERNAL_KEYSTORE;
     Path keystore = Paths.get("src", "test", "resources", "keystores", "smp-keystore.jks");
 
-    @Autowired
-    private WebApplicationContext webAppContext;
-
     @Autowired
     private UIKeystoreService uiKeystoreService;
-    @Autowired
-    private ConfigurationDao configurationDao;
-
-    private MockMvc mvc;
 
     @Before
     public void setup() throws IOException {
-        X509CertificateTestUtils.reloadKeystores();
-        mvc = MockMvcUtils.initializeMockMvc(webAppContext);
-        configurationDao.reloadPropertiesFromDatabase();
+        super.setup();
         uiKeystoreService.refreshData();
     }
 
@@ -177,10 +147,5 @@ public class KeystoreResourceIntegrationTest {
         assertEquals(countStart - 1, uiKeystoreService.getKeystoreEntriesList().size());
     }
 
-    protected ObjectMapper getObjectMapper() {
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.registerModule(new JavaTimeModule());
-        return mapper;
-    }
 
 }
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..29706842d6561b1be9e43cf3cc3836185667387a
--- /dev/null
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminControllerTest.java
@@ -0,0 +1,162 @@
+package eu.europa.ec.edelivery.smp.ui.internal;
+
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
+import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import eu.europa.ec.edelivery.smp.services.ui.UITruststoreService;
+import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils;
+import eu.europa.ec.edelivery.smp.ui.AbstractControllerTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.test.web.servlet.MvcResult;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.UUID;
+
+import static eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils.*;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_INTERNAL_TRUSTSTORE;
+import static org.junit.Assert.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+
+public class TruststoreAdminControllerTest extends AbstractControllerTest {
+    private static final String PATH = CONTEXT_PATH_INTERNAL_TRUSTSTORE;
+
+    @Autowired
+    private UITruststoreService uiTruststoreService;
+
+    @Before
+    public void setup() throws IOException {
+        super.setup();
+        uiTruststoreService.refreshData();
+    }
+
+    @Test
+    public void testGetSystemTruststoreCertificates() throws Exception {
+        // given when
+        int countStart = uiTruststoreService.getCertificateROEntriesList().size();
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult result = mvc.perform(get(PATH + "/" + userRO.getUserId())
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        //then
+        ObjectMapper mapper = getObjectMapper();
+        List<CertificateRO> listCerts = mapper.readValue(result.getResponse().getContentAsString(), new TypeReference<List<CertificateRO>>() {});
+
+        assertNotNull(listCerts);
+        assertEquals(countStart, listCerts.size());
+        listCerts.forEach(sgMap -> {
+            CertificateRO cert = mapper.convertValue(sgMap, CertificateRO.class);
+            assertNotNull(cert.getAlias());
+            assertNotNull(cert.getCertificateId());
+            assertNotNull(cert.getClientCertHeader());
+            assertNull(cert.getEncodedValue()); // submit only metadata
+        });
+    }
+
+    @Test
+    public void testUploadCertificateFailed() throws Exception {
+        // given when
+        // login
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        MvcResult result = mvc.perform(post(PATH + "/" + userRO.getUserId() + "/upload-certificate")
+                        .session(session)
+                        .with(csrf())
+                        .content("Not Certificate")).
+                andExpect(status().isOk()).andReturn();
+
+        //then
+        CertificateRO res = getObjectFromResponse(result, CertificateRO.class);
+
+        assertNotNull(res);
+        assertTrue(res.isError());
+
+        assertEquals("Error occurred while parsing certificate. Is certificate valid!", res.getActionMessage());
+    }
+
+    @Test
+    public void testUploadCertificateOK() throws Exception {
+
+        X509Certificate cert = X509CertificateTestUtils.createX509CertificateForTest("123456", "cn=test,o=test,c=eu");
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        int countStart = uiTruststoreService.getCertificateROEntriesList().size();
+        // given when
+        MvcResult result = mvc.perform(post(PATH + "/" + userRO.getUserId() + "/upload-certificate")
+                        .session(session)
+                        .with(csrf())
+                        .content(cert.getEncoded()))
+                .andExpect(status().isOk()).andReturn();
+
+        //then
+        CertificateRO res = getObjectFromResponse(result, CertificateRO.class);
+
+        assertNotNull(res);
+        assertEquals(countStart + 1, uiTruststoreService.getCertificateROEntriesList().size());
+    }
+
+    @Test
+    public void testDeleteCertificateFailed() throws Exception {
+
+
+        String alias = UUID.randomUUID().toString();
+
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        int countStart = uiTruststoreService.getCertificateROEntriesList().size();
+        // given when
+        MvcResult result = mvc.perform(delete(PATH + "/" + userRO.getUserId() + "/delete/" + alias)
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        //then
+        CertificateRO res = getObjectFromResponse(result, CertificateRO.class);
+
+        assertNotNull(res);
+        assertTrue(res.isError());
+
+        assertEquals("Certificate not removed because alias [" + alias + "] does not exist in truststore!", res.getActionMessage());
+        assertEquals(countStart, uiTruststoreService.getCertificateROEntriesList().size());
+    }
+
+
+    @Test
+    public void testDeleteCertificateOK() throws Exception {
+
+        X509Certificate cert = X509CertificateTestUtils.createX509CertificateForTest("123456", "cn=test,o=test,c=eu");
+        String alias = UUID.randomUUID().toString();
+        uiTruststoreService.addCertificate(alias, cert);
+
+
+        MockHttpSession session = loginWithSystemAdmin(mvc);
+        UserRO userRO = getLoggedUserData(mvc, session);
+        int countStart = uiTruststoreService.getCertificateROEntriesList().size();
+        // given when
+        MvcResult result = mvc.perform(delete(PATH + "/" + userRO.getUserId() + "/delete/" + alias)
+                        .session(session)
+                        .with(csrf()))
+                .andExpect(status().isOk()).andReturn();
+
+        //then
+        CertificateRO res = getObjectFromResponse(result, CertificateRO.class);
+
+        assertNotNull(res);
+        assertEquals(EntityROStatus.REMOVE.getStatusNumber(), res.getStatus());
+        assertEquals(countStart - 1, uiTruststoreService.getCertificateROEntriesList().size());
+    }
+}
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java
index 2c4158f8575146bb18ca23b656cb69ea6a28d467..9857fd9fb099209951257d73a799382209b1f770 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java
@@ -51,7 +51,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
         "classpath:/webapp_integration_test_data.sql"},
         executionPhase = BEFORE_TEST_METHOD)
 @Ignore
-public class TruststoreAdminResourceIntegrationTest {
+public class TruststoreAdminResourceIntegrationTest{
     private static final String PATH_INTERNAL = CONTEXT_PATH_INTERNAL_TRUSTSTORE;
     private static final String PATH_PUBLIC = CONTEXT_PATH_PUBLIC_TRUSTSTORE;