keycloak-uncached

Merge pull request #366 from mposolda/export-import-rebased Full

5/6/2014 10:17:51 PM

Changes

model/jpa/pom.xml 15(+15 -0)

pom.xml 8(+8 -0)

server/pom.xml 15(+15 -0)

services/pom.xml 6(+6 -0)

Details

diff --git a/export-import/export-import-api/pom.xml b/export-import/export-import-api/pom.xml
new file mode 100644
index 0000000..7f94100
--- /dev/null
+++ b/export-import/export-import-api/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-export-import</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-beta-1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-export-import-api</artifactId>
+    <name>Keycloak Export Import API</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java
new file mode 100644
index 0000000..9ada46b
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportProvider.java
@@ -0,0 +1,11 @@
+package org.keycloak.exportimport;
+
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportImportProvider {
+
+    void checkExportImport(KeycloakSessionFactory identitySessionFactory);
+}
diff --git a/export-import/export-import-impl/pom.xml b/export-import/export-import-impl/pom.xml
new file mode 100644
index 0000000..a4898e5
--- /dev/null
+++ b/export-import/export-import-impl/pom.xml
@@ -0,0 +1,228 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-export-import</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-beta-1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-export-import-impl</artifactId>
+    <name>Keycloak Export Import Impl</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-audit-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>jaxrs-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.iharder</groupId>
+            <artifactId>base64</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Encrypted ZIP -->
+        <dependency>
+            <groupId>de.idyl</groupId>
+            <artifactId>winzipaes</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-tests</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-jpa</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-jpa</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-mongo</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate.javax.persistence</groupId>
+            <artifactId>hibernate-jpa-2.0-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-entitymanager</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <keycloak.mongo.host>localhost</keycloak.mongo.host>
+        <keycloak.mongo.port>27018</keycloak.mongo.port>
+        <keycloak.mongo.db>keycloak</keycloak.mongo.db>
+        <keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+
+            <!-- Postpone tests to "integration-test" phase, so that we can bootstrap embedded mongo on 27018 before running tests -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>test</id>
+                        <phase>integration-test</phase>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                        <configuration>
+                            <systemPropertyVariables>
+                                <keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
+                                <keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
+                                <keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
+                                <keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>default-test</id>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- Embedded mongo -->
+            <plugin>
+                <groupId>com.github.joelittlejohn.embedmongo</groupId>
+                <artifactId>embedmongo-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>start-mongodb</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>start</goal>
+                        </goals>
+                        <configuration>
+                            <port>${keycloak.mongo.port}</port>
+                            <logging>file</logging>
+                            <logFile>${project.build.directory}/mongodb.log</logFile>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>stop-mongodb</id>
+                        <phase>post-integration-test</phase>
+                        <goals>
+                            <goal>stop</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+    </build>
+
+</project>
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java
new file mode 100644
index 0000000..87dfa55
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java
@@ -0,0 +1,152 @@
+package org.keycloak.exportimport;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.utils.reflection.Property;
+import org.keycloak.models.utils.reflection.PropertyCriteria;
+import org.keycloak.models.utils.reflection.PropertyQueries;
+
+/**
+ * Not thread safe (objectProperties). Assumption is that export/import is executed once per JVM
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportPropertiesManager {
+
+    private static final Logger logger = Logger.getLogger(ExportImportPropertiesManager.class);
+
+    private Map<Class<?>, Map<String, Property<Object>>> objectProperties = new HashMap<Class<?>, Map<String, Property<Object>>>();
+
+    // Add properties of class to objectProperties
+    protected void initClassProperties(Class<?> clazz) {
+        Map<String, Property<Object>> classProps = PropertyQueries.createQuery(clazz).addCriteria(new NonEmptyGetterCriteria()).getWritableResultList();
+        this.objectProperties.put(clazz, classProps);
+    }
+
+    public void setBasicPropertiesFromModel(Object model, Object entity) {
+        Class<?> modelClass = getModelClass(model);
+
+        // Lazy init of properties
+        checkPropertiesAvailable(modelClass, entity.getClass());
+
+        Map<String, Property<Object>> modelProps = this.objectProperties.get(modelClass);
+        Map<String, Property<Object>> entityProps = this.objectProperties.get(entity.getClass());
+
+        Map<String, Property<Object>> entityPropsCopy = new HashMap<String, Property<Object>>(entityProps);
+
+        logger.debugf("Properties of entity %s: %s", entity, entityProps.keySet());
+        for (Property<Object> modelProperty : modelProps.values()) {
+            Property<Object> entityProperty = entityPropsCopy.get(modelProperty.getName());
+
+            entityPropsCopy.remove(modelProperty.getName());
+
+            if (entityProperty != null) {
+                Object propertyValue = modelProperty.getValue(model);
+
+                // Workaround needed because model classes have many getters/setters with "Set", but for entity classes, there are usually "List"
+                if (propertyValue instanceof Set) {
+                    Set propValueAsSet = (Set)propertyValue;
+                    entityProperty.setValue(entity, new ArrayList(propValueAsSet));
+                }  else {
+                    entityProperty.setValue(entity, propertyValue);
+                }
+                if (logger.isTraceEnabled()) {
+                    logger.tracef("Property %s successfully set in JSON to entity %s", modelProperty.getName(), entity);
+                }
+            } else {
+                logger.debugf("Property %s not known in JSON for entity %s", modelProperty.getName(), entity);
+            }
+        }
+
+        logger.debugf("Entity properties for manual setup: %s", entityPropsCopy.keySet());
+    }
+
+    private void checkPropertiesAvailable(Class<?> modelClass, Class<?> entityClass) {
+        if (!objectProperties.containsKey(modelClass)) {
+            initClassProperties(modelClass);
+        }
+        if (!objectProperties.containsKey(entityClass)) {
+            initClassProperties(entityClass);
+        }
+    }
+
+    public void setBasicPropertiesToModel(Object model, Object entity) {
+        Class<?> modelClass = getModelClass(model);
+
+        // Lazy init of properties
+        checkPropertiesAvailable(modelClass, entity.getClass());
+
+        Map<String, Property<Object>> modelProps = this.objectProperties.get(modelClass);
+        Map<String, Property<Object>> entityProps = this.objectProperties.get(entity.getClass());
+
+        Map<String, Property<Object>> entityPropsCopy = new HashMap<String, Property<Object>>(entityProps);
+
+        logger.debugf("Properties of exported entity %s: %s", entity, entityProps.keySet());
+
+        for (Property<Object> modelProperty : modelProps.values()) {
+            Property<Object> entityProperty = entityPropsCopy.get(modelProperty.getName());
+
+            entityPropsCopy.remove(modelProperty.getName());
+
+            if (entityProperty != null) {
+                Object propertyValue = entityProperty.getValue(entity);
+
+                // Workaround needed because model classes have many getters/setters with "Set", but for entity classes, there are usually "List"
+                if (propertyValue instanceof List && Set.class.isAssignableFrom(modelProperty.getJavaClass())) {
+                    List propValueAsList = (List)propertyValue;
+                    modelProperty.setValue(model, new HashSet(propValueAsList));
+                }  else {
+                    modelProperty.setValue(model, propertyValue);
+                }
+
+                if (logger.isTraceEnabled()) {
+                    logger.tracef("Property %s successfully set in model from entity %s", modelProperty.getName(), entity);
+                }
+            } else {
+                logger.debugf("Property %s not known for entity %s", modelProperty.getName(), entity);
+            }
+        }
+
+        logger.debugf("Entity properties for manual setup: %s", entityPropsCopy.keySet());
+    }
+
+    protected Class<?> getModelClass(Object model) {
+        Class<?> modelClass = model.getClass();
+        Class<?>[] interfaces = modelClass.getInterfaces();
+
+        // Bit unsafe, but looks that it works for all "model adapters" so far
+        if (interfaces.length == 0) {
+            return modelClass;
+        } else {
+            return interfaces[0];
+        }
+    }
+
+    public static class NonEmptyGetterCriteria implements PropertyCriteria {
+
+        private static final List<String> IGNORED_METHODS = Arrays.asList("getPasswordPolicy", "getAuthenticationProviders");
+
+        @Override
+        public boolean methodMatches(Method m) {
+            // Ignore non-empty getters
+            if (m.getParameterTypes().length > 0) {
+                return false;
+            }
+
+            // Ignore some "known" getters (for example incompatible types between model and entity)
+            if (IGNORED_METHODS.contains(m.getName())) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
new file mode 100644
index 0000000..32e0b84
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
@@ -0,0 +1,84 @@
+package org.keycloak.exportimport;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ExportImportIOProvider;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.util.ProviderLoader;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportProviderImpl implements ExportImportProvider {
+
+    private static final Logger logger = Logger.getLogger(ExportImportProviderImpl.class);
+
+    public static final String ACTION_EXPORT = "export";
+    public static final String ACTION_IMPORT = "import";
+
+    @Override
+    public void checkExportImport(KeycloakSessionFactory identitySessionFactory) {
+        String exportImportAction = Config.getExportImportAction();
+
+        boolean export = false;
+        boolean importt = false;
+        if (ACTION_EXPORT.equals(exportImportAction)) {
+            logger.infof("Full model export requested");
+            export = true;
+        } else if (ACTION_IMPORT.equals(exportImportAction)) {
+            logger.infof("Full model import requested");
+            importt = true;
+        }
+
+        if (export || importt) {
+            KeycloakSession session = identitySessionFactory.createSession();
+            KeycloakTransaction transaction = session.getTransaction();
+            try {
+                transaction.begin();
+
+                if (export) {
+                    ExportWriter exportWriter = getProvider().getExportWriter();
+                    new ModelExporter().exportModel(session, exportWriter);
+                    logger.infof("Export finished successfully");
+                } else {
+                    ImportReader importReader = getProvider().getImportReader();
+                    new ModelImporter().importModel(session, importReader);
+                    logger.infof("Import finished successfully");
+                }
+
+                if (transaction.isActive()) {
+                    if (transaction.getRollbackOnly()) {
+                        transaction.rollback();
+                    } else {
+                        transaction.commit();
+                    }
+                }
+            } catch (Exception e) {
+                if (transaction.isActive()) {
+                    session.getTransaction().rollback();
+                }
+                throw new RuntimeException(e);
+            } finally {
+                session.close();
+            }
+        }
+    }
+
+    private ExportImportIOProvider getProvider() {
+        String providerId = Config.getExportImportProvider();
+        logger.infof("Requested migration provider: " + providerId);
+
+        Iterable<ExportImportIOProvider> providers = ProviderLoader.load(ExportImportIOProvider.class);
+        for (ExportImportIOProvider provider : providers) {
+            if (providerId.equals(provider.getId())) {
+                return provider;
+            }
+        }
+
+        throw new IllegalStateException("Provider " + providerId + " not found");
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java
new file mode 100644
index 0000000..962c3ac
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportImportIOProvider.java
@@ -0,0 +1,36 @@
+package org.keycloak.exportimport.io.directory;
+
+import java.io.File;
+
+import org.keycloak.exportimport.io.ExportImportIOProvider;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.models.Config;
+
+/**
+ * Export/import into JSON files inside "tmp" directory. This implementation is used mainly for testing
+ * (shouldn't be used in production due to passwords in JSON files)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class TmpDirExportImportIOProvider implements ExportImportIOProvider {
+
+    public static final String PROVIDER_ID = "dir";
+
+    @Override
+    public ExportWriter getExportWriter() {
+        String dir = Config.getExportImportDir();
+        return dir!=null ? new TmpDirExportWriter(new File(dir)) : new TmpDirExportWriter();
+    }
+
+    @Override
+    public ImportReader getImportReader() {
+        String dir = Config.getExportImportDir();
+        return dir!=null ? new TmpDirImportReader(new File(dir)) : new TmpDirImportReader();
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportWriter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportWriter.java
new file mode 100644
index 0000000..d1ee454
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirExportWriter.java
@@ -0,0 +1,82 @@
+package org.keycloak.exportimport.io.directory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class TmpDirExportWriter implements ExportWriter {
+
+    private static final Logger logger = Logger.getLogger(TmpDirExportWriter.class);
+
+    private final ObjectMapper objectMapper;
+    private final File rootDirectory;
+
+    public TmpDirExportWriter() {
+        // Determine system tmp directory
+        String tempDir = System.getProperty("java.io.tmpdir");
+
+        // Delete and recreate directory inside tmp
+        this.rootDirectory = new File(tempDir + "/keycloak-export");
+        if (this.rootDirectory .exists()) {
+            recursiveDeleteDir(this.rootDirectory );
+        }
+        this.rootDirectory.mkdirs();
+
+        logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
+        this.objectMapper = getObjectMapper();
+    }
+
+    public TmpDirExportWriter(File rootDirectory) {
+        this.rootDirectory = rootDirectory;
+        this.rootDirectory.mkdirs();
+        this.objectMapper = getObjectMapper();
+
+        logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
+    }
+
+    private ObjectMapper getObjectMapper() {
+        return JsonSerialization.prettyMapper;
+    }
+
+    protected boolean recursiveDeleteDir(File dirPath) {
+        if (dirPath.exists()) {
+            File[] files = dirPath.listFiles();
+            for (int i = 0; i < files.length; i++) {
+                if (files[i].isDirectory()) {
+                    recursiveDeleteDir(files[i]);
+                } else {
+                    files[i].delete();
+                }
+            }
+        }
+        if (dirPath.exists())
+            return dirPath.delete();
+        else
+            return true;
+    }
+
+    @Override
+    public <T> void writeEntities(String fileName, List<T> entities) {
+        try {
+            File file = new File(this.rootDirectory, fileName);
+            FileOutputStream stream = new FileOutputStream(file);
+            this.objectMapper.writeValue(stream, entities);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public void closeExportWriter() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirImportReader.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirImportReader.java
new file mode 100644
index 0000000..942e23a
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirImportReader.java
@@ -0,0 +1,67 @@
+package org.keycloak.exportimport.io.directory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.List;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class TmpDirImportReader implements ImportReader {
+
+    private static final Logger logger = Logger.getLogger(TmpDirImportReader.class);
+
+    private final ObjectMapper objectMapper;
+    private final File rootDirectory;
+
+    public TmpDirImportReader() {
+        // Determine system tmp directory
+        String tempDir = System.getProperty("java.io.tmpdir");
+
+        // Delete and recreate directory inside tmp
+        this.rootDirectory = new File(tempDir + "/keycloak-export");
+        if (!this.rootDirectory .exists()) {
+            throw new IllegalStateException("Directory " + this.rootDirectory + " doesn't exists");
+        }
+
+        logger.infof("Importing from directory %s", this.rootDirectory.getAbsolutePath());
+        this.objectMapper = getObjectMapper();
+    }
+
+    public TmpDirImportReader(File rootDirectory) {
+        this.rootDirectory = rootDirectory;
+        this.objectMapper = getObjectMapper();
+
+        logger.infof("Importing from directory %s", this.rootDirectory.getAbsolutePath());
+    }
+
+    private ObjectMapper getObjectMapper() {
+        return JsonSerialization.prettyMapper;
+    }
+
+    @Override
+    public <T> List<T> readEntities(String fileName, Class<T> entityClass) {
+        try {
+            File file = new File(this.rootDirectory, fileName);
+            FileInputStream stream = new FileInputStream(file);
+            T[] template = (T[]) Array.newInstance(entityClass, 0);
+            T[] result = (T[])this.objectMapper.readValue(stream, template.getClass());
+            return Arrays.asList(result);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public void closeImportReader() {
+        //TODO: Should directory be deleted after import?
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportImportIOProvider.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportImportIOProvider.java
new file mode 100644
index 0000000..e53b331
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportImportIOProvider.java
@@ -0,0 +1,14 @@
+package org.keycloak.exportimport.io;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportImportIOProvider {
+
+    String getId();
+
+    ExportWriter getExportWriter();
+
+    ImportReader getImportReader();
+
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportWriter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportWriter.java
new file mode 100644
index 0000000..c90a57f
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportWriter.java
@@ -0,0 +1,13 @@
+package org.keycloak.exportimport.io;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportWriter {
+
+    <T> void writeEntities(String fileName, List<T> entities);
+
+    void closeExportWriter();
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ImportReader.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ImportReader.java
new file mode 100644
index 0000000..83faabd
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ImportReader.java
@@ -0,0 +1,13 @@
+package org.keycloak.exportimport.io;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ImportReader {
+
+    <T> List<T> readEntities(String fileName, Class<T> entityClass);
+
+    void closeImportReader();
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPExportWriter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPExportWriter.java
new file mode 100644
index 0000000..0b49940
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPExportWriter.java
@@ -0,0 +1,66 @@
+package org.keycloak.exportimport.io.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import de.idyl.winzipaes.AesZipFileEncrypter;
+import de.idyl.winzipaes.impl.AESEncrypter;
+import de.idyl.winzipaes.impl.AESEncrypterBC;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class EncryptedZIPExportWriter implements ExportWriter {
+
+    private final File zipFile;
+    private final ObjectMapper objectMapper;
+    private final String password;
+
+    private final AesZipFileEncrypter encrypter;
+
+
+    public EncryptedZIPExportWriter(String zipFileName, String password) {
+        try {
+            this.zipFile = new File(zipFileName);
+            if (zipFile.exists()) {
+                throw new IllegalStateException("File " + zipFileName + " already exists");
+            }
+
+            this.objectMapper = JsonSerialization.mapper;
+
+            AESEncrypter encrypter = new AESEncrypterBC();
+            this.encrypter = new AesZipFileEncrypter(this.zipFile, encrypter);
+            this.password = password;
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public <T> void writeEntities(String fileName, List<T> entities) {
+        try {
+            ByteArrayOutputStream stream = new ByteArrayOutputStream();
+            this.objectMapper.writeValue(stream, entities);
+
+            byte[] byteArray = stream.toByteArray();
+            this.encrypter.add(fileName, new ByteArrayInputStream(byteArray), this.password);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public void closeExportWriter() {
+        try {
+            this.encrypter.close();
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPImportReader.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPImportReader.java
new file mode 100644
index 0000000..d115b7d
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPImportReader.java
@@ -0,0 +1,70 @@
+package org.keycloak.exportimport.io.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.List;
+
+import de.idyl.winzipaes.AesZipFileDecrypter;
+import de.idyl.winzipaes.impl.AESDecrypter;
+import de.idyl.winzipaes.impl.AESDecrypterBC;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class EncryptedZIPImportReader implements ImportReader {
+
+    private final File zipFile;
+    private final ObjectMapper objectMapper;
+    private final String password;
+
+    private final AesZipFileDecrypter decrypter;
+
+
+    public EncryptedZIPImportReader(String zipFileName, String password) {
+        try {
+            this.zipFile = new File(zipFileName);
+            if (!zipFile.exists()) {
+                throw new IllegalStateException("File " + zipFileName + " doesn't exists");
+            }
+
+            this.objectMapper = JsonSerialization.mapper;
+
+            AESDecrypter decrypter = new AESDecrypterBC();
+            this.decrypter = new AesZipFileDecrypter(this.zipFile, decrypter);
+            this.password = password;
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public <T> List<T> readEntities(String fileName, Class<T> entityClass) {
+        try {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            this.decrypter.extractEntry(this.decrypter.getEntry(fileName), bos, this.password);
+
+            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+            T[] template = (T[]) Array.newInstance(entityClass, 0);
+            T[] result = (T[])this.objectMapper.readValue(bis, template.getClass());
+            return Arrays.asList(result);
+        } catch (Exception ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    @Override
+    public void closeImportReader() {
+        try {
+            this.decrypter.close();
+        } catch (Exception ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java
new file mode 100644
index 0000000..837157e
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java
@@ -0,0 +1,48 @@
+package org.keycloak.exportimport.io.zip;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ExportImportIOProvider;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.models.Config;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class EncryptedZIPIOProvider implements ExportImportIOProvider {
+
+    private static final Logger logger = Logger.getLogger(EncryptedZIPIOProvider.class);
+
+    public static final String PROVIDER_ID = "zip";
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public ExportWriter getExportWriter() {
+        String zipFile = Config.getExportImportZipFile();
+        String zipPassword = Config.getExportImportZipPassword();
+        logger.infof("Using zip for export: " + zipFile);
+
+        if (zipFile==null || zipPassword==null) {
+            throw new IllegalArgumentException("zipFile or zipPassword are null");
+        }
+
+        return new EncryptedZIPExportWriter(zipFile, zipPassword);
+    }
+
+    @Override
+    public ImportReader getImportReader() {
+        String zipFile = Config.getExportImportZipFile();
+        String zipPassword = Config.getExportImportZipPassword();
+        logger.infof("Using zip for import: " + zipFile);
+
+        if (zipFile==null || zipPassword==null) {
+            throw new IllegalArgumentException("zipFile or zipPassword are null");
+        }
+
+        return new EncryptedZIPImportReader(zipFile, zipPassword);
+    }
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java
new file mode 100644
index 0000000..b1893f3
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java
@@ -0,0 +1,334 @@
+package org.keycloak.exportimport;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ExportWriter;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.AuthenticationProviderModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.entities.ApplicationEntity;
+import org.keycloak.models.entities.AuthenticationLinkEntity;
+import org.keycloak.models.entities.AuthenticationProviderEntity;
+import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.OAuthClientEntity;
+import org.keycloak.models.entities.RealmEntity;
+import org.keycloak.models.entities.RequiredCredentialEntity;
+import org.keycloak.models.entities.RoleEntity;
+import org.keycloak.models.entities.SocialLinkEntity;
+import org.keycloak.models.entities.UserEntity;
+import org.keycloak.models.entities.UsernameLoginFailureEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ModelExporter {
+
+    private static final Logger logger = Logger.getLogger(ModelExporter.class);
+
+    private ExportWriter exportWriter;
+    private ExportImportPropertiesManager propertiesManager;
+
+    public void exportModel(KeycloakSession keycloakSession, ExportWriter exportWriter) {
+        // Initialize needed objects
+        this.exportWriter = exportWriter;
+        this.propertiesManager = new ExportImportPropertiesManager();
+
+        // Create separate files for "realms", "applications", "oauthClients", "roles" and finally "users". Users may be done in more files (pagination)
+        exportRealms(keycloakSession, "realms.json");
+        exportApplications(keycloakSession, "applications.json");
+        exportOAuthClients(keycloakSession, "oauthClients.json");
+        exportRoles(keycloakSession, "roles.json");
+        exportUsers(keycloakSession, "users.json");
+        exportUserFailures(keycloakSession, "userFailures.json");
+
+        this.exportWriter.closeExportWriter();
+    }
+
+    protected void exportRealms(KeycloakSession keycloakSession, String fileName) {
+        List<RealmModel> realms = keycloakSession.getRealms();
+
+        // Convert models to entities, which will be written into JSON file
+        List<RealmEntity> result = new LinkedList<RealmEntity>();
+        for (RealmModel realmModel : realms) {
+            RealmEntity entity = new RealmEntity();
+            entity.setId(realmModel.getId());
+            result.add(entity);
+
+            // Export all basic properties from realm
+            this.propertiesManager.setBasicPropertiesFromModel(realmModel, entity);
+
+            // Export 'advanced' properties
+            ApplicationModel realmAdminApp = realmModel.getAdminApp();
+            if (realmAdminApp != null) {
+                entity.setAdminAppId(realmAdminApp.getId());
+            }
+            entity.setDefaultRoles(realmModel.getDefaultRoles());
+
+            List<RequiredCredentialEntity> reqCredEntities = new ArrayList<RequiredCredentialEntity>();
+            List<RequiredCredentialModel> requiredCredModels = realmModel.getRequiredCredentials();
+            for (RequiredCredentialModel requiredCredModel : requiredCredModels) {
+                RequiredCredentialEntity reqCredEntity = new RequiredCredentialEntity();
+                this.propertiesManager.setBasicPropertiesFromModel(requiredCredModel, reqCredEntity);
+                reqCredEntities.add(reqCredEntity);
+            }
+            entity.setRequiredCredentials(reqCredEntities);
+
+            // password policy
+            entity.setPasswordPolicy(realmModel.getPasswordPolicy().toString());
+
+            // authentication providers
+            List<AuthenticationProviderEntity> authProviderEntities = new ArrayList<AuthenticationProviderEntity>();
+            for (AuthenticationProviderModel authProvider : realmModel.getAuthenticationProviders()) {
+                AuthenticationProviderEntity authProviderEntity = new AuthenticationProviderEntity();
+                this.propertiesManager.setBasicPropertiesFromModel(authProvider, authProviderEntity);
+                authProviderEntities.add(authProviderEntity);
+
+            }
+            entity.setAuthenticationProviders(authProviderEntities);
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+        logger.infof("Realms exported: " + result);
+    }
+
+    protected void exportApplications(KeycloakSession keycloakSession, String fileName) {
+        List<ApplicationModel> allApplications = getAllApplications(keycloakSession);
+
+        List<ApplicationEntity> result = new LinkedList<ApplicationEntity>();
+        for (ApplicationModel appModel : allApplications) {
+            ApplicationEntity appEntity = new ApplicationEntity();
+            appEntity.setId(appModel.getId());
+            result.add(appEntity);
+
+            this.propertiesManager.setBasicPropertiesFromModel(appModel, appEntity);
+
+            // Export 'advanced' properties of application
+            appEntity.setRealmId(appModel.getRealm().getId());
+            appEntity.setDefaultRoles(appModel.getDefaultRoles());
+
+            List<String> scopeIds = getScopeIds(appModel);
+            appEntity.setScopeIds(scopeIds);
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+        logger.infof("Applications exported: " + result);
+    }
+
+    protected void exportOAuthClients(KeycloakSession keycloakSession, String fileName) {
+        List<RealmModel> realms = keycloakSession.getRealms();
+        List<OAuthClientModel> allClients = new ArrayList<OAuthClientModel>();
+        for (RealmModel realmModel : realms) {
+            allClients.addAll(realmModel.getOAuthClients());
+        }
+
+        List<OAuthClientEntity> result = new LinkedList<OAuthClientEntity>();
+        for (OAuthClientModel clientModel : allClients) {
+            OAuthClientEntity clientEntity = new OAuthClientEntity();
+            clientEntity.setId(clientModel.getId());
+            result.add(clientEntity);
+
+            this.propertiesManager.setBasicPropertiesFromModel(clientModel, clientEntity);
+
+            // Export 'advanced' properties of client
+            clientEntity.setName(clientModel.getClientId());
+            clientEntity.setRealmId(clientModel.getRealm().getId());
+
+            List<String> scopeIds = getScopeIds(clientModel);
+            clientEntity.setScopeIds(scopeIds);
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+        logger.infof("OAuth clients exported: " + result);
+    }
+
+    protected void exportRoles(KeycloakSession keycloakSession, String fileName) {
+        List<RoleModel> allRoles = getAllRoles(keycloakSession);
+
+        List<RoleEntity> result = new LinkedList<RoleEntity>();
+        for (RoleModel roleModel : allRoles) {
+            RoleEntity roleEntity = new RoleEntity();
+            roleEntity.setId(roleModel.getId());
+            result.add(roleEntity);
+
+            roleEntity.setName(roleModel.getName());
+            roleEntity.setDescription(roleModel.getDescription());
+
+            RoleContainerModel roleContainer = roleModel.getContainer();
+            if (roleContainer instanceof RealmModel) {
+                RealmModel realm = (RealmModel)roleContainer;
+                roleEntity.setRealmId(realm.getId());
+            } else {
+                ApplicationModel appModel = (ApplicationModel)roleContainer;
+                roleEntity.setApplicationId(appModel.getId());
+            }
+
+            List<String> compositeRolesIds = null;
+            for (RoleModel composite : roleModel.getComposites()) {
+
+                // Lazy init
+                if (compositeRolesIds == null) {
+                    compositeRolesIds = new ArrayList<String>();
+                }
+
+                compositeRolesIds.add(composite.getId());
+            }
+            roleEntity.setCompositeRoleIds(compositeRolesIds);
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+
+        logger.infof("%d roles exported: ", result.size());
+        if (logger.isDebugEnabled()) {
+            logger.debug("Exported roles: " + result);
+        }
+    }
+
+    protected void exportUsers(KeycloakSession keycloakSession, String fileName) {
+        List<RealmModel> realms = keycloakSession.getRealms();
+        List<UserEntity> result = new LinkedList<UserEntity>();
+
+        for (RealmModel realm : realms) {
+            List<UserModel> userModels = realm.getUsers();
+            for (UserModel userModel : userModels) {
+                UserEntity userEntity = new UserEntity();
+                userEntity.setId(userModel.getId());
+                result.add(userEntity);
+
+                this.propertiesManager.setBasicPropertiesFromModel(userModel, userEntity);
+
+                userEntity.setLoginName(userModel.getLoginName());
+                userEntity.setRealmId(realm.getId());
+
+                // authentication links
+                AuthenticationLinkModel authLink = realm.getAuthenticationLink(userModel);
+                if (authLink != null) {
+                    AuthenticationLinkEntity authLinkEntity = new AuthenticationLinkEntity();
+                    this.propertiesManager.setBasicPropertiesFromModel(authLink, authLinkEntity);
+
+                    userEntity.setAuthenticationLink(authLinkEntity);
+                }
+
+                // social links
+                Set<SocialLinkModel> socialLinks = realm.getSocialLinks(userModel);
+                if (socialLinks != null && !socialLinks.isEmpty()) {
+                    List<SocialLinkEntity> socialLinkEntities = new ArrayList<SocialLinkEntity>();
+                    for (SocialLinkModel socialLink : socialLinks) {
+                        SocialLinkEntity socialLinkEntity = new SocialLinkEntity();
+                        this.propertiesManager.setBasicPropertiesFromModel(socialLink, socialLinkEntity);
+
+                        socialLinkEntities.add(socialLinkEntity);
+                    }
+
+                    userEntity.setSocialLinks(socialLinkEntities);
+                }
+
+                // required actions
+                Set<UserModel.RequiredAction> requiredActions = userModel.getRequiredActions();
+                if (requiredActions != null && !requiredActions.isEmpty()) {
+                    userEntity.setRequiredActions(new ArrayList<UserModel.RequiredAction>(requiredActions));
+                }
+
+                // attributes
+                userEntity.setAttributes(userModel.getAttributes());
+
+                // roleIds
+                Set<RoleModel> roles = realm.getRoleMappings(userModel);
+                List<String> roleIds = new ArrayList<String>();
+                for (RoleModel role : roles) {
+                    roleIds.add(role.getId());
+                }
+                userEntity.setRoleIds(roleIds);
+
+                // credentials
+                List<UserCredentialValueModel> credentials = realm.getCredentialsDirectly(userModel);
+                List<CredentialEntity> credEntities = new ArrayList<CredentialEntity>();
+                for (UserCredentialValueModel credModel : credentials) {
+                    CredentialEntity credEntity = new CredentialEntity();
+                    this.propertiesManager.setBasicPropertiesFromModel(credModel, credEntity);
+                    credEntities.add(credEntity);
+                }
+
+                userEntity.setCredentials(credEntities);
+            }
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+
+        logger.infof("%d users exported: ", result.size());
+        if (logger.isDebugEnabled()) {
+            logger.debug("Exported users: " + result);
+        }
+    }
+
+
+     // Does it makes sense to export user failures ?
+    protected void exportUserFailures(KeycloakSession keycloakSession, String fileName) {
+        List<RealmModel> realms = keycloakSession.getRealms();
+        List<UsernameLoginFailureModel> allFailures = new ArrayList<UsernameLoginFailureModel>();
+        for (RealmModel realmModel : realms) {
+            allFailures.addAll(realmModel.getAllUserLoginFailures());
+        }
+
+        List<UsernameLoginFailureEntity> result = new LinkedList<UsernameLoginFailureEntity>();
+        for (UsernameLoginFailureModel failureModel : allFailures) {
+            UsernameLoginFailureEntity failureEntity = new UsernameLoginFailureEntity();
+            this.propertiesManager.setBasicPropertiesFromModel(failureModel, failureEntity);
+            result.add(failureEntity);
+
+            failureEntity.setUsername(failureModel.getUsername());
+            failureEntity.setNumFailures(failureModel.getNumFailures());
+        }
+
+        this.exportWriter.writeEntities(fileName, result);
+    }
+
+    private List<String> getScopeIds(ClientModel clientModel) {
+        Set<RoleModel> allScopes = clientModel.getRealm().getScopeMappings(clientModel);
+        List<String> scopeIds = new ArrayList<String>();
+        for (RoleModel role : allScopes) {
+            scopeIds.add(role.getId());
+        }
+        return scopeIds;
+    }
+
+    private List<ApplicationModel> getAllApplications(KeycloakSession keycloakSession) {
+        List<RealmModel> realms = keycloakSession.getRealms();
+        List<ApplicationModel> allApplications = new ArrayList<ApplicationModel>();
+        for (RealmModel realmModel : realms) {
+            allApplications.addAll(realmModel.getApplications());
+        }
+        return allApplications;
+    }
+
+    private List<RoleModel> getAllRoles(KeycloakSession keycloakSession) {
+        List<RoleModel> allRoles = new ArrayList<RoleModel>();
+
+        List<RealmModel> realms = keycloakSession.getRealms();
+        for (RealmModel realmModel : realms) {
+            allRoles.addAll(realmModel.getRoles());
+        }
+
+        List<ApplicationModel> allApplications = getAllApplications(keycloakSession);
+        for (ApplicationModel appModel : allApplications) {
+            allRoles.addAll(appModel.getRoles());
+        }
+
+        return allRoles;
+    }
+
+}
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
new file mode 100644
index 0000000..b751d73
--- /dev/null
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
@@ -0,0 +1,329 @@
+package org.keycloak.exportimport;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.io.ImportReader;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.AuthenticationProviderModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.entities.ApplicationEntity;
+import org.keycloak.models.entities.AuthenticationLinkEntity;
+import org.keycloak.models.entities.AuthenticationProviderEntity;
+import org.keycloak.models.entities.ClientEntity;
+import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.OAuthClientEntity;
+import org.keycloak.models.entities.RealmEntity;
+import org.keycloak.models.entities.RequiredCredentialEntity;
+import org.keycloak.models.entities.RoleEntity;
+import org.keycloak.models.entities.SocialLinkEntity;
+import org.keycloak.models.entities.UserEntity;
+import org.keycloak.models.entities.UsernameLoginFailureEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ModelImporter {
+
+    private static final Logger logger = Logger.getLogger(ModelImporter.class);
+
+    private ImportReader importReader;
+    private ExportImportPropertiesManager propertiesManager;
+
+    public void importModel(KeycloakSession keycloakSession, ImportReader importReader) {
+        // Initialize needed objects
+        this.importReader = importReader;
+        this.propertiesManager = new ExportImportPropertiesManager();
+
+        // Delete all the data from current model
+        keycloakSession.removeAllData();
+
+        importRealms(keycloakSession, "realms.json");
+        importApplications(keycloakSession, "applications.json");
+        importRoles(keycloakSession, "roles.json");
+
+        // Now we have all realms,applications and roles filled. So fill other objects (default roles, scopes etc)
+        importRealmsStep2(keycloakSession, "realms.json");
+        importApplicationsStep2(keycloakSession, "applications.json");
+
+        importOAuthClients(keycloakSession, "oauthClients.json");
+        importUsers(keycloakSession, "users.json");
+        importUserFailures(keycloakSession, "userFailures.json");
+
+        this.importReader.closeImportReader();
+    }
+
+    protected void importRealms(KeycloakSession keycloakSession, String fileName) {
+        List<RealmEntity> realms =  this.importReader.readEntities(fileName, RealmEntity.class);
+
+        for (RealmEntity realmEntity : realms) {
+            RealmModel realm = keycloakSession.createRealm(realmEntity.getId(), realmEntity.getName());
+
+            this.propertiesManager.setBasicPropertiesToModel(realm, realmEntity);
+
+            Set<String> reqCredModels = new HashSet<String>();
+            for (RequiredCredentialEntity requiredCredEntity : realmEntity.getRequiredCredentials()) {
+                reqCredModels.add(requiredCredEntity.getType());
+            }
+            realm.updateRequiredCredentials(reqCredModels);
+
+            // AdminApp and defaultRoles are set in step2
+
+            // password policy
+            realm.setPasswordPolicy(new PasswordPolicy(realmEntity.getPasswordPolicy()));
+
+            // authentication providers
+            List<AuthenticationProviderModel> authProviderModels = new ArrayList<AuthenticationProviderModel>();
+            for (AuthenticationProviderEntity authProviderEntity : realmEntity.getAuthenticationProviders()) {
+                AuthenticationProviderModel authProvider = new AuthenticationProviderModel();
+                this.propertiesManager.setBasicPropertiesToModel(authProvider, authProviderEntity);
+                authProviderModels.add(authProvider);
+
+            }
+            realm.setAuthenticationProviders(authProviderModels);
+        }
+
+        logger.infof("Realms imported: " + realms);
+    }
+
+    protected void importApplications(KeycloakSession keycloakSession, String fileName) {
+        List<ApplicationEntity> apps =  this.importReader.readEntities(fileName, ApplicationEntity.class);
+        for (ApplicationEntity appEntity : apps) {
+            RealmModel realm = keycloakSession.getRealm(appEntity.getRealmId());
+            ApplicationModel app = realm.addApplication(appEntity.getId(), appEntity.getName());
+
+            this.propertiesManager.setBasicPropertiesToModel(app , appEntity);
+
+            // scopeIds and default roles will be done in step2
+        }
+
+        logger.infof("Applications imported: " + apps);
+    }
+
+    protected void importRoles(KeycloakSession keycloakSession, String fileName) {
+        // helper map for composite roles
+        Map<String, RoleEntity> rolesMap = new HashMap<String, RoleEntity>();
+
+        List<RoleEntity> roles =  this.importReader.readEntities(fileName, RoleEntity.class);
+        for (RoleEntity roleEntity : roles) {
+            RoleModel role = null;
+            if (roleEntity.getRealmId() != null) {
+                RealmModel realm = keycloakSession.getRealm(roleEntity.getRealmId());
+                role = realm.addRole(roleEntity.getId(), roleEntity.getName());
+            } else if (roleEntity.getApplicationId() != null) {
+                ApplicationModel app = findApplicationById(keycloakSession, roleEntity.getApplicationId());
+                role = app.addRole(roleEntity.getId(), roleEntity.getName());
+            } else {
+                throw new IllegalStateException("Role " + roleEntity.getId() + " doesn't have realmId nor applicationId");
+            }
+
+            role.setDescription(roleEntity.getDescription());
+
+            rolesMap.put(roleEntity.getId(), roleEntity);
+        }
+
+        // All roles were added. Fill composite roles now
+        for (RealmModel realm : keycloakSession.getRealms()) {
+
+            // realm roles
+            fillCompositeRoles(rolesMap, realm, realm);
+
+            // app roles
+            for (ApplicationModel app : realm.getApplications()) {
+                fillCompositeRoles(rolesMap, app, realm);
+            }
+        }
+
+        logger.infof("%d roles imported: ", roles);
+        if (logger.isDebugEnabled()) {
+            logger.debug("Imported roles: " + roles);
+        }
+    }
+
+    private void fillCompositeRoles(Map<String, RoleEntity> rolesMap, RoleContainerModel roleContainer, RealmModel realm) {
+        for (RoleModel role : roleContainer.getRoles()) {
+            RoleEntity roleEntity = rolesMap.get(role.getId());
+
+            if (roleEntity.getCompositeRoleIds() == null) {
+                continue;
+            }
+
+            for (String compositeRoleId : roleEntity.getCompositeRoleIds()) {
+                RoleModel compositeRole = realm.getRoleById(compositeRoleId);
+                role.addCompositeRole(compositeRole);
+            }
+        }
+    }
+
+    protected void importRealmsStep2(KeycloakSession keycloakSession, String fileName) {
+        List<RealmEntity> realms =  this.importReader.readEntities(fileName, RealmEntity.class);
+        RealmModel adminRealm = keycloakSession.getRealm(Config.getAdminRealm());
+
+        for (RealmEntity realmEntity : realms) {
+            RealmModel realm = keycloakSession.getRealm(realmEntity.getId());
+
+            // admin app
+            String adminAppId = realmEntity.getAdminAppId();
+            if (adminAppId != null) {
+                realm.setAdminApp(adminRealm.getApplicationById(adminAppId));
+            }
+
+            // Default roles
+            realm.updateDefaultRoles(realmEntity.getDefaultRoles().toArray(new String[] {}));
+        }
+    }
+
+    protected void importApplicationsStep2(KeycloakSession keycloakSession, String fileName) {
+        List<ApplicationEntity> apps =  this.importReader.readEntities(fileName, ApplicationEntity.class);
+        for (ApplicationEntity appEntity : apps) {
+            RealmModel realm = keycloakSession.getRealm(appEntity.getRealmId());
+            ApplicationModel application = realm.getApplicationById(appEntity.getId());
+
+            // Default roles
+            application.updateDefaultRoles(appEntity.getDefaultRoles().toArray(new String[] {}));
+
+            // Scopes
+            addScopes(realm, application, appEntity);
+        }
+    }
+
+    private void addScopes(RealmModel realm, ClientModel client, ClientEntity clientEntity) {
+        for (String scopeId : clientEntity.getScopeIds()) {
+            RoleModel scope = realm.getRoleById(scopeId);
+            realm.addScopeMapping(client, scope);
+        }
+    }
+
+    protected void importOAuthClients(KeycloakSession keycloakSession, String fileName) {
+        List<OAuthClientEntity> clients =  this.importReader.readEntities(fileName, OAuthClientEntity.class);
+        for (OAuthClientEntity clientEntity : clients) {
+            RealmModel realm = keycloakSession.getRealm(clientEntity.getRealmId());
+            OAuthClientModel client = realm.addOAuthClient(clientEntity.getId(), clientEntity.getName());
+
+            this.propertiesManager.setBasicPropertiesToModel(client, clientEntity);
+
+            client.setClientId(clientEntity.getName());
+
+            // Scopes. All roles are already added at this point
+            addScopes(realm, client, clientEntity);
+        }
+
+        logger.infof("OAuth clients imported: " + clients);
+    }
+
+    protected ApplicationModel findApplicationById(KeycloakSession keycloakSession, String applicationId) {
+        for (RealmModel realm : keycloakSession.getRealms()) {
+            ApplicationModel appModel = realm.getApplicationById(applicationId);
+            if (appModel != null) {
+                return appModel;
+            }
+        }
+
+        return null;
+    }
+
+    public void importUsers(KeycloakSession keycloakSession, String fileName) {
+        List<UserEntity> users = this.importReader.readEntities(fileName, UserEntity.class);
+        for (UserEntity userEntity : users) {
+            RealmModel realm = keycloakSession.getRealm(userEntity.getRealmId());
+            UserModel user = realm.addUser(userEntity.getId(), userEntity.getLoginName());
+
+            // We need to remove defaultRoles here as realm.addUser is automatically adding them. We may add them later during roles mapping processing
+            for (RoleModel role : realm.getRoleMappings(user)) {
+                realm.deleteRoleMapping(user, role);
+            }
+
+            this.propertiesManager.setBasicPropertiesToModel(user, userEntity);
+
+            // authentication links
+            AuthenticationLinkEntity authLinkEntity = userEntity.getAuthenticationLink();
+            if (authLinkEntity != null) {
+                AuthenticationLinkModel authLinkModel = new AuthenticationLinkModel();
+                this.propertiesManager.setBasicPropertiesToModel(authLinkModel, authLinkEntity);
+
+                realm.setAuthenticationLink(user, authLinkModel);
+            }
+
+            // social links
+            List<SocialLinkEntity> socialLinks = userEntity.getSocialLinks();
+            if (socialLinks != null && !socialLinks.isEmpty()) {
+                for (SocialLinkEntity socialLinkEntity : socialLinks) {
+                    SocialLinkModel socialLink = new SocialLinkModel();
+                    this.propertiesManager.setBasicPropertiesToModel(socialLink, socialLinkEntity);
+
+                    realm.addSocialLink(user, socialLink);
+                }
+            }
+
+            // required actions
+            List<UserModel.RequiredAction> requiredActions = userEntity.getRequiredActions();
+            if (requiredActions != null && !requiredActions.isEmpty()) {
+                for (UserModel.RequiredAction reqAction : requiredActions) {
+                    user.addRequiredAction(reqAction);
+                }
+            }
+
+            // attributes
+            if (userEntity.getAttributes() != null) {
+                for (Map.Entry<String, String> attr : userEntity.getAttributes().entrySet()) {
+                    user.setAttribute(attr.getKey(), attr.getValue());
+                }
+            }
+
+            // roles
+            if (userEntity.getRoleIds() != null) {
+                for (String roleId : userEntity.getRoleIds()) {
+                    RoleModel role = realm.getRoleById(roleId);
+                    realm.grantRole(user, role);
+                }
+            }
+
+            // credentials
+            List<CredentialEntity> credentials = userEntity.getCredentials();
+            if (credentials != null) {
+                for (CredentialEntity credEntity : credentials) {
+                    UserCredentialValueModel credModel = new UserCredentialValueModel();
+                    this.propertiesManager.setBasicPropertiesToModel(credModel, credEntity);
+
+                    realm.updateCredentialDirectly(user, credModel);
+                }
+            }
+        }
+
+        logger.infof("%d users imported: ", users.size());
+        if (logger.isDebugEnabled()) {
+            logger.debug("Imported users: " + users);
+        }
+    }
+
+    public void importUserFailures(KeycloakSession keycloakSession, String fileName) {
+        List<UsernameLoginFailureEntity> userFailures = this.importReader.readEntities(fileName, UsernameLoginFailureEntity.class);
+        for (UsernameLoginFailureEntity entity : userFailures) {
+            RealmModel realm = keycloakSession.getRealm(entity.getRealmId());
+            UsernameLoginFailureModel model = realm.addUserLoginFailure(entity.getUsername());
+
+            this.propertiesManager.setBasicPropertiesToModel(model , entity);
+
+            for (int i=0 ; i<entity.getNumFailures() ; i++) {
+                model.incrementFailures();
+            }
+        }
+    }
+}
diff --git a/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportImportProvider b/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportImportProvider
new file mode 100644
index 0000000..353987f
--- /dev/null
+++ b/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportImportProvider
@@ -0,0 +1 @@
+org.keycloak.exportimport.ExportImportProviderImpl
diff --git a/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.io.ExportImportIOProvider b/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.io.ExportImportIOProvider
new file mode 100644
index 0000000..75c97ec
--- /dev/null
+++ b/export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.io.ExportImportIOProvider
@@ -0,0 +1,2 @@
+org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider
+org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
new file mode 100644
index 0000000..1e39f24
--- /dev/null
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java
@@ -0,0 +1,110 @@
+package org.keycloak.exportimport;
+
+import java.util.Iterator;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.model.test.AbstractModelTest;
+import org.keycloak.model.test.ImportTest;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.ApplianceBootstrap;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.keycloak.util.ProviderLoader;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class ExportImportTestBase {
+
+    protected KeycloakSessionFactory factory;
+
+    protected KeycloakSession identitySession;
+    protected RealmManager realmManager;
+
+    @Test
+    public void testExportImport() throws Exception {
+        // Init JPA model
+        Config.setModelProvider(getExportModelProvider());
+        factory = KeycloakApplication.createSessionFactory();
+
+        // Bootstrap admin realm
+        beginTransaction();
+        new ApplianceBootstrap().bootstrap(identitySession, "/auth");
+        commitTransaction();
+
+        // Classic import of realm to JPA model
+        beginTransaction();
+        RealmRepresentation rep = AbstractModelTest.loadJson("testrealm.json");
+        realmManager = new RealmManager(identitySession);
+        RealmModel realm = realmManager.createRealm("demo", rep.getRealm());
+        realmManager.importRealm(rep, realm);
+
+        commitTransaction();
+
+        // Full export of realm
+        exportModel(factory);
+
+        beginTransaction();
+        realm = identitySession.getRealm("demo");
+        String wburkeId = realm.getUser("wburke").getId();
+        String appId = realm.getApplicationByName("Application").getId();
+
+        // Commit transaction and close JPA now
+        commitTransaction();
+        factory.close();
+
+        // Bootstrap mongo session and factory
+        Config.setModelProvider(getImportModelProvider());
+        factory = KeycloakApplication.createSessionFactory();
+
+        // Full import of previous export into mongo
+        importModel(factory);
+
+        // Verify it's imported in mongo (reusing ImportTest)
+        beginTransaction();
+        RealmModel importedRealm = identitySession.getRealm("demo");
+        System.out.println("Exported realm: " + realm + ", Imported realm: " + importedRealm);
+
+        Assert.assertEquals(wburkeId, importedRealm.getUser("wburke").getId());
+        Assert.assertEquals(appId, importedRealm.getApplicationByName("Application").getId());
+        ImportTest.assertDataImportedInRealm(importedRealm);
+
+        // Commit and close Mongo
+        commitTransaction();
+        factory.close();
+    }
+
+    protected abstract String getExportModelProvider();
+
+    protected abstract String getImportModelProvider();
+
+    protected abstract void exportModel(KeycloakSessionFactory factory);
+
+    protected abstract void importModel(KeycloakSessionFactory factory);
+
+    protected void beginTransaction() {
+        identitySession = factory.createSession();
+        identitySession.getTransaction().begin();
+        realmManager = new RealmManager(identitySession);
+    }
+
+    protected void commitTransaction() {
+        identitySession.getTransaction().commit();
+        identitySession.close();
+    }
+
+    protected ExportImportProvider getExportImportProvider() {
+        Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
+
+        if (providers.hasNext()) {
+            return providers.next();
+        } else {
+            throw new IllegalStateException("ExportImportProvider not found");
+        }
+    }
+}
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
new file mode 100644
index 0000000..8175bdb
--- /dev/null
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
@@ -0,0 +1,37 @@
+package org.keycloak.exportimport;
+
+import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * Test for full export of data from JPA and import them to Mongo. Using "directory" provider
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JPAToMongoExportImportTest extends ExportImportTestBase {
+
+    @Override
+    protected String getExportModelProvider() {
+        return "jpa";
+    }
+
+    @Override
+    protected String getImportModelProvider() {
+        return "mongo";
+    }
+
+    @Override
+    protected void exportModel(KeycloakSessionFactory factory) {
+        Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
+        Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
+        getExportImportProvider().checkExportImport(factory);
+    }
+
+    @Override
+    protected void importModel(KeycloakSessionFactory factory) {
+        Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
+        Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
+        getExportImportProvider().checkExportImport(factory);
+    }
+}
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
new file mode 100644
index 0000000..e715c9c
--- /dev/null
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
@@ -0,0 +1,70 @@
+package org.keycloak.exportimport;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * Test for full export of data from Mongo and import them to JPA. Using export into encrypted ZIP and import from it
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class MongoToJPAExportImportTest extends ExportImportTestBase {
+
+    private static final String zipFile = "keycloak-export.zip";
+
+    @Override
+    protected String getExportModelProvider() {
+        return "mongo";
+    }
+
+    @Override
+    protected String getImportModelProvider() {
+        return "jpa";
+    }
+
+    @Override
+    protected void exportModel(KeycloakSessionFactory factory) {
+        Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
+        Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
+        File zipFile = getZipFile();
+        Config.setExportImportZipFile(zipFile.getAbsolutePath());
+        Config.setExportImportZipPassword("password123");
+
+        if (zipFile.exists()) {
+            zipFile.delete();
+        }
+
+        new ExportImportProviderImpl().checkExportImport(factory);
+    }
+
+    @Override
+    protected void importModel(KeycloakSessionFactory factory) {
+        Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
+        Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
+        File zipFile = getZipFile();
+        Config.setExportImportZipFile(zipFile.getAbsolutePath());
+        Config.setExportImportZipPassword("password-invalid");
+
+        // Try invalid password
+        try {
+            new ExportImportProviderImpl().checkExportImport(factory);
+            Assert.fail("Not expected to be here. Exception should be thrown");
+        } catch (Exception e) {};
+
+        Config.setExportImportZipPassword("password123");
+        new ExportImportProviderImpl().checkExportImport(factory);
+
+        if (zipFile.exists()) {
+            zipFile.delete();
+        }
+    }
+
+    private File getZipFile() {
+        String tempDir = System.getProperty("java.io.tmpdir");
+        return new File(tempDir + File.separator + "keycloak-export.zip");
+    }
+}
diff --git a/export-import/pom.xml b/export-import/pom.xml
new file mode 100644
index 0000000..6df4145
--- /dev/null
+++ b/export-import/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-beta-1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>pom</packaging>
+
+    <artifactId>keycloak-export-import</artifactId>
+    <name>Keycloak Export And Import</name>
+    <description/>
+
+    <modules>
+        <module>export-import-api</module>
+        <module>export-import-impl</module>
+    </modules>
+
+</project>
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationLinkModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationLinkModel.java
index 1a4c52d..8cc0bd8 100644
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationLinkModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationLinkModel.java
@@ -7,8 +7,10 @@ package org.keycloak.models;
  */
 public class AuthenticationLinkModel {
 
-    private final String authProvider;
-    private final String authUserId;
+    private String authProvider;
+    private String authUserId;
+
+    public AuthenticationLinkModel() {};
 
     public AuthenticationLinkModel(String authProvider, String authUserId) {
         this.authProvider = authProvider;
@@ -19,7 +21,15 @@ public class AuthenticationLinkModel {
         return authUserId;
     }
 
+    public void setAuthUserId(String authUserId) {
+        this.authUserId = authUserId;
+    }
+
     public String getAuthProvider() {
         return authProvider;
     }
+
+    public void setAuthProvider(String authProvider) {
+        this.authProvider = authProvider;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationProviderModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationProviderModel.java
index 7dea3c9..8ef7abb 100644
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationProviderModel.java
@@ -14,6 +14,8 @@ public class AuthenticationProviderModel {
     private boolean passwordUpdateSupported = true;
     private Map<String, String> config;
 
+    public AuthenticationProviderModel() {};
+
     public AuthenticationProviderModel(String providerName, boolean passwordUpdateSupported, Map<String, String> config) {
         this.providerName = providerName;
         this.passwordUpdateSupported = passwordUpdateSupported;
diff --git a/model/api/src/main/java/org/keycloak/models/Config.java b/model/api/src/main/java/org/keycloak/models/Config.java
index 2655eb3..e50ed9a 100644
--- a/model/api/src/main/java/org/keycloak/models/Config.java
+++ b/model/api/src/main/java/org/keycloak/models/Config.java
@@ -33,6 +33,16 @@ public class Config {
     public static final String TIMER_PROVIDER_KEY = "keycloak.timer";
     public static final String TIMER_PROVIDER_DEFAULT = "basic";
 
+    public static final String EXPORT_IMPORT_ACTION = "keycloak.migration.action";
+    public static final String EXPORT_IMPORT_PROVIDER = "keycloak.migration.provider";
+    public static final String EXPORT_IMPORT_PROVIDER_DEFAULT = "zip";
+    // used for "directory" provider
+    public static final String EXPORT_IMPORT_DIR = "keycloak.migration.dir";
+    // used for "zip" provider
+    public static final String EXPORT_IMPORT_ZIP_FILE = "keycloak.migration.zipFile";
+    public static final String EXPORT_IMPORT_ZIP_PASSWORD = "keycloak.migration.zipPassword";
+
+
     public static String getAdminRealm() {
         return System.getProperty(ADMIN_REALM_KEY, ADMIN_REALM_DEFAULT);
     }
@@ -117,4 +127,45 @@ public class Config {
         System.setProperty(THEME_ADMIN_KEY, adminTheme);
     }
 
+    // EXPORT + IMPORT
+
+    public static String getExportImportAction() {
+        return System.getProperty(EXPORT_IMPORT_ACTION);
+    }
+
+    public static void setExportImportAction(String exportImportAction) {
+        System.setProperty(EXPORT_IMPORT_ACTION, exportImportAction);
+    }
+
+    public static String getExportImportProvider() {
+        return System.getProperty(EXPORT_IMPORT_PROVIDER, EXPORT_IMPORT_PROVIDER_DEFAULT);
+    }
+
+    public static void setExportImportProvider(String exportImportProvider) {
+        System.setProperty(EXPORT_IMPORT_PROVIDER, exportImportProvider);
+    }
+
+    public static String getExportImportDir() {
+        return System.getProperty(EXPORT_IMPORT_DIR);
+    }
+
+    public static void setExportImportDir(String exportImportDir) {
+        System.setProperty(EXPORT_IMPORT_DIR, exportImportDir);
+    }
+
+    public static String getExportImportZipFile() {
+        return System.getProperty(EXPORT_IMPORT_ZIP_FILE);
+    }
+
+    public static void setExportImportZipFile(String exportImportZipFile) {
+        System.setProperty(EXPORT_IMPORT_ZIP_FILE, exportImportZipFile);
+    }
+
+    public static String getExportImportZipPassword() {
+        return System.getProperty(EXPORT_IMPORT_ZIP_PASSWORD);
+    }
+
+    public static void setExportImportZipPassword(String exportImportZipPassword) {
+        System.setProperty(EXPORT_IMPORT_ZIP_PASSWORD, exportImportZipPassword);
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/OAuthClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/OAuthClientEntity.java
new file mode 100644
index 0000000..368fcf7
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/OAuthClientEntity.java
@@ -0,0 +1,7 @@
+package org.keycloak.models.entities;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OAuthClientEntity extends ClientEntity {
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java
new file mode 100644
index 0000000..a961c70
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/RoleEntity.java
@@ -0,0 +1,57 @@
+package org.keycloak.models.entities;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class RoleEntity extends AbstractIdentifiableEntity {
+
+    private String name;
+    private String description;
+
+    private List<String> compositeRoleIds;
+
+    private String realmId;
+    private String applicationId;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public List<String> getCompositeRoleIds() {
+        return compositeRoleIds;
+    }
+
+    public void setCompositeRoleIds(List<String> compositeRoleIds) {
+        this.compositeRoleIds = compositeRoleIds;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    public void setApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
index 00b4db9..9aa55ee 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -16,5 +16,7 @@ public interface KeycloakSession {
     List<RealmModel> getRealms();
     boolean removeRealm(String id);
 
+    void removeAllData();
+
     void close();
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 14d531e..1c73b2f 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -109,12 +109,18 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     void updateCredential(UserModel user, UserCredentialModel cred);
 
+    List<UserCredentialValueModel> getCredentialsDirectly(UserModel user);
+
+    void updateCredentialDirectly(UserModel user, UserCredentialValueModel cred);
+
     UserModel getUser(String name);
 
     UserModel getUserByEmail(String email);
 
     UserModel getUserById(String name);
 
+    UserModel addUser(String id, String username);
+
     UserModel addUser(String username);
 
     boolean removeUser(String name);
@@ -135,6 +141,8 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     ApplicationModel addApplication(String name);
 
+    ApplicationModel addApplication(String id, String name);
+
     boolean removeApplication(String id);
 
     ApplicationModel getApplicationById(String id);
@@ -160,12 +168,13 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     void setSocial(boolean social);
 
-    public boolean isUpdateProfileOnInitialSocialLogin();
+    boolean isUpdateProfileOnInitialSocialLogin();
 
-    public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin);
+    void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin);
 
-    public UsernameLoginFailureModel getUserLoginFailure(String username);
+    UsernameLoginFailureModel getUserLoginFailure(String username);
     UsernameLoginFailureModel addUserLoginFailure(String username);
+    List<UsernameLoginFailureModel> getAllUserLoginFailures();
 
     List<UserModel> getUsers();
 
@@ -175,6 +184,8 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     OAuthClientModel addOAuthClient(String name);
 
+    OAuthClientModel addOAuthClient(String id, String name);
+
     OAuthClientModel getOAuthClient(String name);
     OAuthClientModel getOAuthClientById(String id);
     boolean removeOAuthClient(String id);
diff --git a/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java b/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
index 62ecfdb..2cad371 100755
--- a/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
@@ -12,6 +12,8 @@ public interface RoleContainerModel {
 
     RoleModel addRole(String name);
 
+    RoleModel addRole(String id, String name);
+
     boolean removeRole(RoleModel role);
 
     Set<RoleModel> getRoles();
diff --git a/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java b/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java
index 76e8929..802fa9e 100755
--- a/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java
+++ b/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java
@@ -9,6 +9,8 @@ public class SocialLinkModel {
     private String socialProvider;
     private String socialUsername;
 
+    public SocialLinkModel() {};
+
     public SocialLinkModel(String socialProvider, String socialUserId, String socialUsername) {
         this.socialUserId = socialUserId;
         this.socialProvider = socialProvider;
diff --git a/model/api/src/main/java/org/keycloak/models/UserCredentialValueModel.java b/model/api/src/main/java/org/keycloak/models/UserCredentialValueModel.java
new file mode 100644
index 0000000..3702274
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/UserCredentialValueModel.java
@@ -0,0 +1,46 @@
+package org.keycloak.models;
+
+/**
+ * Used just in cases when we want to "directly" update or retrieve the hash or salt of user credential (For example during export/import)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserCredentialValueModel {
+
+    private String type;
+    private String value;
+    private String device;
+    private byte[] salt;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getDevice() {
+        return device;
+    }
+
+    public void setDevice(String device) {
+        this.device = device;
+    }
+
+    public byte[] getSalt() {
+        return salt;
+    }
+
+    public void setSalt(byte[] salt) {
+        this.salt = salt;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java
new file mode 100644
index 0000000..51e2a3a
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java
@@ -0,0 +1,23 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on its annotations
+ *
+ * @see PropertyCriteria
+ */
+public class AnnotatedPropertyCriteria implements PropertyCriteria {
+    private final Class<? extends Annotation> annotationClass;
+
+    public AnnotatedPropertyCriteria(Class<? extends Annotation> annotationClass) {
+        this.annotationClass = annotationClass;
+    }
+
+    @Override
+    public boolean methodMatches(Method m) {
+        return m.isAnnotationPresent(annotationClass);
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java
new file mode 100644
index 0000000..868fdba
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java
@@ -0,0 +1,8 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.Method;
+
+public interface MethodProperty<V> extends Property<V> {
+
+    Method getAnnotatedElement();
+}
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
new file mode 100644
index 0000000..16cc165
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
@@ -0,0 +1,220 @@
+package org.keycloak.models.utils.reflection;
+
+import java.beans.Introspector;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+/**
+ * A bean property based on the value represented by a getter/setter method pair
+ */
+class MethodPropertyImpl<V> implements MethodProperty<V> {
+    private static final String GETTER_METHOD_PREFIX = "get";
+    private static final String SETTER_METHOD_PREFIX = "set";
+    private static final String BOOLEAN_GETTER_METHOD_PREFIX = "is";
+
+    private static final int GETTER_METHOD_PREFIX_LENGTH = GETTER_METHOD_PREFIX.length();
+    private static final int SETTER_METHOD_PREFIX_LENGTH = SETTER_METHOD_PREFIX.length();
+    private static final int BOOLEAN_GETTER_METHOD_PREFIX_LENGTH = BOOLEAN_GETTER_METHOD_PREFIX.length();
+
+    private final Method getterMethod;
+    private final String propertyName;
+    private final Method setterMethod;
+
+    public MethodPropertyImpl(Method method) {
+        final String accessorMethodPrefix;
+        final String propertyNameInAccessorMethod;
+
+        if (method.getName().startsWith(GETTER_METHOD_PREFIX)) {
+            if (method.getReturnType() == Void.TYPE) {
+                throw new IllegalArgumentException(
+                        "Invalid accessor method, must have return value if starts with 'get'. Method: " + method);
+            } else if (method.getParameterTypes().length > 0) {
+                throw new IllegalArgumentException(
+                        "Invalid accessor method, must have zero arguments if starts with 'get'. Method: " + method);
+            }
+            propertyNameInAccessorMethod = method.getName().substring(GETTER_METHOD_PREFIX_LENGTH);
+            accessorMethodPrefix = GETTER_METHOD_PREFIX;
+        } else if (method.getName().startsWith(SETTER_METHOD_PREFIX)) {
+            if (method.getReturnType() != Void.TYPE) {
+                throw new IllegalArgumentException(
+                        "Invalid accessor method, must not have return value if starts with 'set'. Method: " + method);
+            } else if (method.getParameterTypes().length != 1) {
+                throw new IllegalArgumentException(
+                        "Invalid accessor method, must have one argument if starts with 'set'. Method: " + method);
+            }
+            propertyNameInAccessorMethod = method.getName().substring(SETTER_METHOD_PREFIX_LENGTH);
+            accessorMethodPrefix = SETTER_METHOD_PREFIX;
+        } else if (method.getName().startsWith(BOOLEAN_GETTER_METHOD_PREFIX)) {
+            if (method.getReturnType() != Boolean.TYPE || !method.getReturnType().isPrimitive()) {
+                throw new IllegalArgumentException(
+                        "Invalid accessor method, must return boolean primitive if starts with 'is'. Method: " +
+                                method);
+            }
+            propertyNameInAccessorMethod = method.getName().substring(BOOLEAN_GETTER_METHOD_PREFIX_LENGTH);
+            accessorMethodPrefix = BOOLEAN_GETTER_METHOD_PREFIX;
+        } else {
+            throw new IllegalArgumentException(
+                    "Invalid accessor method, must start with 'get', 'set' or 'is'.  " + "Method: " + method);
+        }
+
+        if (propertyNameInAccessorMethod.length() == 0 ||
+                !Character.isUpperCase(propertyNameInAccessorMethod.charAt(0))) {
+            throw new IllegalArgumentException("Invalid accessor method, prefix '" + accessorMethodPrefix +
+                    "' must be followed a non-empty property name, capitalized. Method: " + method);
+        }
+
+        this.propertyName = Introspector.decapitalize(propertyNameInAccessorMethod);
+        this.getterMethod = getGetterMethod(method.getDeclaringClass(), propertyName);
+        this.setterMethod = getSetterMethod(method.getDeclaringClass(), propertyName);
+    }
+
+    @Override
+    public String getName() {
+        return propertyName;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Class<V> getJavaClass() {
+        return (Class<V>) getterMethod.getReturnType();
+    }
+
+    @Override
+    public Type getBaseType() {
+        return getterMethod.getGenericReturnType();
+    }
+
+    @Override
+    public Method getAnnotatedElement() {
+        return getterMethod;
+    }
+
+    @Override
+    public Member getMember() {
+        return getterMethod;
+    }
+
+    @Override
+    public V getValue(Object instance) {
+        if (getterMethod == null) {
+            throw new UnsupportedOperationException("Property " +
+                    this.setterMethod.getDeclaringClass() + "." + propertyName +
+                    " cannot be read, as there is no getter method.");
+        }
+        return Reflections.cast(Reflections.invokeMethod(getterMethod, instance));
+    }
+
+    @Override
+    public void setValue(Object instance, V value) {
+        if (setterMethod == null) {
+            // if the setter method is null may be because the declaring type is an interface which does not declare
+            // a setter method. We just check if the instance is assignable from the property declaring class and
+            // try to find a overridden method.
+            if (getDeclaringClass().isAssignableFrom(instance.getClass())) {
+                Method instanceSetterMethod = getSetterMethod(instance.getClass(), getName());
+
+                if (instanceSetterMethod != null) {
+                    Reflections.invokeMethod(instanceSetterMethod, instance, value);
+                    return;
+                }
+            }
+
+            throw new UnsupportedOperationException("Property " +
+                    this.getterMethod.getDeclaringClass() + "." + propertyName +
+                    " is read only, as there is no setter method.");
+        }
+        Reflections.invokeMethod(setterMethod, instance, value);
+    }
+
+    private static Method getSetterMethod(Class<?> clazz, String name) {
+        Method[] methods = clazz.getMethods();
+        for (Method method : methods) {
+            String methodName = method.getName();
+            if (methodName.startsWith(SETTER_METHOD_PREFIX) && method.getParameterTypes().length == 1) {
+                if (Introspector.decapitalize(methodName.substring(SETTER_METHOD_PREFIX_LENGTH)).equals(name)) {
+                    return method;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Method getGetterMethod(Class<?> clazz, String name) {
+        for (Method method : clazz.getDeclaredMethods()) {
+            String methodName = method.getName();
+            if (method.getParameterTypes().length == 0) {
+                if (methodName.startsWith(GETTER_METHOD_PREFIX)) {
+                    if (Introspector.decapitalize(methodName.substring(GETTER_METHOD_PREFIX_LENGTH)).equals(name)) {
+                        return method;
+                    }
+                } else if (methodName.startsWith(BOOLEAN_GETTER_METHOD_PREFIX)) {
+                    if (Introspector.decapitalize(
+                            methodName.substring(BOOLEAN_GETTER_METHOD_PREFIX_LENGTH)).equals(name)) {
+                        return method;
+                    }
+                }
+            }
+        }
+        throw new IllegalArgumentException("no such getter method: " + clazz.getName() + '.' + name);
+    }
+
+    @Override
+    public Class<?> getDeclaringClass() {
+        return getterMethod.getDeclaringClass();
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return setterMethod == null;
+    }
+
+    @Override
+    public void setAccessible() {
+        if (setterMethod != null) {
+            Reflections.setAccessible(setterMethod);
+        }
+        if (getterMethod != null) {
+            Reflections.setAccessible(getterMethod);
+        }
+    }
+
+    @Override
+    public boolean isAnnotationPresent(final Class<? extends Annotation> annotation) {
+        return getAnnotatedElement() != null && getAnnotatedElement().isAnnotationPresent(annotation);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        if (isReadOnly()) {
+            builder.append("read-only ").append(setterMethod.toString()).append("; ");
+        }
+        builder.append(getterMethod.toString());
+        return builder.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 1;
+        hash = hash * 31 + (setterMethod == null ? 0 : setterMethod.hashCode());
+        hash = hash * 31 + getterMethod.hashCode();
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof MethodPropertyImpl<?>) {
+            MethodPropertyImpl<?> that = (MethodPropertyImpl<?>) obj;
+            if (this.setterMethod == null) {
+                return that.setterMethod == null && this.getterMethod.equals(that.getterMethod);
+            } else {
+                return this.setterMethod.equals(that.setterMethod) && this.getterMethod.equals(that.getterMethod);
+            }
+        } else {
+            return false;
+        }
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/Properties.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/Properties.java
new file mode 100644
index 0000000..3348d8b
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/Properties.java
@@ -0,0 +1,44 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+ * Utility class for working with JavaBean style properties
+ *
+ * @see Property
+ */
+public class Properties {
+
+    private Properties() {
+    }
+
+    /**
+     * Create a JavaBean style property from the specified method
+     *
+     * @param <V>
+     * @param method
+     *
+     * @return
+     *
+     * @throws IllegalArgumentException if the method does not match JavaBean conventions
+     * @see http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html
+     */
+    public static <V> MethodProperty<V> createProperty(Method method) {
+        return new MethodPropertyImpl<V>(method);
+    }
+
+    /**
+     * Indicates whether this method is a valid property method.
+     */
+    public static <V> boolean isProperty(Method method) {
+        try {
+            new MethodPropertyImpl<V>(method);
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+}
+
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/Property.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/Property.java
new file mode 100644
index 0000000..6cf392d
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/Property.java
@@ -0,0 +1,105 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Member;
+import java.lang.reflect.Type;
+
+/**
+ * A representation of a JavaBean style property
+ *
+ * @param <V> the type of the properties value
+ *
+ * @see Properties
+ */
+public interface Property<V> {
+
+    /**
+     * Returns the name of the property. If the property is a field, then the field name is returned. Otherwise, if the
+     * property is a method, then the name that is returned is the getter method name without the "get" or "is" prefix,
+     * and a lower case first letter.
+     *
+     * @return The name of the property
+     */
+    String getName();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Type getBaseType();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Class<V> getJavaClass();
+
+    /**
+     * Get the element responsible for retrieving the property value
+     *
+     * @return
+     */
+    AnnotatedElement getAnnotatedElement();
+
+    /**
+     * Get the member responsible for retrieving the property value
+     *
+     * @return
+     */
+    Member getMember();
+
+    /**
+     * Returns the property value for the specified bean. The property to be returned is either a field or getter
+     * method.
+     *
+     * @param bean The bean to read the property from
+     *
+     * @return The property value
+     *
+     * @throws ClassCastException if the value is not of the type V
+     */
+    V getValue(Object instance);
+
+    /**
+     * This method sets the property value for a specified bean to the specified value. The property to be set is either
+     * a field or setter method.
+     *
+     * @param bean The bean containing the property to set
+     * @param value The new property value
+     */
+    void setValue(Object instance, V value);
+
+    /**
+     * Returns the class that declares the property
+     *
+     * @return
+     */
+    Class<?> getDeclaringClass();
+
+    /**
+     * Indicates whether this is a read-only property
+     *
+     * @return
+     */
+    boolean isReadOnly();
+
+    /**
+     * Calls the setAccessible method on the underlying member(s).
+     * <p/>
+     * The operation should be performed within a {@link PrivilegedAction}
+     */
+    void setAccessible();
+
+    /**
+     * Indicates whether the given <code>annotation</code> is defined for this property. This method will consider
+     * the annotations present in both field and accessor method.
+     *
+     * @param annotation The Annotation to check.
+     *
+     * @return True if the annotation is defined. Otherwise is false.
+     */
+    boolean isAnnotationPresent(Class<? extends Annotation> annotation);
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java
new file mode 100644
index 0000000..2d2c41d
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java
@@ -0,0 +1,27 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * <p> A property criteria can be used to filter the properties found by a {@link PropertyQuery} </p> <p/> <p>
+ * DeltaSpike provides a number of property queries ( {@link TypedPropertyCriteria}, {@link NamedPropertyCriteria} and
+ * {@link AnnotatedPropertyCriteria}), or you can create a custom query by implementing this interface. </p>
+ *
+ * @see PropertyQuery#addCriteria(PropertyCriteria)
+ * @see PropertyQueries
+ * @see TypedPropertyCriteria
+ * @see AnnotatedPropertyCriteria
+ * @see NamedPropertyCriteria
+ */
+public interface PropertyCriteria {
+
+    /**
+     * Tests whether the specified method matches the criteria
+     *
+     * @param m
+     *
+     * @return true if the method matches
+     */
+    boolean methodMatches(Method m);
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java
new file mode 100644
index 0000000..d8cc8d0
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java
@@ -0,0 +1,25 @@
+package org.keycloak.models.utils.reflection;
+
+/**
+ * Utilities for working with property queries
+ *
+ * @see PropertyQuery
+ */
+public class PropertyQueries {
+
+    private PropertyQueries() {
+    }
+
+    /**
+     * Create a new {@link PropertyQuery}
+     *
+     * @param <V>
+     * @param targetClass
+     *
+     * @return
+     */
+    public static <V> PropertyQuery<V> createQuery(Class<?> targetClass) {
+        return new PropertyQuery<V>(targetClass);
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java
new file mode 100644
index 0000000..5aa3833
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java
@@ -0,0 +1,162 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p> Queries a target class for properties that match certain criteria. A property may either be a private or public
+ * field, declared by the target class or inherited from a superclass, or a public method declared by the target class
+ * or inherited from any of its superclasses. For properties that are exposed via a method, the property must be a
+ * JavaBean style property, i.e. it must provide both an accessor and mutator method according to the JavaBean
+ * specification. </p> <p/> <p> This class is not thread-safe, however the result returned by the getResultList() method
+ * is. </p>
+ *
+ * @see PropertyQueries
+ * @see PropertyCriteria
+ */
+public class PropertyQuery<V> {
+    private final Class<?> targetClass;
+    private final List<PropertyCriteria> criteria;
+
+    PropertyQuery(Class<?> targetClass) {
+        if (targetClass == null) {
+            throw new IllegalArgumentException("targetClass parameter may not be null");
+        }
+
+        this.targetClass = targetClass;
+        this.criteria = new ArrayList<PropertyCriteria>();
+    }
+
+    /**
+     * Add a criteria to query
+     *
+     * @param criteria the criteria to add
+     */
+    public PropertyQuery<V> addCriteria(PropertyCriteria criteria) {
+        this.criteria.add(criteria);
+        return this;
+    }
+
+    /**
+     * Get the first result from the query, causing the query to be run.
+     *
+     * @return the first result, or null if there are no results
+     */
+    public Property<V> getFirstResult() {
+        Map<String, Property<V>> results = getResultList();
+        return results.isEmpty() ? null : results.values().iterator().next();
+    }
+
+    /**
+     * Get the first result from the query that is not marked as read only, causing the query to be run.
+     *
+     * @return the first writable result, or null if there are no results
+     */
+    public Property<V> getFirstWritableResult() {
+        Map<String, Property<V>>  results = getWritableResultList();
+        return results.isEmpty() ? null : results.values().iterator().next();
+    }
+
+    /**
+     * Get a single result from the query, causing the query to be run. An exception is thrown if the query does not
+     * return exactly one result.
+     *
+     * @return the single result
+     *
+     * @throws RuntimeException if the query does not return exactly one result
+     */
+    public Property<V> getSingleResult() {
+        Map<String, Property<V>> results = getResultList();
+        if (results.size() == 1) {
+            return results.values().iterator().next();
+        } else if (results.isEmpty()) {
+            throw new RuntimeException(
+                    "Expected one property match, but the criteria did not match any properties on " +
+                            targetClass.getName());
+        } else {
+            throw new RuntimeException("Expected one property match, but the criteria matched " + results.size() +
+                    " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get a single result from the query that is not marked as read only, causing the query to be run. An exception is
+     * thrown if the query does not return exactly one result.
+     *
+     * @return the single writable result
+     *
+     * @throws RuntimeException if the query does not return exactly one result
+     */
+    public Property<V> getWritableSingleResult() {
+        Map<String, Property<V>> results = getWritableResultList();
+        if (results.size() == 1) {
+            return results.values().iterator().next();
+        } else if (results.isEmpty()) {
+            throw new RuntimeException(
+                    "Expected one property match, but the criteria did not match any properties on " +
+                            targetClass.getName());
+        } else {
+            throw new RuntimeException("Expected one property match, but the criteria matched " +
+                    results.size() + " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public Map<String, Property<V>> getResultList() {
+        return getResultList(false);
+    }
+
+    /**
+     * Get the non read only results from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public Map<String, Property<V>> getWritableResultList() {
+        return getResultList(true);
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @param writable if this query should only return properties that are not read only
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    private Map<String, Property<V>> getResultList(boolean writable) {
+        Map<String, Property<V>> properties = new HashMap<String, Property<V>>();
+
+        // First check public accessor methods (we ignore private methods)
+        for (Method method : targetClass.getMethods()) {
+            if (!(method.getName().startsWith("is") || method.getName().startsWith("get"))) {
+                continue;
+            }
+
+            boolean match = true;
+            for (PropertyCriteria c : criteria) {
+                if (!c.methodMatches(method)) {
+                    match = false;
+                    break;
+                }
+            }
+
+            if (match) {
+                MethodProperty<V> property = Properties.<V>createProperty(method);
+
+                if (!writable || !property.isReadOnly()) {
+                    properties.put(property.getName(), property);
+                }
+            }
+        }
+
+        return Collections.unmodifiableMap(properties);
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/Reflections.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/Reflections.java
new file mode 100644
index 0000000..e8491a4
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/Reflections.java
@@ -0,0 +1,980 @@
+package org.keycloak.models.utils.reflection;
+
+import java.beans.Introspector;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.security.AccessController;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class for working with JDK Reflection and also CDI's {link Annotated} metadata.
+ */
+public class Reflections {
+    /**
+     * An empty array of type {@link java.lang.annotation.Annotation}, useful converting lists to arrays.
+     */
+    public static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
+
+    /**
+     * An empty array of type {@link Object}, useful for converting lists to arrays.
+     */
+    public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    public static final Type[] EMPTY_TYPES = {};
+
+    public static final Class<?>[] EMPTY_CLASSES = new Class<?>[0];
+
+    private Reflections() {
+    }
+
+    /**
+     * <p> Perform a runtime cast. Similar to {@link Class#cast(Object)}, but useful when you do not have a {@link
+     * Class} object for type you wish to cast to. </p> <p/> <p> {@link Class#cast(Object)} should be used if possible
+     * </p>
+     *
+     * @param <T> the type to cast to
+     * @param obj the object to perform the cast on
+     *
+     * @return the casted object
+     *
+     * @throws ClassCastException if the type T is not a subtype of the object
+     * @see Class#cast(Object)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj) {
+        return (T) obj;
+    }
+
+    /**
+     * Get all the declared fields on the class hierarchy. This <b>will</b> return overridden fields.
+     *
+     * @param clazz The class to search
+     *
+     * @return the set of all declared fields or an empty set if there are none
+     */
+    public static Set<Field> getAllDeclaredFields(Class<?> clazz) {
+        HashSet<Field> fields = new HashSet<Field>();
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            for (Field a : c.getDeclaredFields()) {
+                fields.add(a);
+            }
+        }
+        return fields;
+    }
+
+    /**
+     * Search the class hierarchy for a field with the given name. Will return the nearest match, starting with the
+     * class specified and searching up the hierarchy.
+     *
+     * @param clazz The class to search
+     * @param name The name of the field to search for
+     *
+     * @return The field found, or null if no field is found
+     */
+    public static Field findDeclaredField(Class<?> clazz, String name) {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            try {
+                return c.getDeclaredField(name);
+            } catch (NoSuchFieldException e) {
+                // No-op, we continue looking up the class hierarchy
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Search for annotations with the specified meta annotation type
+     *
+     * @param annotations The annotation set to search
+     * @param metaAnnotationType The type of the meta annotation to search for
+     *
+     * @return The set of annotations with the specified meta annotation, or an empty set if none are found
+     */
+    public static Set<Annotation> getAnnotationsWithMetaAnnotation(
+            Set<Annotation> annotations, Class<? extends Annotation> metaAnnotationType) {
+        Set<Annotation> set = new HashSet<Annotation>();
+        for (Annotation annotation : annotations) {
+            if (annotation.annotationType().isAnnotationPresent(metaAnnotationType)) {
+                set.add(annotation);
+            }
+        }
+        return set;
+    }
+
+    /**
+     * Determine if a method exists in a specified class hierarchy
+     *
+     * @param clazz The class to search
+     * @param name The name of the method
+     *
+     * @return true if a method is found, otherwise false
+     */
+    public static boolean methodExists(Class<?> clazz, String name) {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            for (Method m : c.getDeclaredMethods()) {
+                if (m.getName().equals(name)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get all the declared methods on the class hierarchy. This <b>will</b> return overridden methods.
+     *
+     * @param clazz The class to search
+     *
+     * @return the set of all declared methods or an empty set if there are none
+     */
+    public static Set<Method> getAllDeclaredMethods(Class<?> clazz) {
+        HashSet<Method> methods = new HashSet<Method>();
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            for (Method a : c.getDeclaredMethods()) {
+                methods.add(a);
+            }
+        }
+        return methods;
+    }
+
+    /**
+     * Search the class hierarchy for a method with the given name and arguments. Will return the nearest match,
+     * starting with the class specified and searching up the hierarchy.
+     *
+     * @param clazz The class to search
+     * @param name The name of the method to search for
+     * @param args The arguments of the method to search for
+     *
+     * @return The method found, or null if no method is found
+     */
+    public static Method findDeclaredMethod(Class<?> clazz, String name, Class<?>... args) {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            try {
+                return c.getDeclaredMethod(name, args);
+            } catch (NoSuchMethodException e) {
+                // No-op, continue the search
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Search the class hierarchy for a constructor with the given arguments. Will return the nearest match, starting
+     * with the class specified and searching up the hierarchy.
+     *
+     * @param clazz The class to search
+     * @param args The arguments of the constructor to search for
+     *
+     * @return The constructor found, or null if no constructor is found
+     */
+    public static Constructor<?> findDeclaredConstructor(Class<?> clazz, Class<?>... args) {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            try {
+                return c.getDeclaredConstructor(args);
+            } catch (NoSuchMethodException e) {
+                // No-op, continue the search
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get all the declared constructors on the class hierarchy. This <b>will</b> return overridden constructors.
+     *
+     * @param clazz The class to search
+     *
+     * @return the set of all declared constructors or an empty set if there are none
+     */
+    public static Set<Constructor<?>> getAllDeclaredConstructors(Class<?> clazz) {
+        HashSet<Constructor<?>> constructors = new HashSet<Constructor<?>>();
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass()) {
+            for (Constructor<?> constructor : c.getDeclaredConstructors()) {
+                constructors.add(constructor);
+            }
+        }
+        return constructors;
+    }
+
+    /**
+     * Get the type of the member
+     *
+     * @param member The member
+     *
+     * @return The type of the member
+     *
+     * @throws UnsupportedOperationException if the member is not a field, method, or constructor
+     */
+    public static Class<?> getMemberType(Member member) {
+        if (member instanceof Field) {
+            return ((Field) member).getType();
+        } else if (member instanceof Method) {
+            return ((Method) member).getReturnType();
+        } else if (member instanceof Constructor<?>) {
+            return ((Constructor<?>) member).getDeclaringClass();
+        } else {
+            throw new UnsupportedOperationException("Cannot operate on a member of type " + member.getClass());
+        }
+    }
+
+    /**
+     * <p> Loads and initializes a class for the given name. </p> <p/> <p> If the Thread Context Class Loader is
+     * available, it will be used, otherwise the classloader used to load {@link Reflections} will be used </p> <p/> <p>
+     * It is also possible to specify additional classloaders to attempt to load the class with. If the first attempt
+     * fails, then these additional loaders are tried in order. </p>
+     *
+     * @param name the name of the class to load
+     * @param loaders additional classloaders to use to attempt to load the class
+     *
+     * @return the class object
+     *
+     * @throws ClassNotFoundException if the class cannot be found
+     */
+    public static <T> Class<T> classForName(String name, ClassLoader... loaders) throws ClassNotFoundException {
+        try {
+            if (Thread.currentThread().getContextClassLoader() != null) {
+                return (Class<T>) Class.forName(name, true, Thread.currentThread().getContextClassLoader());
+            } else {
+                return (Class<T>) Class.forName(name);
+            }
+        } catch (ClassNotFoundException e) {
+            for (ClassLoader l : loaders) {
+                try {
+                    return (Class<T>) Class.forName(name, true, l);
+                } catch (ClassNotFoundException ex) {
+
+                }
+            }
+        }
+        if (Thread.currentThread().getContextClassLoader() != null) {
+            throw new ClassNotFoundException("Could not load class " + name +
+                    " with the context class loader " + Thread.currentThread().getContextClassLoader().toString() +
+                    " or any of the additional ClassLoaders: " + Arrays.toString(loaders));
+        } else {
+            throw new ClassNotFoundException("Could not load class " + name +
+                    " using Class.forName or using any of the additional ClassLoaders: " +
+                    Arrays.toString(loaders));
+        }
+    }
+
+    private static String buildInvokeMethodErrorMessage(Method method, Object obj, Object... args) {
+        StringBuilder message = new StringBuilder(
+                String.format("Exception invoking method [%s] on object [%s], using arguments [",
+                        method.getName(), obj));
+        if (args != null) {
+            for (int i = 0; i < args.length; i++) {
+                message.append((i > 0 ? "," : "") + args[i]);
+            }
+        }
+        message.append("]");
+        return message.toString();
+    }
+
+    /**
+     * <p> Invoke the specified method on the provided instance, passing any additional arguments included in this
+     * method as arguments to the specified method. </p> <p/> <p>This method provides the same functionality and throws
+     * the same exceptions as {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the
+     * expected return type set to {@link Object} and no change to the method's accessibility.</p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static Object invokeMethod(Method method, Object instance, Object... args) {
+        return invokeMethod(false, method, Object.class, instance, args);
+    }
+
+    /**
+     * <p> Invoke the specified method on the provided instance, passing any additional arguments included in this
+     * method as arguments to the specified method. </p> <p/> <p> This method attempts to set the accessible flag of the
+     * method in a {link PrivilegedAction} before invoking the method if the first argument is true. </p> <p/> <p>This
+     * method provides the same functionality and throws the same exceptions as {@link Reflections#invokeMethod(boolean,
+     * Method, Class, Object, Object...)}, with the expected return type set to {@link Object}.</p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static Object invokeMethod(boolean setAccessible, Method method, Object instance, Object... args) {
+        return invokeMethod(setAccessible, method, Object.class, instance, args);
+    }
+
+    /**
+     * <p> Invoke the specified method on the provided instance, passing any additional arguments included in this
+     * method as arguments to the specified method. </p> <p/> <p>This method provides the same functionality and throws
+     * the same exceptions as {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the
+     * expected return type set to {@link Object} and honoring the accessibility of the method.</p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static <T> T invokeMethod(Method method, Class<T> expectedReturnType, Object instance, Object... args) {
+        return invokeMethod(false, method, expectedReturnType, instance, args);
+    }
+
+    /**
+     * <p> Invoke the method on the instance, with any arguments specified, casting the result of invoking the method to
+     * the expected return type. </p> <p/> <p> This method wraps {@link Method#invoke(Object, Object...)}, converting
+     * the checked exceptions that {@link Method#invoke(Object, Object...)} specifies to runtime exceptions. </p> <p/>
+     * <p> If instructed, this method attempts to set the accessible flag of the method in a {link PrivilegedAction}
+     * before invoking the method. </p>
+     *
+     * @param setAccessible flag indicating whether method should first be set as accessible
+     * @param method the method to invoke
+     * @param instance the instance to invoke the method
+     * @param args the arguments to the method
+     *
+     * @return the result of invoking the method, or null if the method's return type is void
+     *
+     * @throws RuntimeException if this <code>Method</code> object enforces Java language access control and the
+     * underlying method is inaccessible or if the underlying method throws an exception or if the initialization
+     * provoked by this method fails.
+     * @throws IllegalArgumentException if the method is an instance method and the specified <code>instance</code>
+     * argument is not an instance of the class or interface declaring the underlying method (or of a subclass or
+     * implementor thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for
+     * primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the
+     * corresponding formal parameter type by a method invocation conversion.
+     * @throws NullPointerException if the specified <code>instance</code> is null and the method is an instance
+     * method.
+     * @throws ClassCastException if the result of invoking the method cannot be cast to the expectedReturnType
+     * @throws ExceptionInInitializerError if the initialization provoked by this method fails.
+     * @see Method#invoke(Object, Object...)
+     */
+    public static <T> T invokeMethod(boolean setAccessible, Method method,
+                                     Class<T> expectedReturnType, Object instance, Object... args) {
+        if (setAccessible && !method.isAccessible()) {
+            setAccessible(method);
+        }
+
+        try {
+            return expectedReturnType.cast(method.invoke(instance, args));
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new IllegalArgumentException(buildInvokeMethodErrorMessage(method, instance, args), ex);
+        } catch (InvocationTargetException ex) {
+            throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex.getCause());
+        } catch (NullPointerException ex) {
+            NullPointerException ex2 = new NullPointerException(buildInvokeMethodErrorMessage(method, instance, args));
+            ex2.initCause(ex.getCause());
+            throw ex2;
+        } catch (ExceptionInInitializerError e) {
+            ExceptionInInitializerError e2 = new ExceptionInInitializerError(
+                    buildInvokeMethodErrorMessage(method, instance, args));
+            e2.initCause(e.getCause());
+            throw e2;
+        }
+    }
+
+    /**
+     * Set the accessibility flag on the {@link AccessibleObject} as described in {@link
+     * AccessibleObject#setAccessible(boolean)} within the context of a {link PrivilegedAction}.
+     *
+     * @param <A> member the accessible object type
+     * @param member the accessible object
+     *
+     * @return the accessible object after the accessible flag has been altered
+     */
+    public static <A extends AccessibleObject> A setAccessible(A member) {
+        AccessController.doPrivileged(new SetAccessiblePrivilegedAction(member));
+        return member;
+    }
+
+    private static String buildSetFieldValueErrorMessage(Field field, Object obj, Object value) {
+        return String.format("Exception setting [%s] field on object [%s] to value [%s]", field.getName(), obj, value);
+    }
+
+    private static String buildGetFieldValueErrorMessage(Field field, Object obj) {
+        return String.format("Exception reading [%s] field from object [%s].", field.getName(), obj);
+    }
+
+    public static Object getFieldValue(Field field, Object instance) {
+        return getFieldValue(field, instance, Object.class);
+    }
+
+    /**
+     * <p> Get the value of the field, on the specified instance, casting the value of the field to the expected type.
+     * </p> <p/> <p> This method wraps {@link Field#get(Object)}, converting the checked exceptions that {@link
+     * Field#get(Object)} specifies to runtime exceptions. </p>
+     *
+     * @param <T> the type of the field's value
+     * @param field the field to operate on
+     * @param instance the instance from which to retrieve the value
+     * @param expectedType the expected type of the field's value
+     *
+     * @return the value of the field
+     *
+     * @throws RuntimeException if the underlying field is inaccessible.
+     * @throws IllegalArgumentException if the specified <code>instance</code> is not an instance of the class or
+     * interface declaring the underlying field (or a subclass or implementor thereof).
+     * @throws NullPointerException if the specified <code>instance</code> is null and the field is an instance field.
+     * @throws ExceptionInInitializerError if the initialization provoked by this method fails.
+     */
+    public static <T> T getFieldValue(Field field, Object instance, Class<T> expectedType) {
+        try {
+            return Reflections.cast(field.get(instance));
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(buildGetFieldValueErrorMessage(field, instance), e);
+        } catch (NullPointerException ex) {
+            NullPointerException ex2 = new NullPointerException(buildGetFieldValueErrorMessage(field, instance));
+            ex2.initCause(ex.getCause());
+            throw ex2;
+        } catch (ExceptionInInitializerError e) {
+            ExceptionInInitializerError e2 = new ExceptionInInitializerError(
+                    buildGetFieldValueErrorMessage(field, instance));
+            e2.initCause(e.getCause());
+            throw e2;
+        }
+    }
+
+    /**
+     * Extract the raw type, given a type.
+     *
+     * @param <T> the type
+     * @param type the type to extract the raw type from
+     *
+     * @return the raw type, or null if the raw type cannot be determined.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> getRawType(Type type) {
+        if (type instanceof Class<?>) {
+            return (Class<T>) type;
+        } else if (type instanceof ParameterizedType) {
+            if (((ParameterizedType) type).getRawType() instanceof Class<?>) {
+                return (Class<T>) ((ParameterizedType) type).getRawType();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check if a class is serializable.
+     *
+     * @param clazz The class to check
+     *
+     * @return true if the class implements serializable or is a primitive
+     */
+    public static boolean isSerializable(Class<?> clazz) {
+        return clazz.isPrimitive() || Serializable.class.isAssignableFrom(clazz);
+    }
+
+
+    public static Map<Class<?>, Type> buildTypeMap(Set<Type> types) {
+        Map<Class<?>, Type> map = new HashMap<Class<?>, Type>();
+        for (Type type : types) {
+            if (type instanceof Class<?>) {
+                map.put((Class<?>) type, type);
+            } else if (type instanceof ParameterizedType) {
+                if (((ParameterizedType) type).getRawType() instanceof Class<?>) {
+                    map.put((Class<?>) ((ParameterizedType) type).getRawType(), type);
+                }
+            } else if (type instanceof TypeVariable<?>) {
+
+            }
+        }
+        return map;
+    }
+
+    public static boolean isCacheable(Set<Annotation> annotations) {
+        for (Annotation qualifier : annotations) {
+            Class<?> clazz = qualifier.getClass();
+            if (clazz.isAnonymousClass() || (clazz.isMemberClass() && isStatic(clazz))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isCacheable(Annotation[] annotations) {
+        for (Annotation qualifier : annotations) {
+            Class<?> clazz = qualifier.getClass();
+            if (clazz.isAnonymousClass() || (clazz.isMemberClass() && isStatic(clazz))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the property name from a getter method.
+     * <p/>
+     * We extend JavaBean conventions, allowing the getter method to have parameters
+     *
+     * @param method The getter method
+     *
+     * @return The name of the property. Returns null if method wasn't JavaBean getter-styled
+     */
+    public static String getPropertyName(Method method) {
+        String methodName = method.getName();
+        if (methodName.matches("^(get).*")) {
+            return Introspector.decapitalize(methodName.substring(3));
+        } else if (methodName.matches("^(is).*")) {
+            return Introspector.decapitalize(methodName.substring(2));
+        } else {
+            return null;
+        }
+
+    }
+
+    /**
+     * Checks if class is final
+     *
+     * @param clazz The class to check
+     *
+     * @return True if final, false otherwise
+     */
+    public static boolean isFinal(Class<?> clazz) {
+        return Modifier.isFinal(clazz.getModifiers());
+    }
+
+    public static int getNesting(Class<?> clazz) {
+        if (clazz.isMemberClass() && !isStatic(clazz)) {
+            return 1 + getNesting(clazz.getDeclaringClass());
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Checks if member is final
+     *
+     * @param member The member to check
+     *
+     * @return True if final, false otherwise
+     */
+    public static boolean isFinal(Member member) {
+        return Modifier.isFinal(member.getModifiers());
+    }
+
+    /**
+     * Checks if member is private
+     *
+     * @param member The member to check
+     *
+     * @return True if final, false otherwise
+     */
+    public static boolean isPrivate(Member member) {
+        return Modifier.isPrivate(member.getModifiers());
+    }
+
+    /**
+     * Checks if type or member is final
+     *
+     * @param type Type or member
+     *
+     * @return True if final, false otherwise
+     */
+    public static boolean isTypeOrAnyMethodFinal(Class<?> type) {
+        return getNonPrivateFinalMethodOrType(type) != null;
+    }
+
+    public static Object getNonPrivateFinalMethodOrType(Class<?> type) {
+        if (isFinal(type)) {
+            return type;
+        }
+        for (Method method : type.getDeclaredMethods()) {
+            if (isFinal(method) && !isPrivate(method)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isPackagePrivate(int mod) {
+        return !(Modifier.isPrivate(mod) || Modifier.isProtected(mod) || Modifier.isPublic(mod));
+    }
+
+    /**
+     * Checks if type is static
+     *
+     * @param type Type to check
+     *
+     * @return True if static, false otherwise
+     */
+    public static boolean isStatic(Class<?> type) {
+        return Modifier.isStatic(type.getModifiers());
+    }
+
+    /**
+     * Checks if member is static
+     *
+     * @param member Member to check
+     *
+     * @return True if static, false otherwise
+     */
+    public static boolean isStatic(Member member) {
+        return Modifier.isStatic(member.getModifiers());
+    }
+
+    public static boolean isTransient(Member member) {
+        return Modifier.isTransient(member.getModifiers());
+    }
+
+    /**
+     * Checks if a method is abstract
+     *
+     * @param method
+     *
+     * @return
+     */
+    public static boolean isAbstract(Method method) {
+        return Modifier.isAbstract(method.getModifiers());
+    }
+
+    /**
+     * Checks if raw type is array type
+     *
+     * @param rawType The raw type to check
+     *
+     * @return True if array, false otherwise
+     */
+    public static boolean isArrayType(Class<?> rawType) {
+        return rawType.isArray();
+    }
+
+    /**
+     * Checks if type is parameterized type
+     *
+     * @param type The type to check
+     *
+     * @return True if parameterized, false otherwise
+     */
+    public static boolean isParameterizedType(Class<?> type) {
+        return type.getTypeParameters().length > 0;
+    }
+
+    public static boolean isParamerterizedTypeWithWildcard(Class<?> type) {
+        if (isParameterizedType(type)) {
+            return containsWildcards(type.getTypeParameters());
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean containsWildcards(Type[] types) {
+        for (Type type : types) {
+            if (type instanceof WildcardType) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check the assignability of one type to another, taking into account the actual type arguements
+     *
+     * @param rawType1 the raw type of the class to check
+     * @param actualTypeArguments1 the actual type arguements to check, or an empty array if not a parameterized type
+     * @param rawType2 the raw type of the class to check
+     * @param actualTypeArguments2 the actual type arguements to check, or an empty array if not a parameterized type
+     *
+     * @return
+     */
+    public static boolean isAssignableFrom(Class<?> rawType1, Type[] actualTypeArguments1,
+                                           Class<?> rawType2, Type[] actualTypeArguments2) {
+        return Types.boxedClass(rawType1).isAssignableFrom(Types.boxedClass(rawType2)) &&
+                isAssignableFrom(actualTypeArguments1, actualTypeArguments2);
+    }
+
+    public static boolean matches(Class<?> rawType1, Type[] actualTypeArguments1,
+                                  Class<?> rawType2, Type[] actualTypeArguments2) {
+        return Types.boxedClass(rawType1).equals(Types.boxedClass(rawType2)) &&
+                isAssignableFrom(actualTypeArguments1, actualTypeArguments2);
+    }
+
+    public static boolean isAssignableFrom(Type[] actualTypeArguments1, Type[] actualTypeArguments2) {
+        for (int i = 0; i < actualTypeArguments1.length; i++) {
+            Type type1 = actualTypeArguments1[i];
+            Type type2 = Object.class;
+            if (actualTypeArguments2.length > i) {
+                type2 = actualTypeArguments2[i];
+            }
+            if (!isAssignableFrom(type1, type2)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isAssignableFrom(Type type1, Set<? extends Type> types2) {
+        for (Type type2 : types2) {
+            if (isAssignableFrom(type1, type2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean matches(Type type1, Set<? extends Type> types2) {
+        for (Type type2 : types2) {
+            if (matches(type1, type2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isAssignableFrom(Type type1, Type[] types2) {
+        for (Type type2 : types2) {
+            if (isAssignableFrom(type1, type2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isAssignableFrom(Type type1, Type type2) {
+        if (type1 instanceof Class<?>) {
+            Class<?> clazz = (Class<?>) type1;
+            if (isAssignableFrom(clazz, EMPTY_TYPES, type2)) {
+                return true;
+            }
+        }
+        if (type1 instanceof ParameterizedType) {
+            ParameterizedType parameterizedType1 = (ParameterizedType) type1;
+            if (parameterizedType1.getRawType() instanceof Class<?>) {
+                if (isAssignableFrom((Class<?>) parameterizedType1.getRawType(),
+                        parameterizedType1.getActualTypeArguments(), type2)) {
+                    return true;
+                }
+            }
+        }
+        if (type1 instanceof WildcardType) {
+            WildcardType wildcardType = (WildcardType) type1;
+            if (isTypeBounded(type2, wildcardType.getLowerBounds(), wildcardType.getUpperBounds())) {
+                return true;
+            }
+        }
+        if (type2 instanceof WildcardType) {
+            WildcardType wildcardType = (WildcardType) type2;
+            if (isTypeBounded(type1, wildcardType.getUpperBounds(), wildcardType.getLowerBounds())) {
+                return true;
+            }
+        }
+        if (type1 instanceof TypeVariable<?>) {
+            TypeVariable<?> typeVariable = (TypeVariable<?>) type1;
+            if (isTypeBounded(type2, EMPTY_TYPES, typeVariable.getBounds())) {
+                return true;
+            }
+        }
+        if (type2 instanceof TypeVariable<?>) {
+            TypeVariable<?> typeVariable = (TypeVariable<?>) type2;
+            if (isTypeBounded(type1, typeVariable.getBounds(), EMPTY_TYPES)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean matches(Type type1, Type type2) {
+        if (type1 instanceof Class<?>) {
+            Class<?> clazz = (Class<?>) type1;
+            if (matches(clazz, EMPTY_TYPES, type2)) {
+                return true;
+            }
+        }
+        if (type1 instanceof ParameterizedType) {
+            ParameterizedType parameterizedType1 = (ParameterizedType) type1;
+            if (parameterizedType1.getRawType() instanceof Class<?>) {
+                if (matches((Class<?>) parameterizedType1.getRawType(),
+                        parameterizedType1.getActualTypeArguments(), type2)) {
+                    return true;
+                }
+            }
+        }
+        if (type1 instanceof WildcardType) {
+            WildcardType wildcardType = (WildcardType) type1;
+            if (isTypeBounded(type2, wildcardType.getLowerBounds(), wildcardType.getUpperBounds())) {
+                return true;
+            }
+        }
+        if (type2 instanceof WildcardType) {
+            WildcardType wildcardType = (WildcardType) type2;
+            if (isTypeBounded(type1, wildcardType.getUpperBounds(), wildcardType.getLowerBounds())) {
+                return true;
+            }
+        }
+        if (type1 instanceof TypeVariable<?>) {
+            TypeVariable<?> typeVariable = (TypeVariable<?>) type1;
+            if (isTypeBounded(type2, EMPTY_TYPES, typeVariable.getBounds())) {
+                return true;
+            }
+        }
+        if (type2 instanceof TypeVariable<?>) {
+            TypeVariable<?> typeVariable = (TypeVariable<?>) type2;
+            if (isTypeBounded(type1, typeVariable.getBounds(), EMPTY_TYPES)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isTypeBounded(Type type, Type[] lowerBounds, Type[] upperBounds) {
+        if (lowerBounds.length > 0) {
+            if (!isAssignableFrom(type, lowerBounds)) {
+                return false;
+            }
+        }
+        if (upperBounds.length > 0) {
+            if (!isAssignableFrom(upperBounds, type)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isAssignableFrom(Class<?> rawType1, Type[] actualTypeArguments1, Type type2) {
+        if (type2 instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) type2;
+            if (parameterizedType.getRawType() instanceof Class<?>) {
+                if (isAssignableFrom(rawType1, actualTypeArguments1, (Class<?>) parameterizedType.getRawType(),
+                        parameterizedType.getActualTypeArguments())) {
+                    return true;
+                }
+            }
+        } else if (type2 instanceof Class<?>) {
+            Class<?> clazz = (Class<?>) type2;
+            if (isAssignableFrom(rawType1, actualTypeArguments1, clazz, EMPTY_TYPES)) {
+                return true;
+            }
+        } else if (type2 instanceof TypeVariable<?>) {
+            TypeVariable<?> typeVariable = (TypeVariable<?>) type2;
+            if (isTypeBounded(rawType1, actualTypeArguments1, typeVariable.getBounds())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean matches(Class<?> rawType1, Type[] actualTypeArguments1, Type type2) {
+        if (type2 instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) type2;
+            if (parameterizedType.getRawType() instanceof Class<?>) {
+                if (matches(rawType1, actualTypeArguments1, (Class<?>) parameterizedType.getRawType(),
+                        parameterizedType.getActualTypeArguments())) {
+                    return true;
+                }
+            }
+        } else if (type2 instanceof Class<?>) {
+            Class<?> clazz = (Class<?>) type2;
+            if (matches(rawType1, actualTypeArguments1, clazz, EMPTY_TYPES)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check the assiginability of a set of <b>flattened</b> types. This algorithm will check whether any of the types1
+     * matches a type in types2
+     *
+     * @param types1
+     * @param types2
+     *
+     * @return
+     */
+    public static boolean isAssignableFrom(Set<Type> types1, Set<Type> types2) {
+        for (Type type : types1) {
+            if (isAssignableFrom(type, types2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check whether whether any of the types1 matches a type in types2
+     *
+     * @param types1
+     * @param types2
+     *
+     * @return
+     */
+    public static boolean matches(Set<Type> types1, Set<Type> types2) {
+        for (Type type : types1) {
+            if (matches(type, types2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check the assignability of a set of <b>flattened</b> types. This algorithm will check whether any of the types1
+     * matches a type in types2
+     *
+     * @param types1
+     * @param type2
+     *
+     * @return
+     */
+    public static boolean isAssignableFrom(Set<Type> types1, Type type2) {
+        for (Type type : types1) {
+            if (isAssignableFrom(type, type2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isAssignableFrom(Type[] types1, Type type2) {
+        for (Type type : types1) {
+            if (isAssignableFrom(type, type2)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isPrimitive(Type type) {
+        Class<?> rawType = getRawType(type);
+        return rawType == null ? false : rawType.isPrimitive();
+    }
+
+    /**
+     * <p>Creates a new instance of a class.</p>
+     *
+     * <p>This method will use the same class loader of the given class to create the new instance.</p>
+     *
+     * @param fromClass The class from where the instance should be created.
+     *
+     * @return A newly allocated instance of the class.
+     *
+     * @throws ClassNotFoundException
+     * @throws IllegalAccessException
+     * @throws InstantiationException
+     */
+    public static <T> T newInstance(final Class<T> fromClass) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        return newInstance(fromClass, fromClass.getName());
+    }
+
+    /**
+     * <p>Creates a new instance of a class given its <code>fullQualifiedName</code>.</p>
+     *
+     * <p>This method will use the same class loader of <code>type</code> to create the new instance.</p>
+     *
+     * @param type The class that will be used to get the class loader from.
+     * @param fullQualifiedName The full qualified name of the class from which the instance will be created.
+     *
+     * @return A newly allocated instance of the class.
+     *
+     * @throws ClassNotFoundException
+     * @throws IllegalAccessException
+     * @throws InstantiationException
+     */
+    public static <T> T newInstance(final Class<?> type, final String fullQualifiedName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        return (T) classForName(fullQualifiedName, type.getClassLoader()).newInstance();
+    }
+}
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/SetAccessiblePrivilegedAction.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/SetAccessiblePrivilegedAction.java
new file mode 100644
index 0000000..3d10120
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/SetAccessiblePrivilegedAction.java
@@ -0,0 +1,22 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.AccessibleObject;
+import java.security.PrivilegedAction;
+
+/**
+ * A {@link java.security.PrivilegedAction} that calls {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
+ */
+public class SetAccessiblePrivilegedAction implements PrivilegedAction<Void> {
+
+    private final AccessibleObject member;
+
+    public SetAccessiblePrivilegedAction(AccessibleObject member) {
+        this.member = member;
+    }
+
+    public Void run() {
+        member.setAccessible(true);
+        return null;
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/Types.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/Types.java
new file mode 100644
index 0000000..30015b4
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/Types.java
@@ -0,0 +1,54 @@
+package org.keycloak.models.utils.reflection;
+
+import java.lang.reflect.Type;
+
+/**
+ * Utility class for Types
+ */
+public class Types {
+    private Types() {
+
+    }
+
+    /**
+     * Gets the boxed type of a class
+     *
+     * @param type The type
+     *
+     * @return The boxed type
+     */
+    public static Type boxedType(Type type) {
+        if (type instanceof Class<?>) {
+            return boxedClass((Class<?>) type);
+        } else {
+            return type;
+        }
+    }
+
+    public static Class<?> boxedClass(Class<?> type) {
+        if (!type.isPrimitive()) {
+            return type;
+        } else if (type.equals(Boolean.TYPE)) {
+            return Boolean.class;
+        } else if (type.equals(Character.TYPE)) {
+            return Character.class;
+        } else if (type.equals(Byte.TYPE)) {
+            return Byte.class;
+        } else if (type.equals(Short.TYPE)) {
+            return Short.class;
+        } else if (type.equals(Integer.TYPE)) {
+            return Integer.class;
+        } else if (type.equals(Long.TYPE)) {
+            return Long.class;
+        } else if (type.equals(Float.TYPE)) {
+            return Float.class;
+        } else if (type.equals(Double.TYPE)) {
+            return Double.class;
+        } else if (type.equals(Void.TYPE)) {
+            return Void.class;
+        } else {
+            // Vagaries of if/else statement, can't be reached ;-)
+            return type;
+        }
+    }
+}
\ No newline at end of file

model/jpa/pom.xml 15(+15 -0)

diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index 3e4340a..15ac823 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -115,6 +115,21 @@
                 </configuration>
             </plugin>
 
+            <!-- Test jar used in export-import -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>package-tests-jar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
index 113fd0c..d23a0f4 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -7,6 +7,7 @@ import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.jpa.entities.*;
+import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
@@ -99,7 +100,13 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
 
     @Override
     public RoleModel addRole(String name) {
+        return this.addRole(KeycloakModelUtils.generateId(), name);
+    }
+
+    @Override
+    public RoleModel addRole(String id, String name) {
         ApplicationRoleEntity roleEntity = new ApplicationRoleEntity();
+        roleEntity.setId(id);
         roleEntity.setName(name);
         roleEntity.setApplication(applicationEntity);
         em.persist(roleEntity);
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index cd23f5f..96ac2c9 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -29,8 +29,6 @@ import java.util.Set;
 @Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"realm", "name"})})
 public abstract class ClientEntity {
     @Id
-    @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
-    @GeneratedValue(generator = "keycloak_generator")
     private String id;
     @Column(name = "name")
     private String name;
@@ -63,6 +61,10 @@ public abstract class ClientEntity {
         return id;
     }
 
+    public void setId(String id) {
+        this.id = id;
+    }
+
     public boolean isEnabled() {
         return enabled;
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
index 6101cae..3792995 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
@@ -28,8 +28,6 @@ import org.hibernate.annotations.GenericGenerator;
 })
 public abstract class RoleEntity {
     @Id
-    @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
-    @GeneratedValue(generator = "keycloak_generator")
     private String id;
 
     private String description;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
index f7ef212..f51ed94 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
@@ -44,8 +44,6 @@ import java.util.Set;
 })
 public class UserEntity {
     @Id
-    @GenericGenerator(name="uuid_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
-    @GeneratedValue(generator = "uuid_generator")
     protected String id;
 
     protected String loginName;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java
index 6011ccc..e3336e0 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java
@@ -3,12 +3,17 @@ package org.keycloak.models.jpa.entities;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 @Entity
+@NamedQueries({
+        @NamedQuery(name="getAllFailures", query="select failure from UsernameLoginFailureEntity failure"),
+})
 public class UsernameLoginFailureEntity {
     // we manually set the id to be username-realmid
     // we may have a concurrent creation of the same login failure entry that we want to avoid
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
index 9bcca9f..d54cf3c 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
@@ -102,4 +102,13 @@ public class JpaKeycloakSession implements KeycloakSession {
         if (em.getTransaction().isActive()) em.getTransaction().rollback();
         if (em.isOpen()) em.close();
     }
+
+    @Override
+    public void removeAllData() {
+        // Should be sufficient to delete all realms. Rest data should be removed in cascade
+        List<RealmModel> realms = getRealms();
+        for (RealmModel realm : realms) {
+            removeRealm(realm.getId());
+        }
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index a7c32ca..4b6758d 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -4,6 +4,7 @@ import org.keycloak.models.AuthenticationLinkModel;
 import org.keycloak.models.AuthenticationProviderModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UsernameLoginFailureModel;
 import org.keycloak.models.jpa.entities.ApplicationEntity;
 import org.keycloak.models.jpa.entities.ApplicationRoleEntity;
@@ -435,6 +436,17 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        TypedQuery<UsernameLoginFailureEntity> query = em.createNamedQuery("getAllFailures", UsernameLoginFailureEntity.class);
+        List<UsernameLoginFailureEntity> entities = query.getResultList();
+        List<UsernameLoginFailureModel> models = new ArrayList<UsernameLoginFailureModel>();
+        for (UsernameLoginFailureEntity entity : entities) {
+            models.add(new UsernameLoginFailureAdapter(entity));
+        }
+        return models;
+    }
+
+    @Override
     public UserModel getUserByEmail(String email) {
         TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class);
         query.setParameter("email", email);
@@ -454,7 +466,13 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public UserModel addUser(String username) {
+        return this.addUser(KeycloakModelUtils.generateId(), username);
+    }
+
+    @Override
+    public UserModel addUser(String id, String username) {
         UserEntity entity = new UserEntity();
+        entity.setId(id);
         entity.setLoginName(username);
         entity.setRealm(realm);
         em.persist(entity);
@@ -580,7 +598,13 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public ApplicationModel addApplication(String name) {
+        return this.addApplication(KeycloakModelUtils.generateId(), name);
+    }
+
+    @Override
+    public ApplicationModel addApplication(String id, String name) {
         ApplicationEntity applicationData = new ApplicationEntity();
+        applicationData.setId(id);
         applicationData.setName(name);
         applicationData.setEnabled(true);
         applicationData.setRealm(realm);
@@ -805,7 +829,13 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public OAuthClientModel addOAuthClient(String name) {
+        return this.addOAuthClient(KeycloakModelUtils.generateId(), name);
+    }
+
+    @Override
+    public OAuthClientModel addOAuthClient(String id, String name) {
         OAuthClientEntity data = new OAuthClientEntity();
+        data.setId(id);
         data.setEnabled(true);
         data.setName(name);
         data.setRealm(realm);
@@ -949,7 +979,13 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public RoleModel addRole(String name) {
+        return this.addRole(KeycloakModelUtils.generateId(), name);
+    }
+
+    @Override
+    public RoleModel addRole(String id, String name) {
         RealmRoleEntity entity = new RealmRoleEntity();
+        entity.setId(id);
         entity.setName(name);
         entity.setRealm(realm);
         realm.getRoles().add(entity);
@@ -1170,13 +1206,9 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public void updateCredential(UserModel user, UserCredentialModel cred) {
-        CredentialEntity credentialEntity = null;
         UserEntity userEntity = ((UserAdapter) user).getUser();
-        for (CredentialEntity entity : userEntity.getCredentials()) {
-            if (entity.getType().equals(cred.getType())) {
-               credentialEntity = entity;
-            }
-        }
+        CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType());
+
         if (credentialEntity == null) {
             credentialEntity = new CredentialEntity();
             credentialEntity.setType(cred.getType());
@@ -1196,6 +1228,57 @@ public class RealmAdapter implements RealmModel {
         em.flush();
     }
 
+    private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) {
+        for (CredentialEntity entity : userEntity.getCredentials()) {
+            if (entity.getType().equals(credType)) {
+                return entity;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly(UserModel user) {
+        UserEntity userEntity = ((UserAdapter) user).getUser();
+        List<CredentialEntity> credentials = new ArrayList<CredentialEntity>(userEntity.getCredentials());
+        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
+
+        if (credentials != null) {
+            for (CredentialEntity credEntity : credentials) {
+                UserCredentialValueModel credModel = new UserCredentialValueModel();
+                credModel.setType(credEntity.getType());
+                credModel.setDevice(credEntity.getDevice());
+                credModel.setValue(credEntity.getValue());
+                credModel.setSalt(credEntity.getSalt());
+
+                result.add(credModel);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) {
+        UserEntity userEntity = ((UserAdapter) user).getUser();
+        CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(credModel.getType());
+            credentialEntity.setUser(userEntity);
+            em.persist(credentialEntity);
+            userEntity.getCredentials().add(credentialEntity);
+        }
+
+        credentialEntity.setValue(credModel.getValue());
+        credentialEntity.setSalt(credModel.getSalt());
+        credentialEntity.setDevice(credModel.getDevice());
+
+        em.flush();
+    }
+
     @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
diff --git a/model/mongo/pom.xml b/model/mongo/pom.xml
index 6f8110d..01bce2f 100755
--- a/model/mongo/pom.xml
+++ b/model/mongo/pom.xml
@@ -62,11 +62,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.picketlink</groupId>
-            <artifactId>picketlink-common</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.mongodb</groupId>
             <artifactId>mongo-java-driver</artifactId>
             <scope>provided</scope>
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/api/MongoStore.java b/model/mongo/src/main/java/org/keycloak/models/mongo/api/MongoStore.java
index f16400c..56951eb 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/api/MongoStore.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/api/MongoStore.java
@@ -40,4 +40,9 @@ public interface MongoStore {
     <S> boolean pushItemToList(MongoIdentifiableEntity entity, String listPropertyName, S itemToPush, boolean skipIfAlreadyPresent, MongoStoreInvocationContext context);
 
     <S> boolean pullItemFromList(MongoIdentifiableEntity entity, String listPropertyName, S itemToPull, MongoStoreInvocationContext context);
+
+    /**
+     * Completely remove all data from DB
+     */
+    void removeAllEntities();
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/EntityInfo.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/EntityInfo.java
index b6ff046..8a68e96 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/EntityInfo.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/EntityInfo.java
@@ -1,12 +1,9 @@
 package org.keycloak.models.mongo.impl;
 
 import org.keycloak.models.mongo.api.MongoEntity;
-import org.picketlink.common.properties.Property;
+import org.keycloak.models.utils.reflection.Property;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -14,24 +11,19 @@ import java.util.Map;
  */
 public class EntityInfo {
 
-    private final Class<? extends MongoEntity> entityClass;
+    private final Class<?> entityClass;
 
     private final String dbCollectionName;
 
     private final Map<String, Property<Object>> properties;
 
-    public EntityInfo(Class<? extends MongoEntity> entityClass, String dbCollectionName, List<Property<Object>> properties) {
+    public EntityInfo(Class<?> entityClass, String dbCollectionName, Map<String, Property<Object>> properties) {
         this.entityClass = entityClass;
         this.dbCollectionName = dbCollectionName;
-
-        Map<String, Property<Object>> props= new HashMap<String, Property<Object>>();
-        for (Property<Object> property : properties) {
-            props.put(property.getName(), property);
-        }
-        this.properties = Collections.unmodifiableMap(props);
+        this.properties = properties;
     }
 
-    public Class<? extends MongoEntity> getEntityClass() {
+    public Class<?> getEntityClass() {
         return entityClass;
     }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java
index e7468ad..79b0e95 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java
@@ -32,15 +32,16 @@ import org.keycloak.models.mongo.impl.types.MongoEntityMapper;
 import org.keycloak.models.mongo.impl.types.SimpleMapper;
 import org.keycloak.models.mongo.impl.types.StringToEnumMapper;
 import org.keycloak.models.utils.KeycloakModelUtils;
-import org.picketlink.common.properties.Property;
-import org.picketlink.common.properties.query.AnnotatedPropertyCriteria;
-import org.picketlink.common.properties.query.PropertyQueries;
+import org.keycloak.models.utils.reflection.AnnotatedPropertyCriteria;
+import org.keycloak.models.utils.reflection.Property;
+import org.keycloak.models.utils.reflection.PropertyQueries;
 
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -55,19 +56,19 @@ public class MongoStoreImpl implements MongoStore {
     private static final Logger logger = Logger.getLogger(MongoStoreImpl.class);
 
     private final MapperRegistry mapperRegistry;
-    private ConcurrentMap<Class<? extends MongoEntity>, EntityInfo> entityInfoCache =
-            new ConcurrentHashMap<Class<? extends MongoEntity>, EntityInfo>();
+    private ConcurrentMap<Class<?>, EntityInfo> entityInfoCache =
+            new ConcurrentHashMap<Class<?>, EntityInfo>();
 
 
-    public MongoStoreImpl(DB database, boolean clearCollectionsOnStartup, Class<? extends MongoEntity>[] managedEntityTypes) {
+    public MongoStoreImpl(DB database, boolean clearCollectionsOnStartup, Class<?>[] managedEntityTypes) {
         this.database = database;
 
         mapperRegistry = new MapperRegistry();
 
-        for (Class<?> simpleConverterClass : SIMPLE_TYPES) {
-            SimpleMapper converter = new SimpleMapper(simpleConverterClass);
-            mapperRegistry.addAppObjectMapper(converter);
-            mapperRegistry.addDBObjectMapper(converter);
+        for (Class<?> simpleMapperClass : SIMPLE_TYPES) {
+            SimpleMapper mapper = new SimpleMapper(simpleMapperClass);
+            mapperRegistry.addAppObjectMapper(mapper);
+            mapperRegistry.addDBObjectMapper(mapper);
         }
 
         // Specific converter for ArrayList is added just for performance purposes to avoid recursive converter lookup (most of list idm will be ArrayList)
@@ -83,7 +84,7 @@ public class MongoStoreImpl implements MongoStore {
         mapperRegistry.addAppObjectMapper(new EnumToStringMapper());
         mapperRegistry.addDBObjectMapper(new StringToEnumMapper());
 
-        for (Class<? extends MongoEntity> type : managedEntityTypes) {
+        for (Class<?> type : managedEntityTypes) {
             getEntityInfo(type);
             mapperRegistry.addAppObjectMapper(new MongoEntityMapper(this, mapperRegistry, type));
             mapperRegistry.addDBObjectMapper(new BasicDBObjectMapper(this, mapperRegistry, type));
@@ -102,9 +103,9 @@ public class MongoStoreImpl implements MongoStore {
         logger.info("Database " + this.database.getName() + " dropped in MongoDB");
     }
 
-    // Don't drop database, but just clear all data in managed collections (useful for development)
-    protected void clearManagedCollections(Class<? extends MongoEntity>[] managedEntityTypes) {
-        for (Class<? extends MongoEntity> clazz : managedEntityTypes) {
+    // Don't drop database, but just clear all data in managed collections (useful for export/import or during development)
+    protected void clearManagedCollections(Class<?>[] managedEntityTypes) {
+        for (Class<?> clazz : managedEntityTypes) {
             DBCollection dbCollection = getDBCollectionForType(clazz);
             if (dbCollection != null) {
                 dbCollection.remove(new BasicDBObject());
@@ -113,8 +114,8 @@ public class MongoStoreImpl implements MongoStore {
         }
     }
 
-    protected void initManagedCollections(Class<? extends MongoEntity>[] managedEntityTypes) {
-        for (Class<? extends MongoEntity> clazz : managedEntityTypes) {
+    protected void initManagedCollections(Class<?>[] managedEntityTypes) {
+        for (Class<?> clazz : managedEntityTypes) {
             EntityInfo entityInfo = getEntityInfo(clazz);
             String dbCollectionName = entityInfo.getDbCollectionName();
             if (dbCollectionName != null && !database.collectionExists(dbCollectionName)) {
@@ -416,6 +417,13 @@ public class MongoStoreImpl implements MongoStore {
         }
     }
 
+    @Override
+    public void removeAllEntities() {
+        Set<Class<?>> managedTypes = this.entityInfoCache.keySet();
+        Class<? extends MongoEntity>[] arrayTemplate = (Class<? extends MongoEntity>[])new Class<?>[0];
+        this.clearManagedCollections(managedTypes.toArray(arrayTemplate));
+    }
+
     // Possibility to add user-defined mappers
     public void addAppObjectConverter(Mapper<?, ?> mapper) {
         mapperRegistry.addAppObjectMapper(mapper);
@@ -425,10 +433,10 @@ public class MongoStoreImpl implements MongoStore {
         mapperRegistry.addDBObjectMapper(mapper);
     }
 
-    public EntityInfo getEntityInfo(Class<? extends MongoEntity> entityClass) {
+    public EntityInfo getEntityInfo(Class<?> entityClass) {
         EntityInfo entityInfo = entityInfoCache.get(entityClass);
         if (entityInfo == null) {
-            List<Property<Object>> properties = PropertyQueries.createQuery(entityClass).addCriteria(new AnnotatedPropertyCriteria(MongoField.class)).getResultList();
+            Map<String, Property<Object>> properties = PropertyQueries.createQuery(entityClass).getWritableResultList();
 
             MongoCollection classAnnotation = entityClass.getAnnotation(MongoCollection.class);
 
@@ -473,7 +481,7 @@ public class MongoStoreImpl implements MongoStore {
         return object;
     }
 
-    protected DBCollection getDBCollectionForType(Class<? extends MongoEntity> type) {
+    protected DBCollection getDBCollectionForType(Class<?> type) {
         EntityInfo entityInfo = getEntityInfo(type);
         String dbCollectionName = entityInfo.getDbCollectionName();
         return dbCollectionName==null ? null : database.getCollection(dbCollectionName);
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBObjectMapper.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBObjectMapper.java
index 19cfa06..2d0adc0 100644
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBObjectMapper.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/BasicDBObjectMapper.java
@@ -14,13 +14,13 @@ import org.keycloak.models.mongo.api.types.MapperContext;
 import org.keycloak.models.mongo.api.types.MapperRegistry;
 import org.keycloak.models.mongo.impl.MongoStoreImpl;
 import org.keycloak.models.mongo.impl.EntityInfo;
-import org.picketlink.common.properties.Property;
-import org.picketlink.common.reflection.Types;
+import org.keycloak.models.utils.reflection.Property;
+import org.keycloak.models.utils.reflection.Types;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class BasicDBObjectMapper<S extends MongoEntity> implements Mapper<BasicDBObject, S> {
+public class BasicDBObjectMapper<S> implements Mapper<BasicDBObject, S> {
 
     private static final Logger logger = Logger.getLogger(BasicDBObjectMapper.class);
 
@@ -73,7 +73,7 @@ public class BasicDBObjectMapper<S extends MongoEntity> implements Mapper<BasicD
         return entity;
     }
 
-    private void setPropertyValue(MongoEntity entity, Object valueFromDB, Property property) {
+    private void setPropertyValue(Object entity, Object valueFromDB, Property property) {
         if (valueFromDB == null) {
             property.setValue(entity, null);
             return;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/MongoEntityMapper.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/MongoEntityMapper.java
index 1d3d665..b9f71ab 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/MongoEntityMapper.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/types/MongoEntityMapper.java
@@ -1,20 +1,19 @@
 package org.keycloak.models.mongo.impl.types;
 
 import com.mongodb.BasicDBObject;
-import org.keycloak.models.mongo.api.MongoEntity;
 import org.keycloak.models.mongo.api.types.Mapper;
 import org.keycloak.models.mongo.api.types.MapperContext;
 import org.keycloak.models.mongo.api.types.MapperRegistry;
 import org.keycloak.models.mongo.impl.MongoStoreImpl;
 import org.keycloak.models.mongo.impl.EntityInfo;
-import org.picketlink.common.properties.Property;
+import org.keycloak.models.utils.reflection.Property;
 
 import java.util.Collection;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class MongoEntityMapper<T extends MongoEntity> implements Mapper<T, BasicDBObject> {
+public class MongoEntityMapper<T> implements Mapper<T, BasicDBObject> {
 
     private final MongoStoreImpl mongoStoreImpl;
     private final MapperRegistry mapperRegistry;
@@ -37,11 +36,14 @@ public class MongoEntityMapper<T extends MongoEntity> implements Mapper<T, Basic
         Collection<Property<Object>> props = entityInfo.getProperties();
         for (Property<Object> property : props) {
             String propName = property.getName();
-            Object propValue = property.getValue(applicationObject);
 
-            if (propValue != null) {
-                Object dbValue = mapperRegistry.convertApplicationObjectToDBObject(propValue, Object.class);
-                dbObject.put(propName, dbValue);
+            // Ignore "id" property
+            if (!"id".equals(propName)) {
+                Object propValue = property.getValue(applicationObject);
+                if (propValue != null) {
+                    Object dbValue = propValue == null ? null : mapperRegistry.convertApplicationObjectToDBObject(propValue, Object.class);
+                    dbObject.put(propName, dbValue);
+                }
             }
         }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/AbstractMongoAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/AbstractMongoAdapter.java
index 6fcae4c..42b10cd 100644
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/AbstractMongoAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/AbstractMongoAdapter.java
@@ -1,13 +1,13 @@
 package org.keycloak.models.mongo.keycloak.adapters;
 
-import org.keycloak.models.mongo.api.AbstractMongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public abstract class AbstractMongoAdapter<T extends AbstractMongoIdentifiableEntity> {
+public abstract class AbstractMongoAdapter<T extends MongoIdentifiableEntity> {
 
     protected final MongoStoreInvocationContext invocationContext;
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
index 8369432..c30db32 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
@@ -8,8 +8,8 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.ApplicationEntity;
-import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.mongo.utils.MongoModelUtils;
 
 import java.util.ArrayList;
@@ -20,9 +20,9 @@ import java.util.Set;
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> implements ApplicationModel {
+public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> implements ApplicationModel {
 
-    public ApplicationAdapter(RealmModel realm, ApplicationEntity applicationEntity, MongoStoreInvocationContext invContext) {
+    public ApplicationAdapter(RealmModel realm, MongoApplicationEntity applicationEntity, MongoStoreInvocationContext invContext) {
         super(realm, applicationEntity, invContext);
     }
 
@@ -103,7 +103,7 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
                 .and("name").is(name)
                 .and("applicationId").is(getId())
                 .get();
-        RoleEntity role = getMongoStore().loadSingleEntity(RoleEntity.class, query, invocationContext);
+        MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext);
         if (role == null) {
             return null;
         } else {
@@ -113,7 +113,13 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
 
     @Override
     public RoleAdapter addRole(String name) {
-        RoleEntity roleEntity = new RoleEntity();
+        return this.addRole(null, name);
+    }
+
+    @Override
+    public RoleAdapter addRole(String id, String name) {
+        MongoRoleEntity roleEntity = new MongoRoleEntity();
+        roleEntity.setId(id);
         roleEntity.setName(name);
         roleEntity.setApplicationId(getId());
 
@@ -124,7 +130,7 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
 
     @Override
     public boolean removeRole(RoleModel role) {
-        return getMongoStore().removeEntity(RoleEntity.class, role.getId(), invocationContext);
+        return getMongoStore().removeEntity(MongoRoleEntity.class, role.getId(), invocationContext);
     }
 
     @Override
@@ -132,10 +138,10 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
         DBObject query = new QueryBuilder()
                 .and("applicationId").is(getId())
                 .get();
-        List<RoleEntity> roles = getMongoStore().loadEntities(RoleEntity.class, query, invocationContext);
+        List<MongoRoleEntity> roles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext);
 
         Set<RoleModel> result = new HashSet<RoleModel>();
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
         }
 
@@ -145,9 +151,9 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
     @Override
     public Set<RoleModel> getApplicationRoleMappings(UserModel user) {
         Set<RoleModel> result = new HashSet<RoleModel>();
-        List<RoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
 
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             if (getId().equals(role.getApplicationId())) {
                 result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
             }
@@ -158,9 +164,9 @@ public class ApplicationAdapter extends ClientAdapter<ApplicationEntity> impleme
     @Override
     public Set<RoleModel> getApplicationScopeMappings(ClientModel client) {
         Set<RoleModel> result = new HashSet<RoleModel>();
-        List<RoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
 
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             if (getId().equals(role.getApplicationId())) {
                 result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
             }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 181b812..f651f3a 100644
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -7,13 +7,14 @@ import java.util.Set;
 
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.entities.ClientEntity;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.ClientEntity;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<T> implements ClientModel {
+public class ClientAdapter<T extends MongoIdentifiableEntity> extends AbstractMongoAdapter<T> implements ClientModel {
 
     protected final T clientEntity;
     private final RealmModel realm;
@@ -29,6 +30,11 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
         return clientEntity;
     }
 
+    // ClientEntity doesn't extend MongoIdentifiableEntity
+    public ClientEntity getMongoEntityAsClient() {
+        return (ClientEntity)getMongoEntity();
+    }
+
     @Override
     public String getId() {
         return getMongoEntity().getId();
@@ -36,25 +42,25 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
 
     @Override
     public String getClientId() {
-        return getMongoEntity().getName();
+        return getMongoEntityAsClient().getName();
     }
 
     @Override
     public long getAllowedClaimsMask() {
-        return getMongoEntity().getAllowedClaimsMask();
+        return getMongoEntityAsClient().getAllowedClaimsMask();
     }
 
     @Override
     public void setAllowedClaimsMask(long mask) {
-        getMongoEntity().setAllowedClaimsMask(mask);
+        getMongoEntityAsClient().setAllowedClaimsMask(mask);
         updateMongoEntity();
     }
 
     @Override
     public Set<String> getWebOrigins() {
         Set<String> result = new HashSet<String>();
-        if (getMongoEntity().getWebOrigins() != null) {
-            result.addAll(clientEntity.getWebOrigins());
+        if (getMongoEntityAsClient().getWebOrigins() != null) {
+            result.addAll(getMongoEntityAsClient().getWebOrigins());
         }
         return result;
     }
@@ -63,7 +69,7 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
     public void setWebOrigins(Set<String> webOrigins) {
         List<String> result = new ArrayList<String>();
         result.addAll(webOrigins);
-        clientEntity.setWebOrigins(result);
+        getMongoEntityAsClient().setWebOrigins(result);
         updateMongoEntity();
     }
 
@@ -80,8 +86,8 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
     @Override
     public Set<String> getRedirectUris() {
         Set<String> result = new HashSet<String>();
-        if (clientEntity.getRedirectUris() != null) {
-            result.addAll(clientEntity.getRedirectUris());
+        if (getMongoEntityAsClient().getRedirectUris() != null) {
+            result.addAll(getMongoEntityAsClient().getRedirectUris());
         }
         return result;
     }
@@ -90,7 +96,7 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
     public void setRedirectUris(Set<String> redirectUris) {
         List<String> result = new ArrayList<String>();
         result.addAll(redirectUris);
-        clientEntity.setRedirectUris(result);
+        getMongoEntityAsClient().setRedirectUris(result);
         updateMongoEntity();
     }
 
@@ -106,39 +112,39 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
 
     @Override
     public boolean isEnabled() {
-        return clientEntity.isEnabled();
+        return getMongoEntityAsClient().isEnabled();
     }
 
     @Override
     public void setEnabled(boolean enabled) {
-        clientEntity.setEnabled(enabled);
+        getMongoEntityAsClient().setEnabled(enabled);
         updateMongoEntity();
     }
 
     @Override
     public boolean validateSecret(String secret) {
-        return secret.equals(clientEntity.getSecret());
+        return secret.equals(getMongoEntityAsClient().getSecret());
     }
 
     @Override
     public String getSecret() {
-        return clientEntity.getSecret();
+        return getMongoEntityAsClient().getSecret();
     }
 
     @Override
     public void setSecret(String secret) {
-        clientEntity.setSecret(secret);
+        getMongoEntityAsClient().setSecret(secret);
         updateMongoEntity();
     }
 
     @Override
     public boolean isPublicClient() {
-        return clientEntity.isPublicClient();
+        return getMongoEntityAsClient().isPublicClient();
     }
 
     @Override
     public void setPublicClient(boolean flag) {
-        clientEntity.setPublicClient(flag);
+        getMongoEntityAsClient().setPublicClient(flag);
         updateMongoEntity();
     }
 
@@ -149,12 +155,12 @@ public class ClientAdapter<T extends ClientEntity> extends AbstractMongoAdapter<
 
     @Override
     public int getNotBefore() {
-        return clientEntity.getNotBefore();
+        return getMongoEntityAsClient().getNotBefore();
     }
 
     @Override
     public void setNotBefore(int notBefore) {
-        clientEntity.setNotBefore(notBefore);
+        getMongoEntityAsClient().setNotBefore(notBefore);
         updateMongoEntity();
     }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
index e8baa31..0c13eb9 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
@@ -9,7 +9,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.RealmEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import java.util.ArrayList;
@@ -40,13 +40,18 @@ public class MongoKeycloakSession implements KeycloakSession {
     }
 
     @Override
+    public void removeAllData() {
+        getMongoStore().removeAllEntities();
+    }
+
+    @Override
     public RealmModel createRealm(String name) {
         return createRealm(KeycloakModelUtils.generateId(), name);
     }
 
     @Override
     public RealmModel createRealm(String id, String name) {
-        RealmEntity newRealm = new RealmEntity();
+        MongoRealmEntity newRealm = new MongoRealmEntity();
         newRealm.setId(id);
         newRealm.setName(name);
 
@@ -57,17 +62,17 @@ public class MongoKeycloakSession implements KeycloakSession {
 
     @Override
     public RealmModel getRealm(String id) {
-        RealmEntity realmEntity = getMongoStore().loadEntity(RealmEntity.class, id, invocationContext);
+        MongoRealmEntity realmEntity = getMongoStore().loadEntity(MongoRealmEntity.class, id, invocationContext);
         return realmEntity != null ? new RealmAdapter(realmEntity, invocationContext) : null;
     }
 
     @Override
     public List<RealmModel> getRealms() {
         DBObject query = new BasicDBObject();
-        List<RealmEntity> realms = getMongoStore().loadEntities(RealmEntity.class, query, invocationContext);
+        List<MongoRealmEntity> realms = getMongoStore().loadEntities(MongoRealmEntity.class, query, invocationContext);
 
         List<RealmModel> results = new ArrayList<RealmModel>();
-        for (RealmEntity realmEntity : realms) {
+        for (MongoRealmEntity realmEntity : realms) {
             results.add(new RealmAdapter(realmEntity, invocationContext));
         }
         return results;
@@ -78,7 +83,7 @@ public class MongoKeycloakSession implements KeycloakSession {
         DBObject query = new QueryBuilder()
                 .and("name").is(name)
                 .get();
-        RealmEntity realm = getMongoStore().loadSingleEntity(RealmEntity.class, query, invocationContext);
+        MongoRealmEntity realm = getMongoStore().loadSingleEntity(MongoRealmEntity.class, query, invocationContext);
 
         if (realm == null) return null;
         return new RealmAdapter(realm, invocationContext);
@@ -86,7 +91,7 @@ public class MongoKeycloakSession implements KeycloakSession {
 
     @Override
     public boolean removeRealm(String id) {
-        return getMongoStore().removeEntity(RealmEntity.class, id, invocationContext);
+        return getMongoStore().removeEntity(MongoRealmEntity.class, id, invocationContext);
     }
 
     protected MongoStore getMongoStore() {
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
index dcd787d..d431803 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSessionFactory.java
@@ -3,20 +3,20 @@ package org.keycloak.models.mongo.keycloak.adapters;
 import org.jboss.logging.Logger;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.mongo.api.MongoEntity;
+import org.keycloak.models.entities.AuthenticationLinkEntity;
+import org.keycloak.models.entities.AuthenticationProviderEntity;
+import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.RequiredCredentialEntity;
+import org.keycloak.models.entities.SocialLinkEntity;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.impl.MongoStoreImpl;
 import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
-import org.keycloak.models.mongo.keycloak.entities.ApplicationEntity;
-import org.keycloak.models.mongo.keycloak.entities.AuthenticationLinkEntity;
-import org.keycloak.models.mongo.keycloak.entities.AuthenticationProviderEntity;
-import org.keycloak.models.mongo.keycloak.entities.CredentialEntity;
-import org.keycloak.models.mongo.keycloak.entities.OAuthClientEntity;
-import org.keycloak.models.mongo.keycloak.entities.RealmEntity;
-import org.keycloak.models.mongo.keycloak.entities.RequiredCredentialEntity;
-import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
-import org.keycloak.models.mongo.keycloak.entities.SocialLinkEntity;
-import org.keycloak.models.mongo.keycloak.entities.UserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
 
 /**
  * KeycloakSessionFactory implementation based on MongoDB
@@ -26,17 +26,18 @@ import org.keycloak.models.mongo.keycloak.entities.UserEntity;
 public class MongoKeycloakSessionFactory implements KeycloakSessionFactory {
     protected static final Logger logger = Logger.getLogger(MongoKeycloakSessionFactory.class);
 
-    private static final Class<? extends MongoEntity>[] MANAGED_ENTITY_TYPES = (Class<? extends MongoEntity>[])new Class<?>[] {
-            RealmEntity.class,
-            UserEntity.class,
-            RoleEntity.class,
+    private static final Class<?>[] MANAGED_ENTITY_TYPES = (Class<?>[])new Class<?>[] {
+            MongoRealmEntity.class,
+            MongoUserEntity.class,
+            MongoRoleEntity.class,
             RequiredCredentialEntity.class,
             AuthenticationProviderEntity.class,
             CredentialEntity.class,
             SocialLinkEntity.class,
             AuthenticationLinkEntity.class,
-            ApplicationEntity.class,
-            OAuthClientEntity.class
+            MongoApplicationEntity.class,
+            MongoOAuthClientEntity.class,
+            MongoUsernameLoginFailureEntity.class
     };
 
     private final MongoClientProvider mongoClientProvider;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
index b9b5e04..fbb2b3e 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
@@ -3,14 +3,14 @@ package org.keycloak.models.mongo.keycloak.adapters;
 import org.keycloak.models.OAuthClientModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.OAuthClientEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class OAuthClientAdapter extends ClientAdapter<OAuthClientEntity> implements OAuthClientModel {
+public class OAuthClientAdapter extends ClientAdapter<MongoOAuthClientEntity> implements OAuthClientModel {
 
-    public OAuthClientAdapter(RealmModel realm, OAuthClientEntity oauthClientEntity, MongoStoreInvocationContext invContext) {
+    public OAuthClientAdapter(RealmModel realm, MongoOAuthClientEntity oauthClientEntity, MongoStoreInvocationContext invContext) {
         super(realm, oauthClientEntity, invContext);
     }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 10793bd..52308de 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -14,19 +14,21 @@ import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.SocialLinkModel;
 import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.entities.AuthenticationLinkEntity;
+import org.keycloak.models.entities.AuthenticationProviderEntity;
+import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.RequiredCredentialEntity;
+import org.keycloak.models.entities.SocialLinkEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.ApplicationEntity;
-import org.keycloak.models.mongo.keycloak.entities.AuthenticationLinkEntity;
-import org.keycloak.models.mongo.keycloak.entities.AuthenticationProviderEntity;
-import org.keycloak.models.mongo.keycloak.entities.CredentialEntity;
-import org.keycloak.models.mongo.keycloak.entities.OAuthClientEntity;
-import org.keycloak.models.mongo.keycloak.entities.RealmEntity;
-import org.keycloak.models.mongo.keycloak.entities.RequiredCredentialEntity;
-import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
-import org.keycloak.models.mongo.keycloak.entities.SocialLinkEntity;
-import org.keycloak.models.mongo.keycloak.entities.UserEntity;
-import org.keycloak.models.mongo.keycloak.entities.UsernameLoginFailureEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
 import org.keycloak.models.mongo.utils.MongoModelUtils;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
@@ -39,7 +41,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -48,18 +49,18 @@ import java.util.regex.Pattern;
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements RealmModel {
+public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> implements RealmModel {
 
     private static final Logger logger = Logger.getLogger(RealmAdapter.class);
 
-    private final RealmEntity realm;
+    private final MongoRealmEntity realm;
 
     protected volatile transient PublicKey publicKey;
     protected volatile transient PrivateKey privateKey;
 
     private volatile transient PasswordPolicy passwordPolicy;
 
-    public RealmAdapter(RealmEntity realmEntity, MongoStoreInvocationContext invocationContext) {
+    public RealmAdapter(MongoRealmEntity realmEntity, MongoStoreInvocationContext invocationContext) {
         super(invocationContext);
         this.realm = realmEntity;
     }
@@ -132,6 +133,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setBruteForceProtected(boolean value) {
         realm.setBruteForceProtected(value);
+        updateRealm();
     }
 
     @Override
@@ -142,6 +144,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setMaxFailureWaitSeconds(int val) {
         realm.setMaxFailureWaitSeconds(val);
+        updateRealm();
     }
 
     @Override
@@ -152,6 +155,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setWaitIncrementSeconds(int val) {
         realm.setWaitIncrementSeconds(val);
+        updateRealm();
     }
 
     @Override
@@ -162,6 +166,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setQuickLoginCheckMilliSeconds(long val) {
         realm.setQuickLoginCheckMilliSeconds(val);
+        updateRealm();
     }
 
     @Override
@@ -172,6 +177,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setMinimumQuickLoginWaitSeconds(int val) {
         realm.setMinimumQuickLoginWaitSeconds(val);
+        updateRealm();
     }
 
 
@@ -183,6 +189,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setMaxDeltaTimeSeconds(int val) {
         realm.setMaxDeltaTimeSeconds(val);
+        updateRealm();
     }
 
     @Override
@@ -193,6 +200,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     @Override
     public void setFailureFactor(int failureFactor) {
         realm.setFailureFactor(failureFactor);
+        updateRealm();
     }
 
 
@@ -403,7 +411,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("loginName").is(name)
                 .and("realmId").is(getId())
                 .get();
-        UserEntity user = getMongoStore().loadSingleEntity(UserEntity.class, query, invocationContext);
+        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
 
         if (user == null) {
             return null;
@@ -418,7 +426,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("username").is(name)
                 .and("realmId").is(getId())
                 .get();
-        UsernameLoginFailureEntity user = getMongoStore().loadSingleEntity(UsernameLoginFailureEntity.class, query, invocationContext);
+        MongoUsernameLoginFailureEntity user = getMongoStore().loadSingleEntity(MongoUsernameLoginFailureEntity.class, query, invocationContext);
 
         if (user == null) {
             return null;
@@ -434,10 +442,8 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
             return userLoginFailure;
         }
 
-        UsernameLoginFailureEntity userEntity = new UsernameLoginFailureEntity();
+        MongoUsernameLoginFailureEntity userEntity = new MongoUsernameLoginFailureEntity();
         userEntity.setUsername(username);
-        // Compatibility with JPA model, which has user disabled by default
-        // userEntity.setEnabled(true);
         userEntity.setRealmId(getId());
 
         getMongoStore().insertEntity(userEntity, invocationContext);
@@ -445,12 +451,29 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     }
 
     @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        DBObject query = new QueryBuilder()
+                .and("realmId").is(getId())
+                .get();
+        List<MongoUsernameLoginFailureEntity> failures = getMongoStore().loadEntities(MongoUsernameLoginFailureEntity.class, query, invocationContext);
+
+        List<UsernameLoginFailureModel> result = new ArrayList<UsernameLoginFailureModel>();
+
+        if (failures == null) return result;
+        for (MongoUsernameLoginFailureEntity failure : failures) {
+            result.add(new UsernameLoginFailureAdapter(invocationContext, failure));
+        }
+
+        return result;
+    }
+
+    @Override
     public UserModel getUserByEmail(String email) {
         DBObject query = new QueryBuilder()
                 .and("email").is(email)
                 .and("realmId").is(getId())
                 .get();
-        UserEntity user = getMongoStore().loadSingleEntity(UserEntity.class, query, invocationContext);
+        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
 
         if (user == null) {
             return null;
@@ -461,7 +484,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public UserModel getUserById(String id) {
-        UserEntity user = getMongoStore().loadEntity(UserEntity.class, id, invocationContext);
+        MongoUserEntity user = getMongoStore().loadEntity(MongoUserEntity.class, id, invocationContext);
 
         // Check that it's user from this realm
         if (user == null || !getId().equals(user.getRealmId())) {
@@ -473,7 +496,12 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public UserAdapter addUser(String username) {
-        UserAdapter userModel = addUserEntity(username);
+        return this.addUser(null, username);
+    }
+
+    @Override
+    public UserAdapter addUser(String id, String username) {
+        UserAdapter userModel = addUserEntity(id, username);
 
         for (String r : getDefaultRoles()) {
             grantRole(userModel, getRole(r));
@@ -488,9 +516,9 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         return userModel;
     }
 
-    // Add just user entity without defaultRoles
-    protected UserAdapter addUserEntity(String username) {
-        UserEntity userEntity = new UserEntity();
+    protected UserAdapter addUserEntity(String id, String username) {
+        MongoUserEntity userEntity = new MongoUserEntity();
+        userEntity.setId(id);
         userEntity.setLoginName(username);
         // Compatibility with JPA model, which has user disabled by default
         // userEntity.setEnabled(true);
@@ -506,7 +534,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("loginName").is(name)
                 .and("realmId").is(getId())
                 .get();
-        return getMongoStore().removeEntities(UserEntity.class, query, invocationContext);
+        return getMongoStore().removeEntities(MongoUserEntity.class, query, invocationContext);
     }
 
     @Override
@@ -515,7 +543,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("name").is(name)
                 .and("realmId").is(getId())
                 .get();
-        RoleEntity role = getMongoStore().loadSingleEntity(RoleEntity.class, query, invocationContext);
+        MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext);
         if (role == null) {
             return null;
         } else {
@@ -525,7 +553,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public RoleModel addRole(String name) {
-        RoleEntity roleEntity = new RoleEntity();
+        return this.addRole(null, name);
+    }
+
+    @Override
+    public RoleModel addRole(String id, String name) {
+        MongoRoleEntity roleEntity = new MongoRoleEntity();
+        roleEntity.setId(id);
         roleEntity.setName(name);
         roleEntity.setRealmId(getId());
 
@@ -541,7 +575,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public boolean removeRoleById(String id) {
-        return getMongoStore().removeEntity(RoleEntity.class, id, invocationContext);
+        return getMongoStore().removeEntity(MongoRoleEntity.class, id, invocationContext);
     }
 
     @Override
@@ -549,12 +583,12 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         DBObject query = new QueryBuilder()
                 .and("realmId").is(getId())
                 .get();
-        List<RoleEntity> roles = getMongoStore().loadEntities(RoleEntity.class, query, invocationContext);
+        List<MongoRoleEntity> roles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext);
 
         Set<RoleModel> result = new HashSet<RoleModel>();
 
         if (roles == null) return result;
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             result.add(new RoleAdapter(this, role, this, invocationContext));
         }
 
@@ -563,7 +597,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public RoleModel getRoleById(String id) {
-        RoleEntity role = getMongoStore().loadEntity(RoleEntity.class, id, invocationContext);
+        MongoRoleEntity role = getMongoStore().loadEntity(MongoRoleEntity.class, id, invocationContext);
         if (role == null) return null;
         if (role.getRealmId() != null) {
             if (!role.getRealmId().equals(this.getId())) return null;
@@ -615,7 +649,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public ApplicationModel getApplicationById(String id) {
-        ApplicationEntity appData = getMongoStore().loadEntity(ApplicationEntity.class, id, invocationContext);
+        MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, id, invocationContext);
 
         // Check if application belongs to this realm
         if (appData == null || !getId().equals(appData.getRealmId())) {
@@ -631,7 +665,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("realmId").is(getId())
                 .and("name").is(name)
                 .get();
-        ApplicationEntity appEntity = getMongoStore().loadSingleEntity(ApplicationEntity.class, query, invocationContext);
+        MongoApplicationEntity appEntity = getMongoStore().loadSingleEntity(MongoApplicationEntity.class, query, invocationContext);
         return appEntity == null ? null : new ApplicationAdapter(this, appEntity, invocationContext);
     }
 
@@ -649,10 +683,10 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         DBObject query = new QueryBuilder()
                 .and("realmId").is(getId())
                 .get();
-        List<ApplicationEntity> appDatas = getMongoStore().loadEntities(ApplicationEntity.class, query, invocationContext);
+        List<MongoApplicationEntity> appDatas = getMongoStore().loadEntities(MongoApplicationEntity.class, query, invocationContext);
 
         List<ApplicationModel> result = new ArrayList<ApplicationModel>();
-        for (ApplicationEntity appData : appDatas) {
+        for (MongoApplicationEntity appData : appDatas) {
             result.add(new ApplicationAdapter(this, appData, invocationContext));
         }
         return result;
@@ -660,7 +694,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public ApplicationModel addApplication(String name) {
-        ApplicationEntity appData = new ApplicationEntity();
+        return this.addApplication(null, name);
+    }
+
+    @Override
+    public ApplicationModel addApplication(String id, String name) {
+        MongoApplicationEntity appData = new MongoApplicationEntity();
+        appData.setId(id);
         appData.setName(name);
         appData.setRealmId(getId());
         appData.setEnabled(true);
@@ -671,7 +711,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public boolean removeApplication(String id) {
-        return getMongoStore().removeEntity(ApplicationEntity.class, id, invocationContext);
+        return getMongoStore().removeEntity(MongoApplicationEntity.class, id, invocationContext);
     }
 
     @Override
@@ -687,16 +727,16 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public void grantRole(UserModel user, RoleModel role) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         getMongoStore().pushItemToList(userEntity, "roleIds", role.getId(), true, invocationContext);
     }
 
     @Override
     public Set<RoleModel> getRoleMappings(UserModel user) {
         Set<RoleModel> result = new HashSet<RoleModel>();
-        List<RoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
 
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             if (getId().equals(role.getRealmId())) {
                 result.add(new RoleAdapter(this, role, this, invocationContext));
             } else {
@@ -714,7 +754,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
         Set<RoleModel> realmRoles = new HashSet<RoleModel>();
         for (RoleModel role : allRoles) {
-            RoleEntity roleEntity = ((RoleAdapter) role).getRole();
+            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
 
             if (getId().equals(roleEntity.getRealmId())) {
                 realmRoles.add(role);
@@ -727,16 +767,16 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
     public void deleteRoleMapping(UserModel user, RoleModel role) {
         if (user == null || role == null) return;
 
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         getMongoStore().pullItemFromList(userEntity, "roleIds", role.getId(), invocationContext);
     }
 
     @Override
     public Set<RoleModel> getScopeMappings(ClientModel client) {
         Set<RoleModel> result = new HashSet<RoleModel>();
-        List<RoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
 
-        for (RoleEntity role : roles) {
+        for (MongoRoleEntity role : roles) {
             if (getId().equals(role.getRealmId())) {
                 result.add(new RoleAdapter(this, role, this, invocationContext));
             } else {
@@ -754,7 +794,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
         Set<RoleModel> realmRoles = new HashSet<RoleModel>();
         for (RoleModel role : allScopes) {
-            RoleEntity roleEntity = ((RoleAdapter) role).getRole();
+            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
 
             if (getId().equals(roleEntity.getRealmId())) {
                 realmRoles.add(role);
@@ -787,7 +827,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public OAuthClientModel addOAuthClient(String name) {
-        OAuthClientEntity oauthClient = new OAuthClientEntity();
+        return this.addOAuthClient(null, name);
+    }
+
+    @Override
+    public OAuthClientModel addOAuthClient(String id, String name) {
+        MongoOAuthClientEntity oauthClient = new MongoOAuthClientEntity();
+        oauthClient.setId(id);
         oauthClient.setRealmId(getId());
         oauthClient.setName(name);
         getMongoStore().insertEntity(oauthClient, invocationContext);
@@ -797,7 +843,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public boolean removeOAuthClient(String id) {
-        return getMongoStore().removeEntity(OAuthClientEntity.class, id, invocationContext);
+        return getMongoStore().removeEntity(MongoOAuthClientEntity.class, id, invocationContext);
     }
 
     @Override
@@ -806,13 +852,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("realmId").is(getId())
                 .and("name").is(name)
                 .get();
-        OAuthClientEntity oauthClient = getMongoStore().loadSingleEntity(OAuthClientEntity.class, query, invocationContext);
+        MongoOAuthClientEntity oauthClient = getMongoStore().loadSingleEntity(MongoOAuthClientEntity.class, query, invocationContext);
         return oauthClient == null ? null : new OAuthClientAdapter(this, oauthClient, invocationContext);
     }
 
     @Override
     public OAuthClientModel getOAuthClientById(String id) {
-        OAuthClientEntity clientEntity = getMongoStore().loadEntity(OAuthClientEntity.class, id, invocationContext);
+        MongoOAuthClientEntity clientEntity = getMongoStore().loadEntity(MongoOAuthClientEntity.class, id, invocationContext);
 
         // Check if client belongs to this realm
         if (clientEntity == null || !getId().equals(clientEntity.getRealmId())) return null;
@@ -825,9 +871,9 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         DBObject query = new QueryBuilder()
                 .and("realmId").is(getId())
                 .get();
-        List<OAuthClientEntity> results = getMongoStore().loadEntities(OAuthClientEntity.class, query, invocationContext);
+        List<MongoOAuthClientEntity> results = getMongoStore().loadEntities(MongoOAuthClientEntity.class, query, invocationContext);
         List<OAuthClientModel> list = new ArrayList<OAuthClientModel>();
-        for (OAuthClientEntity data : results) {
+        for (MongoOAuthClientEntity data : results) {
             list.add(new OAuthClientAdapter(this, data, invocationContext));
         }
         return list;
@@ -923,13 +969,8 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public void updateCredential(UserModel user, UserCredentialModel cred) {
-        CredentialEntity credentialEntity = null;
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        for (CredentialEntity entity : userEntity.getCredentials()) {
-            if (entity.getType().equals(cred.getType())) {
-                credentialEntity = entity;
-            }
-        }
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+        CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType());
 
         if (credentialEntity == null) {
             credentialEntity = new CredentialEntity();
@@ -949,6 +990,52 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         getMongoStore().updateEntity(userEntity, invocationContext);
     }
 
+    private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) {
+        for (CredentialEntity entity : userEntity.getCredentials()) {
+            if (entity.getType().equals(credType)) {
+                return entity;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly(UserModel user) {
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+        List<CredentialEntity> credentials = userEntity.getCredentials();
+        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
+        for (CredentialEntity credEntity : credentials) {
+            UserCredentialValueModel credModel = new UserCredentialValueModel();
+            credModel.setType(credEntity.getType());
+            credModel.setDevice(credEntity.getDevice());
+            credModel.setValue(credEntity.getValue());
+            credModel.setSalt(credEntity.getSalt());
+
+            result.add(credModel);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) {
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+        CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(credModel.getType());
+            userEntity.getCredentials().add(credentialEntity);
+        }
+
+        credentialEntity.setValue(credModel.getValue());
+        credentialEntity.setSalt(credModel.getSalt());
+        credentialEntity.setDevice(credModel.getDevice());
+
+        getMongoStore().updateEntity(userEntity, invocationContext);
+    }
+
     @Override
     public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
         DBObject query = new QueryBuilder()
@@ -956,13 +1043,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 .and("socialLinks.socialUserId").is(socialLink.getSocialUserId())
                 .and("realmId").is(getId())
                 .get();
-        UserEntity userEntity = getMongoStore().loadSingleEntity(UserEntity.class, query, invocationContext);
+        MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
         return userEntity == null ? null : new UserAdapter(userEntity, invocationContext);
     }
 
     @Override
     public Set<SocialLinkModel> getSocialLinks(UserModel user) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
 
         if (linkEntities == null) {
@@ -985,7 +1072,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         SocialLinkEntity socialLinkEntity = new SocialLinkEntity();
         socialLinkEntity.setSocialProvider(socialLink.getSocialProvider());
         socialLinkEntity.setSocialUserId(socialLink.getSocialUserId());
@@ -1000,13 +1087,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         if (socialLinkEntity == null) {
             return false;
         }
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
 
         return getMongoStore().pullItemFromList(userEntity, "socialLinks", socialLinkEntity, invocationContext);
     }
 
     private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
         if (linkEntities == null) {
             return null;
@@ -1022,7 +1109,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public AuthenticationLinkModel getAuthenticationLink(UserModel user) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         AuthenticationLinkEntity authLinkEntity = userEntity.getAuthenticationLink();
 
         if (authLinkEntity == null) {
@@ -1034,7 +1121,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
         AuthenticationLinkEntity authLinkEntity = new AuthenticationLinkEntity();
         authLinkEntity.setAuthProvider(authenticationLink.getAuthProvider());
         authLinkEntity.setAuthUserId(authenticationLink.getAuthUserId());
@@ -1060,7 +1147,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
         DBObject query = new QueryBuilder()
                 .and("realmId").is(getId())
                 .get();
-        List<UserEntity> users = getMongoStore().loadEntities(UserEntity.class, query, invocationContext);
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, query, invocationContext);
         return convertUserEntities(users);
     }
 
@@ -1100,7 +1187,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 ).get()
         );
 
-        List<UserEntity> users = getMongoStore().loadEntities(UserEntity.class, builder.get(), invocationContext);
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, builder.get(), invocationContext);
         return convertUserEntities(users);
     }
 
@@ -1122,13 +1209,13 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
                 queryBuilder.and(UserModel.EMAIL).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
             }
         }
-        List<UserEntity> users = getMongoStore().loadEntities(UserEntity.class, queryBuilder.get(), invocationContext);
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), invocationContext);
         return convertUserEntities(users);
     }
 
-    protected List<UserModel> convertUserEntities(List<UserEntity> userEntities) {
+    protected List<UserModel> convertUserEntities(List<MongoUserEntity> userEntities) {
         List<UserModel> userModels = new ArrayList<UserModel>();
-        for (UserEntity user : userEntities) {
+        for (MongoUserEntity user : userEntities) {
             userModels.add(new UserAdapter(user, invocationContext));
         }
         return userModels;
@@ -1232,17 +1319,18 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
 
     @Override
     public ApplicationModel getAdminApp() {
-        ApplicationEntity appData = getMongoStore().loadEntity(ApplicationEntity.class, realm.getAdminAppId(), invocationContext);
-        return new ApplicationAdapter(this, appData, invocationContext);
+        MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext);
+        return appData != null ? new ApplicationAdapter(this, appData, invocationContext) : null;
     }
 
     @Override
     public void setAdminApp(ApplicationModel app) {
         realm.setAdminAppId(app.getId());
+        updateRealm();
     }
 
     @Override
-    public RealmEntity getMongoEntity() {
+    public MongoRealmEntity getMongoEntity() {
         return realm;
     }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
index 14cd478..3d8ef1a 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
@@ -10,11 +10,10 @@ import com.mongodb.QueryBuilder;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.mongo.api.AbstractMongoIdentifiableEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.ApplicationEntity;
-import org.keycloak.models.mongo.keycloak.entities.RealmEntity;
-import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 /**
@@ -22,17 +21,17 @@ import org.keycloak.models.utils.KeycloakModelUtils;
  *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class RoleAdapter extends AbstractMongoAdapter<RoleEntity> implements RoleModel {
+public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implements RoleModel {
 
-    private final RoleEntity role;
+    private final MongoRoleEntity role;
     private RoleContainerModel roleContainer;
     private RealmModel realm;
 
-    public RoleAdapter(RealmModel realm, RoleEntity roleEntity, MongoStoreInvocationContext invContext) {
+    public RoleAdapter(RealmModel realm, MongoRoleEntity roleEntity, MongoStoreInvocationContext invContext) {
         this(realm, roleEntity, null, invContext);
     }
 
-    public RoleAdapter(RealmModel realm, RoleEntity roleEntity, RoleContainerModel roleContainer, MongoStoreInvocationContext invContext) {
+    public RoleAdapter(RealmModel realm, MongoRoleEntity roleEntity, RoleContainerModel roleContainer, MongoStoreInvocationContext invContext) {
         super(invContext);
         this.role = roleEntity;
         this.roleContainer = roleContainer;
@@ -94,10 +93,10 @@ public class RoleAdapter extends AbstractMongoAdapter<RoleEntity> implements Rol
         DBObject query = new QueryBuilder()
                 .and("_id").in(role.getCompositeRoleIds())
                 .get();
-        List<RoleEntity> childRoles = getMongoStore().loadEntities(RoleEntity.class, query, invocationContext);
+        List<MongoRoleEntity> childRoles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext);
 
         Set<RoleModel> set = new HashSet<RoleModel>();
-        for (RoleEntity childRole : childRoles) {
+        for (MongoRoleEntity childRole : childRoles) {
             set.add(new RoleAdapter(realm, childRole, invocationContext));
         }
         return set;
@@ -108,13 +107,13 @@ public class RoleAdapter extends AbstractMongoAdapter<RoleEntity> implements Rol
         if (roleContainer == null) {
             // Compute it
             if (role.getRealmId() != null) {
-                RealmEntity realm = getMongoStore().loadEntity(RealmEntity.class, role.getRealmId(), invocationContext);
+                MongoRealmEntity realm = getMongoStore().loadEntity(MongoRealmEntity.class, role.getRealmId(), invocationContext);
                 if (realm == null) {
                     throw new IllegalStateException("Realm with id: " + role.getRealmId() + " doesn't exists");
                 }
                 roleContainer = new RealmAdapter(realm, invocationContext);
             } else if (role.getApplicationId() != null) {
-                ApplicationEntity appEntity = getMongoStore().loadEntity(ApplicationEntity.class, role.getApplicationId(), invocationContext);
+                MongoApplicationEntity appEntity = getMongoStore().loadEntity(MongoApplicationEntity.class, role.getApplicationId(), invocationContext);
                 if (appEntity == null) {
                     throw new IllegalStateException("Application with id: " + role.getApplicationId() + " doesn't exists");
                 }
@@ -135,12 +134,12 @@ public class RoleAdapter extends AbstractMongoAdapter<RoleEntity> implements Rol
         return KeycloakModelUtils.searchFor(role, this, visited);
     }
 
-    public RoleEntity getRole() {
+    public MongoRoleEntity getRole() {
         return role;
     }
 
     @Override
-    public RoleEntity getMongoEntity() {
+    public MongoRoleEntity getMongoEntity() {
         return role;
     }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
index 608082e..c713b9f 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -2,7 +2,7 @@ package org.keycloak.models.mongo.keycloak.adapters;
 
 import org.keycloak.models.UserModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.UserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -15,11 +15,11 @@ import java.util.Set;
  *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class UserAdapter extends AbstractMongoAdapter<UserEntity> implements UserModel {
+public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implements UserModel {
 
-    private final UserEntity user;
+    private final MongoUserEntity user;
 
-    public UserAdapter(UserEntity userEntity, MongoStoreInvocationContext invContext) {
+    public UserAdapter(MongoUserEntity userEntity, MongoStoreInvocationContext invContext) {
         super(invContext);
         this.user = userEntity;
     }
@@ -133,7 +133,7 @@ public class UserAdapter extends AbstractMongoAdapter<UserEntity> implements Use
         return user.getAttributes()==null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(user.getAttributes());
     }
 
-    public UserEntity getUser() {
+    public MongoUserEntity getUser() {
         return user;
     }
 
@@ -173,7 +173,7 @@ public class UserAdapter extends AbstractMongoAdapter<UserEntity> implements Use
     }
 
     @Override
-    public UserEntity getMongoEntity() {
+    public MongoUserEntity getMongoEntity() {
         return user;
     }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UsernameLoginFailureAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UsernameLoginFailureAdapter.java
index 0722945..131a08b 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UsernameLoginFailureAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UsernameLoginFailureAdapter.java
@@ -2,23 +2,22 @@ package org.keycloak.models.mongo.keycloak.adapters;
 
 import org.keycloak.models.UsernameLoginFailureModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
-import org.keycloak.models.mongo.keycloak.entities.UserEntity;
-import org.keycloak.models.mongo.keycloak.entities.UsernameLoginFailureEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<UsernameLoginFailureEntity> implements UsernameLoginFailureModel {
-    protected UsernameLoginFailureEntity user;
+public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<MongoUsernameLoginFailureEntity> implements UsernameLoginFailureModel {
+    protected MongoUsernameLoginFailureEntity user;
 
-    public UsernameLoginFailureAdapter(MongoStoreInvocationContext invocationContext, UsernameLoginFailureEntity user) {
+    public UsernameLoginFailureAdapter(MongoStoreInvocationContext invocationContext, MongoUsernameLoginFailureEntity user) {
         super(invocationContext);
         this.user = user;
     }
 
     @Override
-    protected UsernameLoginFailureEntity getMongoEntity() {
+    protected MongoUsernameLoginFailureEntity getMongoEntity() {
         return user;
     }
 
@@ -35,6 +34,7 @@ public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<UsernameL
     @Override
     public void setFailedLoginNotBefore(int notBefore) {
         user.setFailedLoginNotBefore(notBefore);
+        updateMongoEntity();
     }
 
     @Override
@@ -45,11 +45,13 @@ public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<UsernameL
     @Override
     public void incrementFailures() {
         user.setNumFailures(getNumFailures() + 1);
+        updateMongoEntity();
     }
 
     @Override
     public void clearFailures() {
         user.setNumFailures(0);
+        updateMongoEntity();
     }
 
     @Override
@@ -60,6 +62,7 @@ public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<UsernameL
     @Override
     public void setLastFailure(long lastFailure) {
         user.setLastFailure(lastFailure);
+        updateMongoEntity();
     }
 
     @Override
@@ -70,4 +73,5 @@ public class UsernameLoginFailureAdapter  extends AbstractMongoAdapter<UsernameL
     @Override
     public void setLastIPFailure(String ip) {
         user.setLastIPFailure(ip);
+        updateMongoEntity();
     }}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java
index 1095195..4635fd4 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/SystemPropertiesMongoClientProvider.java
@@ -15,12 +15,12 @@ public class SystemPropertiesMongoClientProvider implements MongoClientProvider 
 
     protected static final Logger logger = Logger.getLogger(SystemPropertiesMongoClientProvider.class);
 
-    private static final String MONGO_HOST = "keycloak.mongo.host";
-    private static final String MONGO_PORT = "keycloak.mongo.port";
-    private static final String MONGO_DB_NAME = "keycloak.mongo.db";
-    private static final String MONGO_CLEAR_ON_STARTUP = "keycloak.mongo.clearOnStartup";
+    public static final String MONGO_HOST = "keycloak.mongo.host";
+    public static final String MONGO_PORT = "keycloak.mongo.port";
+    public static final String MONGO_DB_NAME = "keycloak.mongo.db";
+    public static final String MONGO_CLEAR_ON_STARTUP = "keycloak.mongo.clearOnStartup";
 
-    // Property names from Liveoak . Those are used as fallback in case that original value is not available
+    // Property names from Liveoak . Those are used as fallback
     private static final String MONGO_HOST_2 = "mongo.host";
     private static final String MONGO_PORT_2 = "mongo.port";
     private static final String MONGO_DB_NAME_2 = "mongo.db";
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoApplicationEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoApplicationEntity.java
new file mode 100755
index 0000000..c4a8d1a
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoApplicationEntity.java
@@ -0,0 +1,26 @@
+package org.keycloak.models.mongo.keycloak.entities;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.models.entities.ApplicationEntity;
+import org.keycloak.models.mongo.api.MongoCollection;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.MongoIndex;
+import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@MongoCollection(collectionName = "applications")
+@MongoIndex(fields = { "realmId", "name" }, unique = true)
+public class MongoApplicationEntity extends ApplicationEntity implements MongoIdentifiableEntity {
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext context) {
+        // Remove all roles, which belongs to this application
+        DBObject query = new QueryBuilder()
+                .and("applicationId").is(getId())
+                .get();
+        context.getMongoStore().removeEntities(MongoRoleEntity.class, query, context);
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoRealmEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoRealmEntity.java
new file mode 100755
index 0000000..1bd2f90
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoRealmEntity.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.mongo.keycloak.entities;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.models.entities.RealmEntity;
+import org.keycloak.models.mongo.api.MongoCollection;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.MongoIndex;
+import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@MongoCollection(collectionName = "realms")
+@MongoIndex(fields = { "name" }, unique = true)
+public class MongoRealmEntity extends RealmEntity implements MongoIdentifiableEntity {
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext context) {
+        DBObject query = new QueryBuilder()
+                .and("realmId").is(getId())
+                .get();
+
+        // Remove all users of this realm
+        context.getMongoStore().removeEntities(MongoUserEntity.class, query, context);
+
+        // Remove all roles of this realm
+        context.getMongoStore().removeEntities(MongoRoleEntity.class, query, context);
+
+        // Remove all applications of this realm
+        context.getMongoStore().removeEntities(MongoApplicationEntity.class, query, context);
+
+        // Remove all clients of this realm
+        context.getMongoStore().removeEntities(MongoOAuthClientEntity.class, query, context);
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUserEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUserEntity.java
new file mode 100755
index 0000000..e9dd851
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUserEntity.java
@@ -0,0 +1,32 @@
+package org.keycloak.models.mongo.keycloak.entities;
+
+import org.keycloak.models.entities.UserEntity;
+import org.keycloak.models.mongo.api.MongoCollection;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.MongoIndex;
+import org.keycloak.models.mongo.api.MongoIndexes;
+import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@MongoCollection(collectionName = "users")
+@MongoIndexes({
+        @MongoIndex(fields = { "realmId", "loginName" }, unique = true),
+        @MongoIndex(fields = { "emailIndex" }, unique = true, sparse = true),
+})
+public class MongoUserEntity extends UserEntity implements MongoIdentifiableEntity {
+
+
+    public String getEmailIndex() {
+        return getEmail() != null ? getRealmId() + "//" + getEmail() : null;
+    }
+
+    public void setEmailIndex(String ignored) {
+    }
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUsernameLoginFailureEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUsernameLoginFailureEntity.java
new file mode 100755
index 0000000..62533f5
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/MongoUsernameLoginFailureEntity.java
@@ -0,0 +1,18 @@
+package org.keycloak.models.mongo.keycloak.entities;
+
+import org.keycloak.models.entities.UsernameLoginFailureEntity;
+import org.keycloak.models.mongo.api.MongoCollection;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@MongoCollection(collectionName = "userFailures")
+public class MongoUsernameLoginFailureEntity extends UsernameLoginFailureEntity implements MongoIdentifiableEntity {
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/utils/MongoModelUtils.java b/model/mongo/src/main/java/org/keycloak/models/mongo/utils/MongoModelUtils.java
index d485615..a6d40b9 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/utils/MongoModelUtils.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/utils/MongoModelUtils.java
@@ -7,12 +7,12 @@ import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.entities.ClientEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.keycloak.adapters.ClientAdapter;
 import org.keycloak.models.mongo.keycloak.adapters.UserAdapter;
-import org.keycloak.models.mongo.keycloak.entities.ClientEntity;
-import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
-import org.keycloak.models.mongo.keycloak.entities.UserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -20,8 +20,8 @@ import org.keycloak.models.mongo.keycloak.entities.UserEntity;
 public class MongoModelUtils {
 
     // Get everything including both application and realm roles
-    public static List<RoleEntity> getAllRolesOfUser(UserModel user, MongoStoreInvocationContext invContext) {
-        UserEntity userEntity = ((UserAdapter)user).getUser();
+    public static List<MongoRoleEntity> getAllRolesOfUser(UserModel user, MongoStoreInvocationContext invContext) {
+        MongoUserEntity userEntity = ((UserAdapter)user).getUser();
         List<String> roleIds = userEntity.getRoleIds();
 
         if (roleIds == null || roleIds.isEmpty()) {
@@ -31,12 +31,12 @@ public class MongoModelUtils {
         DBObject query = new QueryBuilder()
                 .and("_id").in(roleIds)
                 .get();
-        return invContext.getMongoStore().loadEntities(RoleEntity.class, query, invContext);
+        return invContext.getMongoStore().loadEntities(MongoRoleEntity.class, query, invContext);
     }
 
     // Get everything including both application and realm scopes
-    public static List<RoleEntity> getAllScopesOfClient(ClientModel client, MongoStoreInvocationContext invContext) {
-        ClientEntity scopedEntity = ((ClientAdapter)client).getMongoEntity();
+    public static List<MongoRoleEntity> getAllScopesOfClient(ClientModel client, MongoStoreInvocationContext invContext) {
+        ClientEntity scopedEntity = ((ClientAdapter)client).getMongoEntityAsClient();
         List<String> scopeIds = scopedEntity.getScopeIds();
 
         if (scopeIds == null || scopeIds.isEmpty()) {
@@ -46,6 +46,6 @@ public class MongoModelUtils {
         DBObject query = new QueryBuilder()
                 .and("_id").in(scopeIds)
                 .get();
-        return invContext.getMongoStore().loadEntities(RoleEntity.class, query, invContext);
+        return invContext.getMongoStore().loadEntities(MongoRoleEntity.class, query, invContext);
     }
 }
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
index 215a9fc..d549fa7 100755
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Address.java
@@ -8,12 +8,11 @@ import java.util.List;
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class Address implements MongoEntity {
+public class Address {
 
     private String street;
     private int number;
 
-    @MongoField
     public String getStreet() {
         return street;
     }
@@ -22,7 +21,6 @@ public class Address implements MongoEntity {
         this.street = street;
     }
 
-    @MongoField
     public int getNumber() {
         return number;
     }
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java
index 0495f43..7e13e94 100644
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/AddressWithFlats.java
@@ -13,7 +13,6 @@ public class AddressWithFlats extends Address {
 
     private List<String> flatNumbers;
 
-    @MongoField
     public List<String> getFlatNumbers() {
         return flatNumbers;
     }
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java
index 7200806..f48b372 100755
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/MongoStoreTest.java
@@ -6,7 +6,6 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.keycloak.models.mongo.api.MongoEntity;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.impl.MongoStoreImpl;
@@ -22,7 +21,7 @@ import java.util.List;
  */
 public class MongoStoreTest {
 
-    private static final Class<? extends MongoEntity>[] MANAGED_DATA_TYPES = (Class<? extends MongoEntity>[])new Class<?>[] {
+    private static final Class<?>[] MANAGED_DATA_TYPES = (Class<?>[])new Class<?>[] {
             Person.class,
             Address.class,
             AddressWithFlats.class
diff --git a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
index e3f8042..3db6616 100755
--- a/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
+++ b/model/mongo/src/test/java/org/keycloak/models/mongo/test/Person.java
@@ -1,8 +1,8 @@
 package org.keycloak.models.mongo.test;
 
-import org.keycloak.models.mongo.api.AbstractMongoIdentifiableEntity;
 import org.keycloak.models.mongo.api.MongoCollection;
-import org.keycloak.models.mongo.api.MongoField;
+import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 
 import java.util.HashMap;
 import java.util.List;
@@ -12,8 +12,9 @@ import java.util.Map;
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 @MongoCollection(collectionName = "persons")
-public class Person extends AbstractMongoIdentifiableEntity {
+public class Person implements MongoIdentifiableEntity {
 
+    private String id;
     private String firstName;
     private int age;
     private List<String> kids;
@@ -23,7 +24,14 @@ public class Person extends AbstractMongoIdentifiableEntity {
     private List<Gender> genders;
     private Map<String, String> attributes = new HashMap<String, String>();
 
-    @MongoField
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
     public String getFirstName() {
         return firstName;
     }
@@ -32,7 +40,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.firstName = firstName;
     }
 
-    @MongoField
     public int getAge() {
         return age;
     }
@@ -41,7 +48,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.age = age;
     }
 
-    @MongoField
     public Gender getGender() {
         return gender;
     }
@@ -50,7 +56,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.gender = gender;
     }
 
-    @MongoField
     public List<Gender> getGenders() {
         return genders;
     }
@@ -59,7 +64,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.genders = genders;
     }
 
-    @MongoField
     public List<String> getKids() {
         return kids;
     }
@@ -68,7 +72,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.kids = kids;
     }
 
-    @MongoField
     public List<AddressWithFlats> getAddresses() {
         return addresses;
     }
@@ -77,7 +80,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.addresses = addresses;
     }
 
-    @MongoField
     public Address getMainAddress() {
         return mainAddress;
     }
@@ -86,7 +88,6 @@ public class Person extends AbstractMongoIdentifiableEntity {
         this.mainAddress = mainAddress;
     }
 
-    @MongoField
     public Map<String, String> getAttributes() {
         return attributes;
     }
@@ -103,6 +104,10 @@ public class Person extends AbstractMongoIdentifiableEntity {
         attributes.remove(key);
     }
 
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+    }
+
     public static enum Gender {
         MALE, FEMALE
     }
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
index 7fcbadb..4270d29 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
@@ -164,6 +164,9 @@ public class AdapterTest extends AbstractModelTest {
         cred.setValue("password");
         realmModel.updateCredential(user, cred);
 
+        commit();
+
+        realmModel = identitySession.getRealm("JUGGLER");
         Assert.assertTrue(realmModel.removeUser("bburke"));
         Assert.assertFalse(realmModel.removeUser("bburke"));
         Assert.assertNull(realmModel.getUser("bburke"));
@@ -218,6 +221,9 @@ public class AdapterTest extends AbstractModelTest {
 
         realmModel.addScopeMapping(app, realmRole);
 
+        commit();
+        realmModel = identitySession.getRealm("JUGGLER");
+
         Assert.assertTrue(realmManager.removeRealm(realmModel));
         Assert.assertFalse(realmManager.removeRealm(realmModel));
         Assert.assertNull(realmManager.getRealm(realmModel.getId()));
@@ -241,6 +247,10 @@ public class AdapterTest extends AbstractModelTest {
         RoleModel realmRole = realmModel.addRole("test");
         realmModel.addScopeMapping(app, realmRole);
 
+        commit();
+        realmModel = identitySession.getRealm("JUGGLER");
+        app = realmModel.getApplicationByName("test-app");
+
         Assert.assertTrue(realmModel.removeRoleById(realmRole.getId()));
         Assert.assertFalse(realmModel.removeRoleById(realmRole.getId()));
         Assert.assertNull(realmModel.getRole(realmRole.getName()));
@@ -521,7 +531,7 @@ public class AdapterTest extends AbstractModelTest {
         }
         commit(true);
 
-        // Ty to rename realm to duplicate name
+        // Try to rename realm to duplicate name
         realmManager.createRealm("JUGGLER2");
         commit();
         try {
diff --git a/model/tests/src/test/java/org/keycloak/model/test/ApplicationModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/ApplicationModelTest.java
index 4d94084..05fbe78 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/ApplicationModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/ApplicationModelTest.java
@@ -64,6 +64,15 @@ public class ApplicationModelTest extends AbstractModelTest {
         assertEquals(application, copy);
     }
 
+    @Test
+    public void testAddApplicationWithId() {
+        application = realm.addApplication("app-123", "application2");
+        commit();
+        application = realmManager.getRealm(realm.getId()).getApplicationById("app-123");
+        Assert.assertNotNull(application);
+    }
+
+
     public static void assertEquals(ApplicationModel expected, ApplicationModel actual) {
         Assert.assertEquals(expected.getName(), actual.getName());
         Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
diff --git a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
index db004b5..0552a97 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
@@ -50,6 +50,16 @@ public class ImportTest extends AbstractModelTest {
         commit();
 
         realm = realmManager.getRealm("demo");
+        assertDataImportedInRealm(realm);
+
+        commit();
+
+        realm = realmManager.getRealm("demo");
+        realmManager.removeRealm(realm);
+    }
+
+    // Moved to static method, so it's possible to test this from other places too (for example export-import tests)
+    public static void assertDataImportedInRealm(RealmModel realm) {
         Assert.assertTrue(realm.isVerifyEmail());
 
         Assert.assertFalse(realm.isUpdateProfileOnInitialSocialLogin());
@@ -211,13 +221,6 @@ public class ImportTest extends AbstractModelTest {
         AuthenticationLinkModel authLink = realm.getAuthenticationLink(socialUser);
         Assert.assertEquals(AuthProviderConstants.PROVIDER_NAME_PICKETLINK, authLink.getAuthProvider());
         Assert.assertEquals("myUser1", authLink.getAuthUserId());
-
-        commit();
-
-        realm = realmManager.getRealm("demo");
-        realmManager.removeRealm(realm);
-
-
     }
 
     @Test
diff --git a/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
index c783eaa..35a0981 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
@@ -48,6 +48,10 @@ public class MultipleRealmsTest extends AbstractModelTest {
         // Test searching
         Assert.assertEquals(2, realm1.searchForUser("user").size());
 
+        commit();
+        realm1 = identitySession.getRealm("id1");
+        realm2 = identitySession.getRealm("id2");
+
         realm1.removeUser("user1");
         realm1.removeUser("user2");
         Assert.assertEquals(0, realm1.searchForUser("user").size());

pom.xml 8(+8 -0)

diff --git a/pom.xml b/pom.xml
index 640300d..bc1e568 100755
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,7 @@
         <module>timer</module>
         <module>bundled-war-example</module>
         <module>project-integrations</module>
+        <module>export-import</module>
     </modules>
 
     <dependencyManagement>
@@ -323,6 +324,13 @@
 	    		<version>1.3.1b</version>
 			</dependency>
 
+            <!-- Encrypted ZIP -->
+            <dependency>
+                <groupId>de.idyl</groupId>
+                <artifactId>winzipaes</artifactId>
+                <version>1.0.1</version>
+            </dependency>
+
 			<!-- Selenium -->
 			<dependency>
 				<groupId>org.seleniumhq.selenium</groupId>

server/pom.xml 15(+15 -0)

diff --git a/server/pom.xml b/server/pom.xml
index 7fb498b..3e29a02 100755
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -225,6 +225,21 @@
             <scope>provided</scope>
         </dependency>
 
+        <!-- export/import -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-impl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>de.idyl</groupId>
+            <artifactId>winzipaes</artifactId>
+        </dependency>
 
     </dependencies>
 

services/pom.xml 6(+6 -0)

diff --git a/services/pom.xml b/services/pom.xml
index bec5d06..af526e7 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -87,6 +87,12 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-picketlink-api</artifactId>
             <version>${project.version}</version>
             <scope>provided</scope>
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 3012507..158ad59 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -10,6 +10,7 @@ import org.keycloak.audit.AuditProvider;
 import org.keycloak.audit.AuditProviderFactory;
 import org.keycloak.authentication.AuthenticationProvider;
 import org.keycloak.authentication.AuthenticationProviderFactory;
+import org.keycloak.exportimport.ExportImportProvider;
 import org.keycloak.models.Config;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
@@ -31,6 +32,7 @@ import org.keycloak.models.utils.ModelProviderUtils;
 import org.keycloak.timer.TimerProvider;
 import org.keycloak.timer.TimerProviderFactory;
 import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.ProviderLoader;
 
 import javax.servlet.ServletContext;
 import javax.ws.rs.core.Application;
@@ -43,6 +45,7 @@ import java.io.InputStream;
 import java.net.URI;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
 import java.util.StringTokenizer;
 
@@ -92,6 +95,8 @@ public class KeycloakApplication extends Application {
 
         setupScheduledTasks(providerSessionFactory, factory);
         importRealms(context);
+
+        checkExportImportProvider();
     }
 
     public String getContextPath() {
@@ -267,5 +272,16 @@ public class KeycloakApplication extends Application {
         }
     }
 
+    protected void checkExportImportProvider() {
+        Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
+
+        if (providers.hasNext()) {
+            ExportImportProvider exportImport = providers.next();
+            exportImport.checkExportImport(factory);
+        } else {
+            log.warn("No ExportImportProvider found!");
+        }
+    }
+
 
 }
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 5566e60..a83b4a7 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -234,6 +234,17 @@
         </dependency>
 
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-export-import-impl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
         </dependency>
@@ -346,6 +357,12 @@
             <artifactId>picketlink-common</artifactId>
         </dependency>
 
+        <!-- Encrypted ZIP -->
+        <dependency>
+            <groupId>de.idyl</groupId>
+            <artifactId>winzipaes</artifactId>
+        </dependency>
+
         <!-- This adds couple of other dependencies (like picketlink) -->
         <dependency>
             <groupId>org.keycloak</groupId>