keycloak-memoizeit

Merge pull request #2963 from ssilvert/migrate-importexport KEYCLOAK-3031

6/24/2016 5:44:46 AM

Changes

testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java 402(+0 -402)

Details

diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 547b583..8beaffb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -90,6 +90,12 @@ public class ImportTest extends AbstractModelTest {
     }
 
     // Moved to static method, so it's possible to test this from other places too (for example export-import tests)
+    /*
+    BIG HELPFUL HINT!!!!
+    WHEN YOU MIGRATE THIS CLASS YOU DO NOT NEED TO MIGRATE THIS METHOD.
+    IT HAS ALREADY BEEN IMPLEMENTED IN THE NEW ARQUILLIAN TESTSUTE.
+    SEE org.keycloak.testsuite.exportimport.ExportImportUtil
+    */
     public static void assertDataImportedInRealm(KeycloakSession session, RealmModel realm) {
         Assert.assertTrue(realm.isVerifyEmail());
         Assert.assertEquals(3600000, realm.getOfflineSessionIdleTimeout());
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 ca5156b..e484645 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
@@ -61,7 +61,19 @@ import org.keycloak.events.EventType;
 import org.keycloak.events.admin.AdminEventQuery;
 import org.keycloak.events.admin.AuthDetails;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.exportimport.ExportImportManager;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderFactory;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserProvider;
 import org.keycloak.representations.idm.AuthDetailsRepresentation;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -544,4 +556,93 @@ public class TestingResourceProvider implements RealmResourceProvider {
         result.setUsername(PassThroughAuthenticator.username);
         return result;
     }
+
+    @GET
+    @Path("/run-import")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runImport() {
+        new ExportImportManager(session).runImport();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/run-export")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runExport() {
+        new ExportImportManager(session).runExport();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/valid-credentials")
+    @Produces(MediaType.APPLICATION_JSON)
+    public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password) {
+        RealmModel realm = session.realms().getRealm(realmName);
+        if (realm == null) return false;
+        UserProvider userProvider = session.getProvider(UserProvider.class);
+        UserModel user = userProvider.getUserByUsername(userName, realm);
+        return userProvider.validCredentials(session, realm, user, UserCredentialModel.password(password));
+    }
+
+    @GET
+    @Path("/user-by-federated-identity")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName,
+                                                         @QueryParam("identityProvider") String identityProvider,
+                                                         @QueryParam("userId") String userId,
+                                                         @QueryParam("userName") String userName) {
+        RealmModel realm = getRealmByName(realmName);
+        UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(new FederatedIdentityModel(identityProvider, userId, userName), realm);
+        if (foundFederatedUser == null) return null;
+        return ModelToRepresentation.toRepresentation(foundFederatedUser);
+    }
+
+    @GET
+    @Path("/user-by-username-from-fed-factory")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
+                                                                      @QueryParam("userName") String userName) {
+        RealmModel realm = getRealmByName(realmName);
+        UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
+        UserModel user = factory.getInstance(session, null).getUserByUsername(realm, userName);
+        if (user == null) return null;
+        return ModelToRepresentation.toRepresentation(user);
+    }
+
+    @GET
+    @Path("/get-client-auth-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName) {
+        RealmModel realm = getRealmByName(realmName);
+        AuthenticationFlowModel flow = realm.getClientAuthenticationFlow();
+        if (flow == null) return null;
+        return ModelToRepresentation.toRepresentation(realm, flow);
+    }
+
+    @GET
+    @Path("/get-reset-cred-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName) {
+        RealmModel realm = getRealmByName(realmName);
+        AuthenticationFlowModel flow = realm.getResetCredentialsFlow();
+        if (flow == null) return null;
+        return ModelToRepresentation.toRepresentation(realm, flow);
+    }
+
+    @GET
+    @Path("/get-user-by-service-account-client")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId) {
+        RealmModel realm = getRealmByName(realmName);
+        ClientModel client =  realm.getClientByClientId(clientId);
+        UserModel user = session.users().getUserByServiceAccountClient(client);
+        if (user == null) return null;
+        return ModelToRepresentation.toRepresentation(user);
+    }
+
+    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 23d2d01..8bd36f3 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
@@ -20,7 +20,9 @@ package org.keycloak.testsuite.client.resources;
 import java.util.Date;
 import java.util.List;
 import org.keycloak.representations.idm.AdminEventRepresentation;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.rest.representation.AuthenticatorState;
 
 import javax.ws.rs.Consumes;
@@ -35,6 +37,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.Map;
 import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.exportimport.ExportImportManager;
 
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@@ -202,4 +205,48 @@ public interface TestingResource {
     @Path("/update-pass-through-auth-state")
     @Produces(MediaType.APPLICATION_JSON)
     AuthenticatorState updateAuthenticator(AuthenticatorState state);
+
+    @GET
+    @Path("/run-import")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runImport();
+
+    @GET
+    @Path("/run-export")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runExport();
+    
+    @GET
+    @Path("/valid-credentials")
+    @Produces(MediaType.APPLICATION_JSON)
+    public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password);
+
+    @GET
+    @Path("/user-by-federated-identity")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName,
+                                                         @QueryParam("identityProvider") String identityProvider,
+                                                         @QueryParam("userId") String userId,
+                                                         @QueryParam("userName") String userName);
+
+    @GET
+    @Path("/user-by-username-from-fed-factory")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
+                                                                      @QueryParam("userName") String userName);
+
+    @GET
+    @Path("/get-client-auth-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName);
+
+    @GET
+    @Path("/get-reset-cred-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName);
+
+    @GET
+    @Path("/get-user-by-service-account-client")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId);
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
index 670e340..a1a1813 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
@@ -53,6 +53,7 @@ import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 import twitter4j.JSONArray;
 import twitter4j.JSONObject;
@@ -68,7 +69,7 @@ public class ProfileTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         user.setFirstName("First");
         user.setLastName("Last");
         Map<String, Object> attributes = user.getAttributes();
@@ -87,7 +88,7 @@ public class ProfileTest extends TestRealmKeycloakTest {
         RealmBuilder.edit(testRealm)
                     .user(user2);
 
-        ClientBuilder.edit(findClientInRealmRep(testRealm, "test-app"))
+        ClientBuilder.edit(RealmRepUtil.findClientByClientId(testRealm, "test-app"))
                      .addWebOrigin("http://localtest.me:8180");
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java
index 499e387..75ba24e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java
@@ -59,7 +59,7 @@ public class TrustStoreEmailTest extends TestRealmKeycloakTest {
     public void configureTestRealm(RealmRepresentation testRealm) {
         log.info("enable verify email and configure smtp server to run with ssl in test realm");
 
-        user = findUserInRealmRep(testRealm, "test-user@localhost");
+        user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         testRealm.setSmtpServer(SslMailServer.getServerConfiguration());
         testRealm.setVerifyEmail(true);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
index dca666f..d7946ce 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -60,6 +60,15 @@ public class ApiUtil {
         return path.substring(path.lastIndexOf('/') + 1);
     }
 
+    public static ClientResource findClientResourceById(RealmResource realm, String id) {
+        for (ClientRepresentation c : realm.clients().findAll()) {
+            if (c.getId().equals(id)) {
+                return realm.clients().get(c.getId());
+            }
+        }
+        return null;
+    }
+
     public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) {
         for (ClientRepresentation c : realm.clients().findAll()) {
             if (c.getClientId().equals(clientId)) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
new file mode 100755
index 0000000..3a6a1bb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.testsuite.exportimport;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.dir.DirExportProvider;
+import org.keycloak.exportimport.dir.DirExportProviderFactory;
+import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+import java.util.regex.Matcher;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.junit.After;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.util.UserBuilder;
+
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ *
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ExportImportTest extends AbstractExportImportTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation testRealm1 = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealm1.getUsers().add(makeUser("user1"));
+        testRealm1.getUsers().add(makeUser("user2"));
+        testRealm1.getUsers().add(makeUser("user3"));
+        testRealms.add(testRealm1);
+
+        RealmRepresentation testRealm2 = loadJson(getClass().getResourceAsStream("/model/testrealm.json"), RealmRepresentation.class);
+        testRealm2.setId("test-realm");
+        testRealms.add(testRealm2);
+    }
+
+    private UserRepresentation makeUser(String userName) {
+        return UserBuilder.create()
+                .username(userName)
+                .email(userName + "@test.com")
+                .password("password")
+                .build();
+    }
+
+    @After
+    public void clearExportImportProps() throws LifecycleException {
+        clearExportImportProperties();
+    }
+
+    @Test
+    public void testDirFullExportImport() throws Throwable {
+        ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
+        String targetDirPath = getExportImportTestDirectory() + File.separator + "dirExport";
+        DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+        ExportImportConfig.setDir(targetDirPath);
+        ExportImportConfig.setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
+
+        testFullExportImport();
+
+        // There should be 6 files in target directory (3 realm, 3 user)
+        Assert.assertEquals(6, new File(targetDirPath).listFiles().length);
+    }
+
+    @Test
+    public void testDirRealmExportImport() throws Throwable {
+        ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
+        String targetDirPath = getExportImportTestDirectory() + File.separator + "dirRealmExport";
+        DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+        ExportImportConfig.setDir(targetDirPath);
+        ExportImportConfig.setUsersPerFile(3);
+
+        testRealmExportImport();
+
+        // There should be 3 files in target directory (1 realm, 3 user)
+        File[] files = new File(targetDirPath).listFiles();
+        Assert.assertEquals(4, files.length);
+    }
+
+    @Test
+    public void testSingleFileFullExportImport() throws Throwable {
+        ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-full.json";
+        ExportImportConfig.setFile(targetFilePath);
+
+        testFullExportImport();
+    }
+
+    @Test
+    public void testSingleFileRealmExportImport() throws Throwable {
+        ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
+        ExportImportConfig.setFile(targetFilePath);
+
+        testRealmExportImport();
+    }
+
+    @Test
+    public void testSingleFileRealmWithoutBuiltinsImport() throws Throwable {
+        // Remove test realm
+        removeRealm("test-realm");
+
+        // Set the realm, which doesn't have builtin clients/roles inside JSON
+        ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        URL url = ExportImportTest.class.getResource("/model/testrealm.json");
+        String targetFilePath = new File(url.getFile()).getAbsolutePath();
+        ExportImportConfig.setFile(targetFilePath);
+
+        ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        RealmResource testRealmRealm = adminClient.realm("test-realm");
+
+        ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation());
+    }
+
+
+    private void removeRealm(String realmName) {
+        adminClient.realm(realmName).remove();
+    }
+
+    private void testFullExportImport() throws LifecycleException {
+        ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
+        ExportImportConfig.setRealmName(null);
+
+        testingClient.testing().runExport();
+
+        removeRealm("test");
+        removeRealm("test-realm");
+        Assert.assertEquals(1, adminClient.realms().findAll().size());
+
+        assertNotAuthenticated("test", "test-user@localhost", "password");
+        assertNotAuthenticated("test", "user1", "password");
+        assertNotAuthenticated("test", "user2", "password");
+        assertNotAuthenticated("test", "user3", "password");
+
+        // Configure import
+        ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        // Ensure data are imported back
+        Assert.assertEquals(3, adminClient.realms().findAll().size());
+
+        assertAuthenticated("test", "test-user@localhost", "password");
+        assertAuthenticated("test", "user1", "password");
+        assertAuthenticated("test", "user2", "password");
+        assertAuthenticated("test", "user3", "password");
+    }
+
+    private void testRealmExportImport() throws LifecycleException {
+        ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
+        ExportImportConfig.setRealmName("test");
+
+        testingClient.testing().runExport();
+
+        // Delete some realm (and some data in admin realm)
+        adminClient.realm("test").remove();
+
+        Assert.assertEquals(2, adminClient.realms().findAll().size());
+
+        assertNotAuthenticated("test", "test-user@localhost", "password");
+        assertNotAuthenticated("test", "user1", "password");
+        assertNotAuthenticated("test", "user2", "password");
+        assertNotAuthenticated("test", "user3", "password");
+
+        // Configure import
+        ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        // Ensure data are imported back, but just for "test" realm
+        Assert.assertEquals(3, adminClient.realms().findAll().size());
+
+        assertAuthenticated("test", "test-user@localhost", "password");
+        assertAuthenticated("test", "user1", "password");
+        assertAuthenticated("test", "user2", "password");
+        assertAuthenticated("test", "user3", "password");
+    }
+
+    private void assertAuthenticated(String realmName, String username, String password) {
+        assertAuth(true, realmName, username, password);
+    }
+
+    private void assertNotAuthenticated(String realmName, String username, String password) {
+        assertAuth(false, realmName, username, password);
+    }
+
+    private void assertAuth(boolean expectedResult, String realmName, String username, String password) {
+        Assert.assertEquals(expectedResult, testingClient.testing().validCredentials(realmName, username, password));
+    }
+
+    private static String getExportImportTestDirectory() {
+        String dirPath = null;
+        String relativeDirExportImportPath = "testsuite" + File.separator +
+                                             "integration-arquillian" + File.separator +
+                                             "tests" + File.separator +
+                                             "base" + File.separator +
+                                             "target" + File.separator +
+                                             "export-import";
+
+        if (System.getProperties().containsKey("maven.home")) {
+            dirPath = System.getProperty("user.dir").replaceFirst("testsuite.integration.*", Matcher.quoteReplacement(relativeDirExportImportPath));
+        } else {
+            for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) {
+                if (c.contains(File.separator + "testsuite" + File.separator + "integration-arquillian" + File.separator)) {
+                    dirPath = c.replaceFirst("testsuite.integration-arquillian.*", Matcher.quoteReplacement(relativeDirExportImportPath));
+                }
+            }
+        }
+
+        String absolutePath = new File(dirPath).getAbsolutePath();
+        return absolutePath;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
new file mode 100644
index 0000000..95b327f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.testsuite.exportimport;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Assert;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientTemplateResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.common.constants.KerberosConstants;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
+import org.keycloak.models.Constants;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.representations.idm.ClientMappingsRepresentation;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserFederationMapperRepresentation;
+import org.keycloak.representations.idm.UserFederationProviderRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.client.KeycloakTestingClient;
+import org.keycloak.testsuite.util.RealmRepUtil;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ExportImportUtil {
+
+    // In the old testsuite, this method exists as a public method of ImportTest from the model package.
+    // However, model package is not ready to be migrated yet.
+    public static void assertDataImportedInRealm(Keycloak adminClient, KeycloakTestingClient testingClient, RealmRepresentation realm) {
+        Assert.assertTrue(realm.isVerifyEmail());
+        Assert.assertEquals((Integer)3600000, realm.getOfflineSessionIdleTimeout());
+        Assert.assertEquals((Integer)1500, realm.getAccessTokenLifespanForImplicitFlow());
+
+        Set<String> creds = realm.getRequiredCredentials();
+        Assert.assertEquals(1, creds.size());
+        String cred = (String)creds.iterator().next();
+        Assert.assertEquals("password", cred);
+        Assert.assertEquals(4, realm.getDefaultRoles().size());
+
+        Assert.assertNotNull(RealmRepUtil.findDefaultRole(realm, "foo"));
+        Assert.assertNotNull(RealmRepUtil.findDefaultRole(realm, "bar"));
+
+        RealmResource realmRsc = adminClient.realm(realm.getRealm());
+
+        /* See KEYCLOAK-3104*/
+        UserRepresentation user = findByUsername(realmRsc, "loginclient");
+        Assert.assertNotNull(user);
+
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        Assert.assertEquals(0, userRsc.getFederatedIdentity().size());
+
+        List<ClientRepresentation> resources = realmRsc.clients().findAll();
+        Assert.assertEquals(8, resources.size());
+
+        // Test applications imported
+        ClientRepresentation application = ApiUtil.findClientByClientId(realmRsc, "Application").toRepresentation();
+        ClientRepresentation otherApp = ApiUtil.findClientByClientId(realmRsc, "OtherApp").toRepresentation();
+        ClientRepresentation accountApp = ApiUtil.findClientByClientId(realmRsc, Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).toRepresentation();
+        ClientResource nonExisting = ApiUtil.findClientByClientId(realmRsc, "NonExisting");
+        Assert.assertNotNull(application);
+        Assert.assertNotNull(otherApp);
+        Assert.assertNull(nonExisting);
+        List<ClientRepresentation> clients = realmRsc.clients().findAll();
+        Assert.assertEquals(8, clients.size());
+        Assert.assertTrue(hasClient(clients, application));
+        Assert.assertTrue(hasClient(clients, otherApp));
+        Assert.assertTrue(hasClient(clients, accountApp));
+
+        Assert.assertEquals("Applicationn", application.getName());
+        Assert.assertEquals((Integer)50, application.getNodeReRegistrationTimeout());
+        Map<String, Integer> appRegisteredNodes = application.getRegisteredNodes();
+        Assert.assertEquals(2, appRegisteredNodes.size());
+        Assert.assertTrue(10 == appRegisteredNodes.get("node1"));
+        Assert.assertTrue(20 == appRegisteredNodes.get("172.10.15.20"));
+
+        // test clientAuthenticatorType
+        Assert.assertEquals("client-secret", application.getClientAuthenticatorType());
+        Assert.assertEquals("client-jwt", otherApp.getClientAuthenticatorType());
+
+        // Test finding applications by ID
+        Assert.assertNull(ApiUtil.findClientResourceById(realmRsc, "982734"));
+        Assert.assertEquals(application.getId(), ApiUtil.findClientResourceById(realmRsc, application.getId()).toRepresentation().getId());
+
+
+        // Test role mappings
+        UserRepresentation admin = findByUsername(realmRsc, "admin");
+        // user without creation timestamp in import
+        Assert.assertNull(admin.getCreatedTimestamp());
+        Set<RoleRepresentation> allRoles = allRoles(realmRsc, admin);
+        Assert.assertEquals(3, allRoles.size());
+        Assert.assertTrue(containsRole(allRoles, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, application.getId(), "app-admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, otherApp.getId(), "otherapp-admin")));
+
+        Assert.assertTrue(findClientRole(realmRsc, application.getId(), "app-admin").isScopeParamRequired());
+        Assert.assertFalse(findClientRole(realmRsc, otherApp.getId(), "otherapp-admin").isScopeParamRequired());
+        Assert.assertFalse(findClientRole(realmRsc, otherApp.getId(), "otherapp-user").isScopeParamRequired());
+
+        UserRepresentation wburke = findByUsername(realmRsc, "wburke");
+        // user with creation timestamp in import
+        Assert.assertEquals(new Long(123654), wburke.getCreatedTimestamp());
+        allRoles = allRoles(realmRsc, wburke);
+        Assert.assertEquals(2, allRoles.size());
+        Assert.assertFalse(containsRole(allRoles, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, application.getId(), "app-user")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, otherApp.getId(), "otherapp-user")));
+
+        Assert.assertNull(realmRsc.users().get(wburke.getId()).roles().getAll().getRealmMappings());
+
+        UserRepresentation loginclient = findByUsername(realmRsc, "loginclient");
+        // user with creation timestamp as string in import
+        Assert.assertEquals(new Long(123655), loginclient.getCreatedTimestamp());
+
+        List<RoleRepresentation> realmRoles = realmRolesForUser(realmRsc, admin);
+        Assert.assertEquals(1, realmRoles.size());
+        Assert.assertEquals("admin", realmRoles.iterator().next().getName());
+
+        List<RoleRepresentation> appRoles = clientRolesForUser(realmRsc, application, admin);
+        Assert.assertEquals(1, appRoles.size());
+        Assert.assertEquals("app-admin", appRoles.iterator().next().getName());
+
+        // Test attributes
+        Map<String, List<String>> attrs = wburke.getAttributesAsListValues();
+        Assert.assertEquals(1, attrs.size());
+        List<String> attrVals = attrs.get("email");
+        Assert.assertEquals(1, attrVals.size());
+        Assert.assertEquals("bburke@redhat.com", attrVals.get(0));
+
+        attrs = admin.getAttributesAsListValues();
+        Assert.assertEquals(2, attrs.size());
+        attrVals = attrs.get("key1");
+        Assert.assertEquals(1, attrVals.size());
+        Assert.assertEquals("val1", attrVals.get(0));
+        attrVals = attrs.get("key2");
+        Assert.assertEquals(2, attrVals.size());
+        Assert.assertTrue(attrVals.contains("val21") && attrVals.contains("val22"));
+
+        // Test client
+        ClientResource oauthClient = ApiUtil.findClientResourceByClientId(realmRsc, "oauthclient");
+        ClientRepresentation oauthClientRep = oauthClient.toRepresentation();
+        Assert.assertEquals("clientpassword", oauthClient.getSecret().getValue());
+        Assert.assertTrue(oauthClientRep.isEnabled());
+        Assert.assertNotNull(oauthClientRep);
+
+        // Test scope relationship
+        Set<RoleRepresentation> allScopes = allScopeMappings(oauthClient);
+        Assert.assertEquals(2, allScopes.size());
+        Assert.assertTrue(containsRole(allScopes, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allScopes, findClientRole(realmRsc, application.getId(), "app-user")));
+
+        List<RoleRepresentation> realmScopes = realmScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(realmScopes, findRealmRole(realmRsc, "admin")));
+
+        List<RoleRepresentation> appScopes = clientScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(appScopes, findClientRole(realmRsc, application.getId(), "app-user")));
+
+        // Test social linking
+        UserResource socialUser = realmRsc.users().get(findByUsername(realmRsc, "mySocialUser").getId());
+        List<FederatedIdentityRepresentation> socialLinks = socialUser.getFederatedIdentity();
+        Assert.assertEquals(3, socialLinks.size());
+        boolean facebookFound = false;
+        boolean googleFound = false;
+        boolean twitterFound = false;
+        FederatedIdentityRepresentation facebookIdentityRep = null;
+        for (FederatedIdentityRepresentation federatedIdentityRep : socialLinks) {
+            if ("facebook1".equals(federatedIdentityRep.getIdentityProvider())) {
+                facebookFound = true;
+                facebookIdentityRep = federatedIdentityRep;
+                Assert.assertEquals("facebook1",federatedIdentityRep.getUserId());
+                Assert.assertEquals("fbuser1", federatedIdentityRep.getUserName());
+            } else if ("google1".equals(federatedIdentityRep.getIdentityProvider())) {
+                googleFound = true;
+                Assert.assertEquals("google1", federatedIdentityRep.getUserId());
+                Assert.assertEquals("mysocialuser@gmail.com", federatedIdentityRep.getUserName());
+            } else if ("twitter1".equals(federatedIdentityRep.getIdentityProvider())) {
+                twitterFound = true;
+                Assert.assertEquals("twitter1", federatedIdentityRep.getUserId());
+                Assert.assertEquals("twuser1", federatedIdentityRep.getUserName());
+            }
+        }
+        Assert.assertTrue(facebookFound && twitterFound && googleFound);
+
+        UserRepresentation foundSocialUser =  testingClient.testing().getUserByFederatedIdentity(realm.getRealm(), "facebook1", "facebook1", "fbuser1");
+        Assert.assertEquals(foundSocialUser.getUsername(), socialUser.toRepresentation().getUsername());
+        Assert.assertNull(testingClient.testing().getUserByFederatedIdentity(realm.getRealm(), "facebook", "not-existing", "not-existing"));
+
+        Assert.assertEquals("facebook1", facebookIdentityRep.getUserId());
+        Assert.assertEquals("fbuser1", facebookIdentityRep.getUserName());
+        Assert.assertEquals("facebook1", facebookIdentityRep.getIdentityProvider());
+
+        // Test remove/add social link
+        socialUser.removeFederatedIdentity("facebook1");
+        Assert.assertEquals(2, socialUser.getFederatedIdentity().size());
+        socialUser.addFederatedIdentity("facebook1", facebookIdentityRep);
+        Assert.assertEquals(3, socialUser.getFederatedIdentity().size());
+
+        // Test smtp config
+        Map<String, String> smtpConfig = realm.getSmtpServer();
+        Assert.assertTrue(smtpConfig.size() == 3);
+        Assert.assertEquals("auto@keycloak.org", smtpConfig.get("from"));
+        Assert.assertEquals("localhost", smtpConfig.get("host"));
+        Assert.assertEquals("3025", smtpConfig.get("port"));
+
+        // Test identity providers
+        List<IdentityProviderRepresentation> identityProviders = realm.getIdentityProviders();
+        Assert.assertEquals(3, identityProviders.size());
+        IdentityProviderRepresentation google = null;
+        for (IdentityProviderRepresentation idpRep : identityProviders) {
+            if (idpRep.getAlias().equals("google1")) google = idpRep;
+        }
+        Assert.assertNotNull(google);
+        Assert.assertEquals("google1", google.getAlias());
+        Assert.assertEquals("google", google.getProviderId());
+        Assert.assertTrue(google.isEnabled());
+        Assert.assertEquals("googleId", google.getConfig().get("clientId"));
+        Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
+
+        // Test federation providers
+        List<UserFederationProviderRepresentation> fedProviders = realm.getUserFederationProviders();
+        Assert.assertTrue(fedProviders.size() == 2);
+        UserFederationProviderRepresentation ldap1 = fedProviders.get(0);
+        Assert.assertEquals("MyLDAPProvider1", ldap1.getDisplayName());
+        Assert.assertEquals("ldap", ldap1.getProviderName());
+        Assert.assertEquals(1, ldap1.getPriority());
+        Assert.assertEquals("ldap://foo", ldap1.getConfig().get(LDAPConstants.CONNECTION_URL));
+
+        UserFederationProviderRepresentation ldap2 = fedProviders.get(1);
+        Assert.assertEquals("MyLDAPProvider2", ldap2.getDisplayName());
+        Assert.assertEquals("ldap://bar", ldap2.getConfig().get(LDAPConstants.CONNECTION_URL));
+
+        // Test federation mappers
+        List<UserFederationMapperRepresentation> fedMappers1 = realmRsc.userFederation().get(ldap1.getId()).getMappers();
+        Assert.assertTrue(fedMappers1.size() == 1);
+        UserFederationMapperRepresentation fullNameMapper = fedMappers1.iterator().next();
+        Assert.assertEquals("FullNameMapper", fullNameMapper.getName());
+        Assert.assertEquals(FullNameLDAPFederationMapperFactory.PROVIDER_ID, fullNameMapper.getFederationMapperType());
+        //Assert.assertEquals(ldap1.getId(), fullNameMapper.getFederationProviderId());
+        Assert.assertEquals("cn", fullNameMapper.getConfig().get(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE));
+
+        // All builtin LDAP mappers should be here
+        List<UserFederationMapperRepresentation> fedMappers2 = realmRsc.userFederation().get(ldap2.getId()).getMappers();
+        Assert.assertTrue(fedMappers2.size() > 3);
+        List<UserFederationMapperRepresentation> allMappers = realm.getUserFederationMappers();
+        Assert.assertEquals(allMappers.size(), fedMappers1.size() + fedMappers2.size());
+
+        // Assert that federation link wasn't created during import
+        Assert.assertNull(testingClient.testing().getUserByUsernameFromFedProviderFactory(realm.getRealm(), "wburke"));
+
+        // Test builtin authentication flows
+        AuthenticationFlowRepresentation clientFlow = testingClient.testing().getClientAuthFlow(realm.getRealm());
+        Assert.assertEquals(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW, clientFlow.getAlias());
+        Assert.assertNotNull(realmRsc.flows().getFlow(clientFlow.getId()));
+        Assert.assertTrue(realmRsc.flows().getExecutions(clientFlow.getAlias()).size() > 0);
+
+        AuthenticationFlowRepresentation resetFlow = testingClient.testing().getResetCredFlow(realm.getRealm());
+        Assert.assertEquals(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW, resetFlow.getAlias());
+        Assert.assertNotNull(realmRsc.flows().getFlow(resetFlow.getId()));
+        Assert.assertTrue(realmRsc.flows().getExecutions(resetFlow.getAlias()).size() > 0);
+
+        // Test protocol mappers. Default application has all the builtin protocol mappers. OtherApp just gss credential
+        List<ProtocolMapperRepresentation> applicationMappers = application.getProtocolMappers();
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));//application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "email"));
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "given name"));
+        Assert.assertNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME));
+
+        Assert.assertEquals(1, otherApp.getProtocolMappers().size());
+        List<ProtocolMapperRepresentation> otherAppMappers = otherApp.getProtocolMappers();
+        Assert.assertNull(findMapperByName(otherAppMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+        ProtocolMapperRepresentation gssCredentialMapper = findMapperByName(otherAppMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
+        assertGssProtocolMapper(gssCredentialMapper);
+
+        // Test clientTemplates
+        List<ClientTemplateRepresentation> clientTemplates = realmRsc.clientTemplates().findAll();
+        Assert.assertEquals(1, clientTemplates.size());
+        ClientTemplateRepresentation clientTemplate = clientTemplates.get(0);
+        Assert.assertEquals("foo-template", clientTemplate.getName());
+        Assert.assertEquals("foo-template-desc", clientTemplate.getDescription());
+        Assert.assertEquals(OIDCLoginProtocol.LOGIN_PROTOCOL, clientTemplate.getProtocol());
+        Assert.assertEquals(1, clientTemplate.getProtocolMappers().size());
+        List<ProtocolMapperRepresentation> clientTemplateMappers = clientTemplate.getProtocolMappers();
+        ProtocolMapperRepresentation templateGssCredentialMapper = findMapperByName(clientTemplateMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
+        assertGssProtocolMapper(templateGssCredentialMapper);
+
+        // Test client template scopes
+        Set<RoleRepresentation> allClientTemplateScopes = allScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));
+        Assert.assertEquals(3, allClientTemplateScopes.size());
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findRealmRole(realmRsc, "admin")));//allClientTemplateScopes.contains(realm.getRole("admin")));
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findClientRole(realmRsc, application.getId(), "app-user")));//allClientTemplateScopes.contains(application.getRole("app-user")));
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findClientRole(realmRsc, application.getId(), "app-admin")));//allClientTemplateScopes.contains(application.getRole("app-admin")));
+
+        List<RoleRepresentation> clientTemplateRealmScopes = realmScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));
+        Assert.assertTrue(containsRole(clientTemplateRealmScopes, findRealmRole(realmRsc, "admin")));//clientTemplateRealmScopes.contains(realm.getRole("admin")));
+
+        List<RoleRepresentation> clientTemplateAppScopes = clientScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));//application.getClientScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(clientTemplateAppScopes, findClientRole(realmRsc, application.getId(), "app-user")));//clientTemplateAppScopes.contains(application.getRole("app-user")));
+        Assert.assertTrue(containsRole(clientTemplateAppScopes, findClientRole(realmRsc, application.getId(), "app-admin")));//clientTemplateAppScopes.contains(application.getRole("app-admin")));
+
+        // Test user consents
+        //admin =  session.users().getUserByUsername("admin", realm);
+
+        UserResource adminRsc = realmRsc.users().get(admin.getId());
+        List<Map<String, Object>> consents = adminRsc.getConsents();
+        Assert.assertEquals(2, consents.size());//.getConsents().size());
+
+        Map<String, Object> appAdminConsent = findConsentByClientId(consents, application.getClientId());
+        Assert.assertEquals(2, calcNumberGrantedRoles(appAdminConsent));
+        Assert.assertTrue(getGrantedProtocolMappers(appAdminConsent) == null || getGrantedProtocolMappers(appAdminConsent).isEmpty());
+        Assert.assertTrue(isRealmRoleGranted(appAdminConsent, "admin"));//appAdminConsent.isRoleGranted(realm.getRole("admin")));
+        Assert.assertTrue(isClientRoleGranted(appAdminConsent, application.getClientId(), "app-admin"));//appAdminConsent.isRoleGranted(application.getRole("app-admin")));
+
+        Map<String, Object> otherAppAdminConsent = findConsentByClientId(consents, otherApp.getClientId());//admin.getConsentByClient(otherApp.getId());
+        Assert.assertEquals(1, calcNumberGrantedRoles(otherAppAdminConsent));
+        Assert.assertEquals(1, getGrantedProtocolMappers(otherAppAdminConsent).size());//otherAppAdminConsent.getGrantedProtocolMappers().size());
+        Assert.assertTrue(isRealmRoleGranted(otherAppAdminConsent, "admin"));//otherAppAdminConsent.isRoleGranted(realm.getRole("admin")));
+        Assert.assertFalse(isClientRoleGranted(otherAppAdminConsent, application.getClientId(), "app-admin"));//otherAppAdminConsent.isRoleGranted(application.getRole("app-admin")));
+        Assert.assertTrue(isProtocolMapperGranted(otherAppAdminConsent, gssCredentialMapper));
+
+        Assert.assertTrue(application.isStandardFlowEnabled());
+        Assert.assertTrue(application.isImplicitFlowEnabled());
+        Assert.assertTrue(application.isDirectAccessGrantsEnabled());
+        Assert.assertFalse(otherApp.isStandardFlowEnabled());
+        Assert.assertFalse(otherApp.isImplicitFlowEnabled());
+        Assert.assertFalse(otherApp.isDirectAccessGrantsEnabled());
+
+        // Test service accounts
+        Assert.assertFalse(application.isServiceAccountsEnabled());
+        Assert.assertTrue(otherApp.isServiceAccountsEnabled());
+        Assert.assertNull(testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), application.getClientId()));//session.users().getUserByServiceAccountClient(application));
+        UserRepresentation linked = testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), otherApp.getClientId());//session.users().getUserByServiceAccountClient(otherApp);
+        Assert.assertNotNull(linked);
+        Assert.assertEquals("my-service-user", linked.getUsername());
+    }
+
+    private static boolean isProtocolMapperGranted(Map<String, Object> consent, ProtocolMapperRepresentation mapperRep) {
+        Map<String, List> grantedMappers = (Map<String, List>)consent.get("grantedProtocolMappers");
+        if (grantedMappers == null) return false;
+        List<String> mappers = grantedMappers.get(mapperRep.getProtocol());
+        if (mappers == null) return false;
+        return mappers.contains(mapperRep.getName());
+    }
+
+    private static boolean isRealmRoleGranted(Map<String, Object> consent, String roleName) {
+        if (consent.get("grantedRealmRoles") == null) return false;
+        return ((List)consent.get("grantedRealmRoles")).contains(roleName);
+    }
+
+    private static boolean isClientRoleGranted(Map<String, Object> consent, String clientId, String roleName) {
+        if (consent.get("grantedClientRoles") == null) return false;
+        Map<String, List> grantedClientRoles = (Map<String, List>)consent.get("grantedClientRoles");
+        List rolesForClient = grantedClientRoles.get(clientId);
+        if (rolesForClient == null) return false;
+        return rolesForClient.contains(roleName);
+    }
+
+    private static Map<String, List<String>> getGrantedProtocolMappers(Map<String, Object> consent) {
+        return (Map<String, List<String>>)consent.get("grantedProtocolMappers");
+    }
+
+    private static int calcNumberGrantedRoles(Map<String, Object> consent) {
+        int numGranted = 0;
+        List realmRoles = (List)consent.get("grantedRealmRoles");
+        if (realmRoles != null) numGranted += realmRoles.size();
+        Map clientRoles = (Map)consent.get("grantedClientRoles");
+        if (clientRoles != null) numGranted += clientRoles.size();
+        return numGranted;
+    }
+
+    private static Map<String, Object> findConsentByClientId(List<Map<String, Object>> consents, String clientId) {
+        for (Map<String, Object> consent : consents) {
+            if (clientId.equals(consent.get("clientId"))) return consent;
+        }
+        return null;
+    }
+
+    private static void assertGssProtocolMapper(ProtocolMapperRepresentation gssCredentialMapper) {
+        Assert.assertEquals(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME, gssCredentialMapper.getName());
+        Assert.assertEquals( OIDCLoginProtocol.LOGIN_PROTOCOL, gssCredentialMapper.getProtocol());
+        Assert.assertEquals(UserSessionNoteMapper.PROVIDER_ID, gssCredentialMapper.getProtocolMapper());
+        String includeInAccessToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
+        String includeInIdToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
+        Assert.assertTrue(includeInAccessToken.equalsIgnoreCase("true"));
+        Assert.assertTrue(includeInIdToken == null || Boolean.parseBoolean(includeInIdToken) == false);
+    }
+
+    private static ProtocolMapperRepresentation findMapperByName(List<ProtocolMapperRepresentation> mappers, String type, String name) {
+        for (ProtocolMapperRepresentation mapper : mappers) {
+            if (mapper.getProtocol().equals(type) &&
+                mapper.getName().equals(name)) {
+                return mapper;
+            }
+        }
+        return null;
+    }
+
+    private static boolean hasClient(List<ClientRepresentation> clients, ClientRepresentation client) {
+        for (ClientRepresentation clientRep : clients) {
+            if (client.getId().equals(clientRep.getId())) return true;
+        }
+        return false;
+    }
+
+    // Workaround for KEYCLOAK-3104.  For this realm, search() only works if username is null.
+    private static UserRepresentation findByUsername(RealmResource realmRsc, String username) {
+        for (UserRepresentation user : realmRsc.users().search(null, 0, Integer.MAX_VALUE)) {
+            if (user.getUsername().equalsIgnoreCase(username)) return user;
+        }
+        return null;
+    }
+
+    private static Set<RoleRepresentation> allScopeMappings(ClientResource client) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        List<RoleRepresentation> realmRoles = realmScopeMappings(client);
+        if (realmRoles != null) allRoles.addAll(realmRoles);
+
+        allRoles.addAll(clientScopeMappings(client));
+
+        return allRoles;
+    }
+
+    private static Set<RoleRepresentation> allScopeMappings(ClientTemplateResource client) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        List<RoleRepresentation> realmRoles = realmScopeMappings(client);
+        if (realmRoles != null) allRoles.addAll(realmRoles);
+
+        allRoles.addAll(clientScopeMappings(client));
+
+        return allRoles;
+    }
+
+    private static List<RoleRepresentation> clientScopeMappings(ClientResource client) {
+        List<RoleRepresentation> clientScopeMappings = new LinkedList<>();
+        Map<String, ClientMappingsRepresentation> clientRoles = client.getScopeMappings().getAll().getClientMappings();
+        if (clientRoles == null) return clientScopeMappings;
+
+        for (String clientKey : clientRoles.keySet()) {
+            List<RoleRepresentation> clientRoleScopeMappings = clientRoles.get(clientKey).getMappings();
+            if (clientRoleScopeMappings != null) clientScopeMappings.addAll(clientRoleScopeMappings);
+        }
+
+        return clientScopeMappings;
+    }
+
+    private static List<RoleRepresentation> clientScopeMappings(ClientTemplateResource client) {
+        List<RoleRepresentation> clientScopeMappings = new LinkedList<>();
+        Map<String, ClientMappingsRepresentation> clientRoles = client.getScopeMappings().getAll().getClientMappings();
+        if (clientRoles == null) return clientScopeMappings;
+
+        for (String clientKey : clientRoles.keySet()) {
+            List<RoleRepresentation> clientRoleScopeMappings = clientRoles.get(clientKey).getMappings();
+            if (clientRoleScopeMappings != null) clientScopeMappings.addAll(clientRoleScopeMappings);
+        }
+
+        return clientScopeMappings;
+    }
+
+    private static List<RoleRepresentation> realmScopeMappings(ClientResource client) {
+        return client.getScopeMappings().realmLevel().listAll();
+    }
+
+    private static List<RoleRepresentation> realmScopeMappings(ClientTemplateResource client) {
+        return client.getScopeMappings().realmLevel().listAll();
+    }
+
+    private static Set<RoleRepresentation> allRoles(RealmResource realmRsc, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        Set<RoleRepresentation> roles = new HashSet<>();
+
+        List<RoleRepresentation> realmRoles = userRsc.roles().getAll().getRealmMappings();
+        if (realmRoles != null) roles.addAll(realmRoles);
+
+        roles.addAll(allClientRolesForUser(realmRsc, user));
+
+        return roles;
+    }
+
+    private static List<RoleRepresentation> realmRolesForUser(RealmResource realmRsc, UserRepresentation user) {
+        return realmRsc.users().get(user.getId()).roles().getAll().getRealmMappings();
+    }
+
+    private static List<RoleRepresentation> allClientRolesForUser(RealmResource realmRsc, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        List<RoleRepresentation> roles = new LinkedList<>();
+        for(String client : userRsc.roles().getAll().getClientMappings().keySet()) {
+            List<RoleRepresentation> clientRoles = userRsc.roles().getAll().getClientMappings().get(client).getMappings();
+            if (clientRoles != null) roles.addAll(clientRoles);
+        }
+        return roles;
+    }
+
+    private static List<RoleRepresentation> clientRolesForUser(RealmResource realmRsc, ClientRepresentation client, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        return userRsc.roles().clientLevel(client.getId()).listAll();
+    }
+
+    private static RoleRepresentation findRealmRole(RealmResource realmRsc, String roleName) {
+        return realmRsc.roles().get(roleName).toRepresentation();
+    }
+
+    private static RoleRepresentation findClientRole(RealmResource realmRsc, String clientDbId, String roleName) {
+        return realmRsc.clients().get(clientDbId).roles().get(roleName).toRepresentation();
+    }
+
+    private static boolean containsRole(Collection<RoleRepresentation> roles, RoleRepresentation role) {
+        for (RoleRepresentation setRole : roles) {
+            if (setRole.getId().equals(role.getId())) return true;
+        }
+        return false;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
index 0d6de84..90178a9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
@@ -41,6 +41,7 @@ import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
 import org.keycloak.testsuite.util.OAuthClient;
 import org.keycloak.testsuite.util.UserBuilder;
+import org.keycloak.testsuite.util.RealmRepUtil;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -50,7 +51,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         CredentialRepresentation credRep = new CredentialRepresentation();
         credRep.setType(CredentialRepresentation.TOTP);
         credRep.setValue("totpSecret");
@@ -60,8 +61,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
         testRealm.setBruteForceProtected(true);
         testRealm.setFailureFactor(2);
 
-        findClientInRealmRep(testRealm, "test-app").setDirectAccessGrantsEnabled(true);
-
+        RealmRepUtil.findClientByClientId(testRealm, "test-app").setDirectAccessGrantsEnabled(true);
         testRealm.getUsers().add(UserBuilder.create().username("user2").email("user2@localhost").password("password").build());
     }
 
@@ -146,8 +146,8 @@ public class BruteForceTest extends TestRealmKeycloakTest {
             OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
             Assert.assertNull(response.getAccessToken());
             Assert.assertNotNull(response.getError());
-            Assert.assertEquals(response.getError(), "invalid_grant");
-            Assert.assertEquals(response.getErrorDescription(), "Account temporarily disabled");
+            Assert.assertEquals("invalid_grant", response.getError());
+            Assert.assertEquals("Account temporarily disabled", response.getErrorDescription());
             events.clear();
         }
         clearUserFailures();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
index d9f2182..73b2af4 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
@@ -45,6 +45,7 @@ import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.ExecutionBuilder;
 import org.keycloak.testsuite.util.FlowBuilder;
 import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 import static org.junit.Assert.assertEquals;
@@ -73,7 +74,7 @@ public class CustomFlowTest extends AbstractFlowTest {
                                               .build();
         testRealm.getClients().add(dummyClient);
 
-        ClientRepresentation testApp = findClientInRealmRep(testRealm, "test-app");
+        ClientRepresentation testApp = RealmRepUtil.findClientByClientId(testRealm, "test-app");
         testApp.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
         testApp.setDirectAccessGrantsEnabled(true);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
index 8964040..43c6153 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
@@ -36,6 +36,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 /**
@@ -48,7 +49,7 @@ public class LoginHotpTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         UserBuilder.edit(user)
                    .hotpSecret("hotpSecret")
                    .otpEnabled();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 1c04847..66e6bad 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -34,6 +34,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 /**
@@ -44,7 +45,7 @@ public class LoginTotpTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         UserBuilder.edit(user)
                    .totpSecret("totpSecret")
                    .otpEnabled();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
index 0e41cee..4eaba86 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
@@ -28,28 +28,12 @@ import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
 
 /**
  * This class provides loading of the testRealm called "test".  It also
- * provides an OAuthClient for the testRealm.
+ * provides a few utility methods for the testRealm.
  *
  * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
  */
 public abstract class TestRealmKeycloakTest extends AbstractKeycloakTest {
 
-    protected UserRepresentation findUserInRealmRep(RealmRepresentation testRealm, String userName) {
-        for (UserRepresentation user : testRealm.getUsers()) {
-            if (user.getUsername().equals(userName)) return user;
-        }
-
-        return null;
-    }
-
-    protected ClientRepresentation findClientInRealmRep(RealmRepresentation testRealm, String clientId) {
-        for (ClientRepresentation client : testRealm.getClients()) {
-            if (client.getClientId().equals(clientId)) return client;
-        }
-
-        return null;
-    }
-
     protected RealmResource testRealm() {
         return adminClient.realm("test");
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java
new file mode 100644
index 0000000..7d5b0c0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.testsuite.util;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class RealmRepUtil {
+
+    // don't allow instance
+    private RealmRepUtil() {
+    }
+
+    public static UserRepresentation findUser(RealmRepresentation testRealm, String userName) {
+        for (UserRepresentation user : testRealm.getUsers()) {
+            if (user.getUsername().equals(userName)) return user;
+        }
+
+        return null;
+    }
+
+    public static ClientRepresentation findClientByClientId(RealmRepresentation testRealm, String clientId) {
+        for (ClientRepresentation client : testRealm.getClients()) {
+            if (client.getClientId().equals(clientId)) return client;
+        }
+
+        return null;
+    }
+
+    public static ClientRepresentation findClientById(RealmRepresentation testRealm, String id) {
+        for (ClientRepresentation client : testRealm.getClients()) {
+            if (client.getId().equals(id)) return client;
+        }
+        return null;
+    }
+
+    public static RoleRepresentation findRealmRole(RealmRepresentation realm, String roleName) {
+        if (realm.getRoles() == null) return null;
+        if (realm.getRoles().getRealm() == null) return null;
+        for (RoleRepresentation role : realm.getRoles().getRealm()) {
+            if (role.getName().equals(roleName)) return role;
+        }
+
+        return null;
+    }
+
+    public static RoleRepresentation findClientRole(RealmRepresentation realm, String clientId, String roleName) {
+        if (realm.getRoles() == null) return null;
+        if (realm.getRoles().getClient() == null) return null;
+        if (realm.getRoles().getClient().get(clientId) == null) return null;
+        for (RoleRepresentation role : realm.getRoles().getClient().get(clientId)) {
+            if (roleName.equals(role.getName())) return role;
+        }
+
+        return null;
+    }
+
+    public static String findDefaultRole(RealmRepresentation realm, String roleName) {
+        if (realm.getDefaultRoles() == null) return null;
+        for (String role : realm.getDefaultRoles()) {
+            if (role.equals(roleName)) return role;
+        }
+
+        return null;
+    }
+
+    public static Set<RoleRepresentation> allRoles(RealmRepresentation realm, UserRepresentation user) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        for (String roleName : user.getRealmRoles()) {
+            allRoles.add(findRealmRole(realm, roleName));
+        }
+
+        for (String clientId : user.getClientRoles().keySet()) {
+            for (String roleName : user.getClientRoles().get(clientId)) {
+                allRoles.add(findClientRole(realm, clientId, roleName));
+            }
+        }
+
+        return allRoles;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testcomposites.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testcomposites.json
new file mode 100755
index 0000000..740a4e1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testcomposites.json
@@ -0,0 +1,191 @@
+{
+    "id": "TestComposites",
+    "realm": "TestComposites",
+    "enabled": true,
+    "accessTokenLifespan": 600,
+    "accessCodeLifespan": 600,
+    "accessCodeLifespanUserAction": 600,
+    "sslRequired": "external",
+    "registrationAllowed": true,
+    "resetPasswordAllowed": true,
+    "requiredCredentials": [ "password" ],
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "users" : [
+        {
+            "username" : "REALM_COMPOSITE_1_USER",
+            "enabled": true,
+            "email" : "test-user1@localhost",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "REALM_COMPOSITE_1" ]
+        },
+        {
+            "username" : "REALM_ROLE_1_USER",
+            "enabled": true,
+            "email" : "test-user2@localhost",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "REALM_ROLE_1"]
+        },
+        {
+            "username" : "REALM_APP_COMPOSITE_USER",
+            "enabled": true,
+            "email" : "test-user3@localhost",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "REALM_APP_COMPOSITE_ROLE" ]
+        },
+        {
+            "username" : "REALM_APP_ROLE_USER",
+            "enabled": true,
+            "email" : "test-user4@localhost",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "applicationRoles": {
+                "APP_ROLE_APPLICATION": [ "APP_ROLE_2" ]
+            }
+        },
+        {
+            "username" : "APP_COMPOSITE_USER",
+            "enabled": true,
+            "email" : "test-user5@localhost",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": ["REALM_APP_COMPOSITE_ROLE", "REALM_COMPOSITE_1"]
+        }
+    ],
+    "oauthClients" : [
+        {
+            "name" : "third-party",
+            "enabled": true,
+            "secret": "password"
+        }
+    ],
+    "scopeMappings": [
+        {
+            "client": "REALM_COMPOSITE_1_APPLICATION",
+            "roles": ["REALM_COMPOSITE_1"]
+        },
+        {
+            "client": "REALM_ROLE_1_APPLICATION",
+            "roles": ["REALM_ROLE_1"]
+        }
+    ],
+    "applications": [
+        {
+            "name": "REALM_COMPOSITE_1_APPLICATION",
+            "fullScopeAllowed": false,
+            "enabled": true,
+            "baseUrl": "http://localhost:8081/app",
+            "adminUrl": "http://localhost:8081/app/logout",
+            "secret": "password"
+         },
+        {
+            "name": "REALM_ROLE_1_APPLICATION",
+            "fullScopeAllowed": false,
+            "enabled": true,
+            "baseUrl": "http://localhost:8081/app",
+            "adminUrl": "http://localhost:8081/app/logout",
+            "secret": "password"
+        },
+        {
+            "name": "APP_ROLE_APPLICATION",
+            "fullScopeAllowed": false,
+            "enabled": true,
+            "baseUrl": "http://localhost:8081/app",
+            "adminUrl": "http://localhost:8081/app/logout",
+            "secret": "password"
+        },
+        {
+            "name": "APP_COMPOSITE_APPLICATION",
+            "fullScopeAllowed": false,
+            "enabled": true,
+            "baseUrl": "http://localhost:8081/app",
+            "adminUrl": "http://localhost:8081/app/logout",
+            "secret": "password"
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "REALM_ROLE_1"
+            },
+            {
+                "name": "REALM_ROLE_2"
+            },
+            {
+                "name": "REALM_ROLE_3"
+            },
+            {
+                "name": "REALM_COMPOSITE_1",
+                "composites": {
+                    "realm": ["REALM_ROLE_1"]
+                }
+            },
+            {
+                "name": "REALM_APP_COMPOSITE_ROLE",
+                "composites": {
+                    "application": {
+                        "APP_ROLE_APPLICATION" :[
+                            "APP_ROLE_1"
+                        ]
+                    }
+                }
+            }
+        ],
+        "application" : {
+            "APP_ROLE_APPLICATION" : [
+                {
+                    "name": "APP_ROLE_1"
+                },
+                {
+                    "name": "APP_ROLE_2"
+                }
+            ],
+            "APP_COMPOSITE_APPLICATION" : [
+                {
+                    "name": "APP_COMPOSITE_ROLE",
+                    "composites": {
+                        "realm" : [
+                            "REALM_ROLE_1",
+                            "REALM_ROLE_2",
+                            "REALM_ROLE_3"
+                        ],
+                        "application": {
+                            "APP_ROLE_APPLICATION" :[
+                                "APP_ROLE_1"
+                            ]
+                        }
+                    }
+                },
+                {
+                    "name": "APP_ROLE_2"
+                }
+            ]
+        }
+
+    },
+
+    "applicationScopeMappings": {
+        "APP_ROLE_APPLICATION": [
+            {
+                "client": "APP_COMPOSITE_APPLICATION",
+                "roles": ["APP_ROLE_2"]
+            }
+        ]
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
new file mode 100755
index 0000000..23be719
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
@@ -0,0 +1,290 @@
+{
+    "realm": "test-realm",
+    "enabled": true,
+    "accessTokenLifespan": 6000,
+    "accessTokenLifespanForImplicitFlow": 1500,
+    "accessCodeLifespan": 30,
+    "accessCodeLifespanUserAction": 600,
+    "offlineSessionIdleTimeout": 3600000,
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "foo", "bar" ],
+    "verifyEmail" : "true",
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "identityProviders" : [
+        {
+            "providerId" : "google",
+            "alias" : "google1",
+            "enabled": true,
+            "config": {
+                "clientId": "googleId",
+                "clientSecret": "googleSecret"
+            }
+        },
+        {
+            "providerId" : "facebook",
+            "alias" : "facebook1",
+            "enabled": true,
+            "config": {
+                "clientId": "facebookId",
+                "clientSecret": "facebookSecret"
+            }
+        },
+        {
+            "providerId" : "twitter",
+            "alias" : "twitter1",
+            "enabled": true,
+            "config": {
+                "clientId": "twitterId",
+                "clientSecret": "twitterSecret"
+            }
+        }
+    ],
+    "userFederationProviders": [
+        {
+            "displayName": "MyLDAPProvider1",
+            "providerName": "ldap",
+            "priority": 1,
+            "config": {
+                "connectionUrl": "ldap://foo"
+            }
+        },
+        {
+            "displayName": "MyLDAPProvider2",
+            "providerName": "ldap",
+            "priority": 2,
+            "config": {
+                "connectionUrl": "ldap://bar"
+            }
+        }
+    ],
+    "userFederationMappers": [
+        {
+            "name": "FullNameMapper",
+            "federationProviderDisplayName": "MyLDAPProvider1",
+            "federationMapperType": "full-name-ldap-mapper",
+            "config": {
+                "ldap.full.name.attribute": "cn"
+            }
+        }
+    ],
+    "users": [
+        {
+            "username": "wburke",
+            "enabled": true,
+            "createdTimestamp" : 123654,
+            "attributes": {
+                "email": "bburke@redhat.com"
+            },
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "userpassword"
+                }
+            ],
+            "applicationRoles": {
+                "Application": [ "app-user" ],
+                "OtherApp": [  "otherapp-user" ]
+            }
+        },
+        {
+            "username": "loginclient",
+            "createdTimestamp" : "123655",
+            "enabled": true,
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "clientpassword"
+                }
+            ]
+        },
+        {
+            "username": "admin",
+            "enabled": true,
+            "attributes": {
+                "key1": [
+                    "val1"
+                ],
+                "key2": [
+                    "val21",
+                    "val22"
+                ]
+            },
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "adminpassword"
+                }
+            ],
+            "realmRoles": [ "admin" ],
+            "applicationRoles": {
+                "Application": [ "app-admin" ],
+                "OtherApp": [  "otherapp-admin" ]
+            },
+            "clientConsents": [
+                {
+                    "clientId": "Application",
+                    "grantedRealmRoles": [ "admin" ],
+                    "grantedClientRoles": {
+                        "Application": [ "app-admin" ]
+                    }
+                },
+                {
+                    "clientId": "OtherApp",
+                    "grantedRealmRoles": [ "admin" ],
+                    "grantedProtocolMappers": {
+                        "openid-connect": [ "gss delegation credential" ]
+                    }
+                }
+            ]
+        },
+        {
+            "username": "mySocialUser",
+            "enabled": true,
+            "federatedIdentities": [
+                {
+                    "identityProvider": "facebook1",
+                    "userId": "facebook1",
+                    "userName": "fbuser1"
+                },
+                {
+                    "identityProvider": "twitter1",
+                    "userId": "twitter1",
+                    "userName": "twuser1"
+                },
+                {
+                    "identityProvider": "google1",
+                    "userId": "google1",
+                    "userName": "mySocialUser@gmail.com"
+                }
+            ]
+        },
+        {
+            "username": "my-service-user",
+            "enabled": true,
+            "serviceAccountClientId": "OtherApp"
+        }
+    ],
+    "clients": [
+        {
+            "clientId": "Application",
+            "name": "Applicationn",
+            "enabled": true,
+            "implicitFlowEnabled": true,
+            "directAccessGrantsEnabled": true,
+            "nodeReRegistrationTimeout": 50,
+            "registeredNodes": {
+                "node1": 10,
+                "172.10.15.20": 20
+            }
+        },
+        {
+            "clientId": "OtherApp",
+            "name": "Other Application",
+            "enabled": true,
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": false,
+            "serviceAccountsEnabled": true,
+            "clientAuthenticatorType": "client-jwt",
+            "protocolMappers" : [
+                {
+                    "name" : "gss delegation credential",
+                    "protocol" : "openid-connect",
+                    "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+                    "consentRequired" : true,
+                    "consentText" : "gss delegation credential",
+                    "config" : {
+                        "user.session.note" : "gss_delegation_credential",
+                        "access.token.claim" : "true",
+                        "claim.name" : "gss_delegation_credential",
+                        "Claim JSON Type" : "String"
+                    }
+                }
+            ]
+        }
+    ],
+    "oauthClients" : [
+        {
+            "name" : "oauthclient",
+            "enabled": true,
+            "secret": "clientpassword"
+        }
+    ],
+    "clientTemplates" : [
+        {
+            "name" : "foo-template",
+            "description" : "foo-template-desc",
+            "protocol" : "openid-connect",
+            "protocolMappers" : [
+                {
+                    "name" : "gss delegation credential",
+                    "protocol" : "openid-connect",
+                    "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+                    "consentRequired" : true,
+                    "consentText" : "gss delegation credential",
+                    "config" : {
+                        "user.session.note" : "gss_delegation_credential",
+                        "access.token.claim" : "true",
+                        "claim.name" : "gss_delegation_credential",
+                        "Claim JSON Type" : "String"
+                    }
+                }
+            ]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "admin"
+            }
+        ],
+        "application" : {
+            "Application" : [
+                {
+                    "name": "app-admin",
+                    "scopeParamRequired": true
+                },
+                {
+                    "name": "app-user"
+                }
+            ],
+            "OtherApp" : [
+                {
+                    "name": "otherapp-admin",
+                    "scopeParamRequired": false
+                },
+                {
+                    "name": "otherapp-user"
+                }
+            ]
+        }
+    },
+    "scopeMappings": [
+        {
+            "client": "oauthclient",
+            "roles": ["admin"]
+        },
+        {
+            "clientTemplate": "foo-template",
+            "roles": ["admin"]
+        }
+    ],
+    "applicationScopeMappings": {
+        "Application": [
+            {
+                "client": "oauthclient",
+                "roles": ["app-user"]
+            },
+            {
+                "clientTemplate": "foo-template",
+                "roles": ["app-user", "app-admin" ]
+            }
+        ]
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json
new file mode 100755
index 0000000..4e3d9fb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json
@@ -0,0 +1,89 @@
+{
+    "realm": "demo-delete",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": ["user"],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        },
+        {
+            "client": "customer-portal",
+            "roles": ["user"]
+        },
+        {
+            "client": "product-portal",
+            "roles": ["user"]
+        }
+
+    ],
+    "applications": [
+        {
+            "name": "customer-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/customer-portal",
+            "redirectUris": [
+                "http://localhost:8080/customer-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "product-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/product-portal",
+            "redirectUris": [
+                "http://localhost:8080/product-portal/*"
+            ],
+            "secret": "password"
+        }
+    ],
+    "oauthClients": [
+        {
+            "name": "third-party",
+            "enabled": true,
+            "redirectUris": [
+                "http://localhost:8080/oauth-client/*",
+                "http://localhost:8080/oauth-client-cdi/*"
+            ],
+            "secret": "password"
+        }
+    ]
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json
new file mode 100755
index 0000000..c98bbf7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json
@@ -0,0 +1,63 @@
+{
+    "realm": "demo",
+    "enabled": true,
+    "accessTokenLifespan": 300,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 600,
+    "sslRequired": "external",
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "Password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "user" ]
+        }
+    ],
+    "oauthClients" : [
+        {
+            "name" : "third-party",
+            "enabled": true,
+            "secret": "password"
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Have Administrator privileges"
+            }
+        ]
+    },
+
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        }
+    ],
+    "applications": [
+        {
+            "name": "customer-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/customer-portal/j_admin_request",
+            "secret": "password"
+        },
+        {
+            "name": "product-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/product-portal/j_admin_request",
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json
new file mode 100755
index 0000000..4751c7f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json
@@ -0,0 +1,57 @@
+
+{
+    "realm": "demo-no-client-id",
+    "enabled": true,
+    "accessTokenLifespan": 300,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 600,
+    "sslRequired": "external",
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "Password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user" ]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Have Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        }
+    ],
+    "clients": [
+        {
+            "name": "third-party",
+            "enabled": true,
+            "bearerOnly": true
+        }
+    ],
+    "clientScopeMappings": {
+        "realm-management": [
+            {
+                "client": "some-client",
+                "roles": ["create-client"]
+            }
+        ]
+    }
+}
\ No newline at end of file