More cleanup and removed export-import-impl module
This commit is contained in:
parent
c14840a4c0
commit
726ce08700
26 changed files with 78 additions and 1599 deletions
|
@ -1,236 +0,0 @@
|
|||
<?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-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4-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.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-invalidation-cache-model</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<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.keycloak</groupId>
|
||||
<artifactId>keycloak-model-tests</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.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||
<keycloak.model.mongo.bindIp>127.0.0.1</keycloak.model.mongo.bindIp>
|
||||
</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.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>-->
|
||||
<!--<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>-->
|
||||
<!--<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>-->
|
||||
<!--<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>-->
|
||||
<!--<keycloak.model.mongo.bindIp>${keycloak.model.mongo.bindIp}</keycloak.model.mongo.bindIp>-->
|
||||
<!--</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.model.mongo.port}</port>-->
|
||||
<!--<logging>file</logging>-->
|
||||
<!--<logFile>${project.build.directory}/mongodb.log</logFile>-->
|
||||
<!--<bindIp>${keycloak.model.mongo.bindIp}</bindIp>-->
|
||||
<!--</configuration>-->
|
||||
<!--</execution>-->
|
||||
<!--<execution>-->
|
||||
<!--<id>stop-mongodb</id>-->
|
||||
<!--<phase>post-integration-test</phase>-->
|
||||
<!--<goals>-->
|
||||
<!--<goal>stop</goal>-->
|
||||
<!--</goals>-->
|
||||
<!--</execution>-->
|
||||
<!--</executions>-->
|
||||
<!--</plugin>-->
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,152 +0,0 @@
|
|||
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", "getAuthenticationLink");
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
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.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 {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExportImportProviderImpl.class);
|
||||
|
||||
public static final String ACTION_EXPORT = "export";
|
||||
public static final String ACTION_IMPORT = "import";
|
||||
|
||||
public void checkExportImport(KeycloakSessionFactory sessionFactory) {
|
||||
String exportImportAction = ExportImportConfig.getAction();
|
||||
|
||||
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 = sessionFactory.create();
|
||||
KeycloakTransaction transaction = session.getTransaction();
|
||||
try {
|
||||
transaction.begin();
|
||||
|
||||
if (export) {
|
||||
ExportWriter exportWriter = getProvider().getExportWriter();
|
||||
new ModelExporter().exportModel(session.model(), exportWriter);
|
||||
logger.infof("Export finished successfully");
|
||||
} else {
|
||||
ImportReader importReader = getProvider().getImportReader();
|
||||
new ModelImporter().importModel(session.model(), 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 = ExportImportConfig.getProvider();
|
||||
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");
|
||||
}
|
||||
}
|
|
@ -1,335 +0,0 @@
|
|||
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.ModelProvider;
|
||||
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(ModelProvider model, 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(model, "realms.json");
|
||||
exportApplications(model, "applications.json");
|
||||
exportOAuthClients(model, "oauthClients.json");
|
||||
exportRoles(model, "roles.json");
|
||||
exportUsers(model, "users.json");
|
||||
// exportUserFailures(model, "userFailures.json");
|
||||
|
||||
this.exportWriter.closeExportWriter();
|
||||
}
|
||||
|
||||
protected void exportRealms(ModelProvider model, String fileName) {
|
||||
List<RealmModel> realms = model.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.getMasterAdminApp();
|
||||
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(ModelProvider model, String fileName) {
|
||||
List<ApplicationModel> allApplications = getAllApplications(model);
|
||||
|
||||
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(ModelProvider model, String fileName) {
|
||||
List<RealmModel> realms = model.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(ModelProvider model, String fileName) {
|
||||
List<RoleModel> allRoles = getAllRoles(model);
|
||||
|
||||
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(ModelProvider model, String fileName) {
|
||||
List<RealmModel> realms = model.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.setUsername(userModel.getUsername());
|
||||
userEntity.setRealmId(realm.getId());
|
||||
|
||||
// authentication links
|
||||
AuthenticationLinkModel authLink = userModel.getAuthenticationLink();
|
||||
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 = userModel.getRoleMappings();
|
||||
List<String> roleIds = new ArrayList<String>();
|
||||
for (RoleModel role : roles) {
|
||||
roleIds.add(role.getId());
|
||||
}
|
||||
userEntity.setRoleIds(roleIds);
|
||||
|
||||
// credentials
|
||||
List<UserCredentialValueModel> credentials = userModel.getCredentialsDirectly();
|
||||
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(ModelProvider model, String fileName) {
|
||||
// List<RealmModel> realms = model.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.getScopeMappings();
|
||||
List<String> scopeIds = new ArrayList<String>();
|
||||
for (RoleModel role : allScopes) {
|
||||
scopeIds.add(role.getId());
|
||||
}
|
||||
return scopeIds;
|
||||
}
|
||||
|
||||
private List<ApplicationModel> getAllApplications(ModelProvider model) {
|
||||
List<RealmModel> realms = model.getRealms();
|
||||
List<ApplicationModel> allApplications = new ArrayList<ApplicationModel>();
|
||||
for (RealmModel realmModel : realms) {
|
||||
allApplications.addAll(realmModel.getApplications());
|
||||
}
|
||||
return allApplications;
|
||||
}
|
||||
|
||||
private List<RoleModel> getAllRoles(ModelProvider model) {
|
||||
List<RoleModel> allRoles = new ArrayList<RoleModel>();
|
||||
|
||||
List<RealmModel> realms = model.getRealms();
|
||||
for (RealmModel realmModel : realms) {
|
||||
allRoles.addAll(realmModel.getRoles());
|
||||
}
|
||||
|
||||
List<ApplicationModel> allApplications = getAllApplications(model);
|
||||
for (ApplicationModel appModel : allApplications) {
|
||||
allRoles.addAll(appModel.getRoles());
|
||||
}
|
||||
|
||||
return allRoles;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,327 +0,0 @@
|
|||
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.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
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(ModelProvider model, ImportReader importReader) {
|
||||
// Initialize needed objects
|
||||
this.importReader = importReader;
|
||||
this.propertiesManager = new ExportImportPropertiesManager();
|
||||
|
||||
importRealms(model, "realms.json");
|
||||
importApplications(model, "applications.json");
|
||||
importRoles(model, "roles.json");
|
||||
|
||||
// Now we have all realms,applications and roles filled. So fill other objects (default roles, scopes etc)
|
||||
importRealmsStep2(model, "realms.json");
|
||||
importApplicationsStep2(model, "applications.json");
|
||||
|
||||
importOAuthClients(model, "oauthClients.json");
|
||||
importUsers(model, "users.json");
|
||||
// importUserFailures(model, "userFailures.json");
|
||||
|
||||
this.importReader.closeImportReader();
|
||||
}
|
||||
|
||||
protected void importRealms(ModelProvider model, String fileName) {
|
||||
List<RealmEntity> realms = this.importReader.readEntities(fileName, RealmEntity.class);
|
||||
|
||||
for (RealmEntity realmEntity : realms) {
|
||||
RealmModel realm = model.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(ModelProvider model, String fileName) {
|
||||
List<ApplicationEntity> apps = this.importReader.readEntities(fileName, ApplicationEntity.class);
|
||||
for (ApplicationEntity appEntity : apps) {
|
||||
RealmModel realm = model.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(ModelProvider model, 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 = model.getRealm(roleEntity.getRealmId());
|
||||
role = realm.addRole(roleEntity.getId(), roleEntity.getName());
|
||||
} else if (roleEntity.getApplicationId() != null) {
|
||||
ApplicationModel app = findApplicationById(model, 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 : model.getRealms()) {
|
||||
|
||||
// realm roles
|
||||
fillCompositeRoles(rolesMap, realm, realm);
|
||||
|
||||
// app roles
|
||||
for (ApplicationModel app : realm.getApplications()) {
|
||||
fillCompositeRoles(rolesMap, app, realm);
|
||||
}
|
||||
}
|
||||
|
||||
logger.infof("%d roles imported: ", roles.size());
|
||||
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(ModelProvider model, String fileName) {
|
||||
List<RealmEntity> realms = this.importReader.readEntities(fileName, RealmEntity.class);
|
||||
RealmModel adminRealm = model.getRealm(Config.getAdminRealm());
|
||||
|
||||
for (RealmEntity realmEntity : realms) {
|
||||
RealmModel realm = model.getRealm(realmEntity.getId());
|
||||
|
||||
// admin app
|
||||
String adminAppId = realmEntity.getAdminAppId();
|
||||
if (adminAppId != null) {
|
||||
realm.setMasterAdminApp(adminRealm.getApplicationById(adminAppId));
|
||||
}
|
||||
|
||||
// Default roles
|
||||
realm.updateDefaultRoles(realmEntity.getDefaultRoles().toArray(new String[] {}));
|
||||
}
|
||||
}
|
||||
|
||||
protected void importApplicationsStep2(ModelProvider model, String fileName) {
|
||||
List<ApplicationEntity> apps = this.importReader.readEntities(fileName, ApplicationEntity.class);
|
||||
for (ApplicationEntity appEntity : apps) {
|
||||
RealmModel realm = model.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);
|
||||
client.addScopeMapping(scope);
|
||||
}
|
||||
}
|
||||
|
||||
protected void importOAuthClients(ModelProvider model, String fileName) {
|
||||
List<OAuthClientEntity> clients = this.importReader.readEntities(fileName, OAuthClientEntity.class);
|
||||
for (OAuthClientEntity clientEntity : clients) {
|
||||
RealmModel realm = model.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.info("OAuth clients imported: " + clients);
|
||||
}
|
||||
|
||||
protected ApplicationModel findApplicationById(ModelProvider model, String applicationId) {
|
||||
for (RealmModel realm : model.getRealms()) {
|
||||
ApplicationModel appModel = realm.getApplicationById(applicationId);
|
||||
if (appModel != null) {
|
||||
return appModel;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void importUsers(ModelProvider model, String fileName) {
|
||||
List<UserEntity> users = this.importReader.readEntities(fileName, UserEntity.class);
|
||||
for (UserEntity userEntity : users) {
|
||||
RealmModel realm = model.getRealm(userEntity.getRealmId());
|
||||
UserModel user = realm.addUser(userEntity.getId(), userEntity.getUsername(), false);
|
||||
|
||||
// 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 : user.getRoleMappings()) {
|
||||
user.deleteRoleMapping(role);
|
||||
}
|
||||
|
||||
this.propertiesManager.setBasicPropertiesToModel(user, userEntity);
|
||||
|
||||
// authentication links
|
||||
AuthenticationLinkEntity authLinkEntity = userEntity.getAuthenticationLink();
|
||||
if (authLinkEntity != null) {
|
||||
AuthenticationLinkModel authLinkModel = new AuthenticationLinkModel();
|
||||
this.propertiesManager.setBasicPropertiesToModel(authLinkModel, authLinkEntity);
|
||||
|
||||
user.setAuthenticationLink(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);
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
|
||||
// credentials
|
||||
List<CredentialEntity> credentials = userEntity.getCredentials();
|
||||
if (credentials != null) {
|
||||
for (CredentialEntity credEntity : credentials) {
|
||||
UserCredentialValueModel credModel = new UserCredentialValueModel();
|
||||
this.propertiesManager.setBasicPropertiesToModel(credModel, credEntity);
|
||||
|
||||
user.updateCredentialDirectly(credModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.infof("%d users imported: ", users.size());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Imported users: " + users);
|
||||
}
|
||||
}
|
||||
|
||||
// public void importUserFailures(ModelProvider model, String fileName) {
|
||||
// List<UsernameLoginFailureEntity> userFailures = this.importReader.readEntities(fileName, UsernameLoginFailureEntity.class);
|
||||
// for (UsernameLoginFailureEntity entity : userFailures) {
|
||||
// RealmModel realm = model.getRealm(entity.getRealmId());
|
||||
// UsernameLoginFailureModel loginFailureModel = realm.addUserLoginFailure(entity.getUsername());
|
||||
//
|
||||
// this.propertiesManager.setBasicPropertiesToModel(loginFailureModel , entity);
|
||||
//
|
||||
// for (int i=0 ; i<entity.getNumFailures() ; i++) {
|
||||
// loginFailureModel.incrementFailures();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package org.keycloak.exportimport.io;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportImportIOProvider {
|
||||
|
||||
String getId();
|
||||
|
||||
ExportWriter getExportWriter();
|
||||
|
||||
ImportReader getImportReader();
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.keycloak.exportimport.io.directory;
|
||||
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||
import org.keycloak.exportimport.io.ExportWriter;
|
||||
import org.keycloak.exportimport.io.ImportReader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 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 = ExportImportConfig.getDir();
|
||||
return dir!=null ? new TmpDirExportWriter(new File(dir)) : new TmpDirExportWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportReader getImportReader() {
|
||||
String dir = ExportImportConfig.getDir();
|
||||
return dir!=null ? new TmpDirImportReader(new File(dir)) : new TmpDirImportReader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
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.
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
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?
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package org.keycloak.exportimport.io.zip;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||
import org.keycloak.exportimport.io.ExportWriter;
|
||||
import org.keycloak.exportimport.io.ImportReader;
|
||||
|
||||
/**
|
||||
* @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 = ExportImportConfig.getZipFile();
|
||||
String zipPassword = ExportImportConfig.getZipPassword();
|
||||
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 = ExportImportConfig.getZipFile();
|
||||
String zipPassword = ExportImportConfig.getZipPassword();
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
org.keycloak.exportimport.ExportImportProviderImpl
|
|
@ -1,2 +0,0 @@
|
|||
org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider
|
||||
org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider
|
|
@ -1,14 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider;
|
||||
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>
|
||||
*/
|
||||
@Ignore
|
||||
public class JPAToMongoExportImportTest {
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
@Ignore
|
||||
public class MongoToJPAExportImportTest {
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
<modules>
|
||||
<module>export-import-api</module>
|
||||
<module>export-import-impl</module>
|
||||
<module>export-import-dir</module>
|
||||
<module>export-import-single-file</module>
|
||||
<module>export-import-zip</module>
|
||||
|
|
|
@ -266,9 +266,23 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
|
|||
@Override
|
||||
public boolean removeRealm(String id) {
|
||||
cache.invalidateCachedRealmById(id);
|
||||
|
||||
RealmModel realm = getDelegate().getRealm(id);
|
||||
Set<RoleModel> realmRoles = null;
|
||||
if (realm != null) {
|
||||
realmRoles = realm.getRoles();
|
||||
}
|
||||
|
||||
boolean didIt = getDelegate().removeRealm(id);
|
||||
realmInvalidations.add(id);
|
||||
|
||||
// TODO: Temporary workaround to invalidate cached realm roles
|
||||
if (didIt && realmRoles != null) {
|
||||
for (RoleModel role : realmRoles) {
|
||||
roleInvalidations.add(role.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return didIt;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,12 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-impl</artifactId>
|
||||
<artifactId>keycloak-export-import-dir</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -284,7 +284,17 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-impl</artifactId>
|
||||
<artifactId>keycloak-export-import-dir</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-zip</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -5,8 +5,6 @@ import java.util.Properties;
|
|||
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.junit.rules.RuleChain;
|
||||
|
@ -25,7 +23,6 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testutils.KeycloakServer;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -64,6 +61,29 @@ public class ExportImportTest {
|
|||
}
|
||||
};
|
||||
|
||||
// We want data to be persisted among server restarts
|
||||
private static ExternalResource mongoRule = new ExternalResource() {
|
||||
|
||||
private static final String MONGO_CLEAR_ON_STARTUP_PROP_NAME = "keycloak.model.mongo.clearOnStartup";
|
||||
private String previousMongoClearOnStartup;
|
||||
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
previousMongoClearOnStartup = System.getProperty(MONGO_CLEAR_ON_STARTUP_PROP_NAME);
|
||||
System.setProperty(MONGO_CLEAR_ON_STARTUP_PROP_NAME, "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
if (previousMongoClearOnStartup != null) {
|
||||
System.setProperty(MONGO_CLEAR_ON_STARTUP_PROP_NAME, "false");
|
||||
} else {
|
||||
System.getProperties().remove(MONGO_CLEAR_ON_STARTUP_PROP_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static KeycloakRule keycloakRule = new KeycloakRule( new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
@Override
|
||||
|
@ -79,9 +99,10 @@ public class ExportImportTest {
|
|||
@ClassRule
|
||||
public static TestRule chain = RuleChain
|
||||
.outerRule(hibernateSetupRule)
|
||||
.around(mongoRule)
|
||||
.around(keycloakRule);
|
||||
|
||||
//@Test
|
||||
@Test
|
||||
public void testDirFullExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
||||
String targetDirPath = getExportImportTestDirectory() + File.separator + "dirExport";
|
||||
|
@ -95,7 +116,7 @@ public class ExportImportTest {
|
|||
Assert.assertEquals(4, new File(targetDirPath).listFiles().length);
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Test
|
||||
public void testDirRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
||||
String targetDirPath = getExportImportTestDirectory() + File.separator + "dirRealmExport";
|
||||
|
@ -118,7 +139,7 @@ public class ExportImportTest {
|
|||
testFullExportImport();
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Test
|
||||
public void testSingleFileRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||
String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
|
||||
|
@ -127,7 +148,7 @@ public class ExportImportTest {
|
|||
testRealmExportImport();
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Test
|
||||
public void testZipFullExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
|
||||
String zipFilePath = getExportImportTestDirectory() + File.separator + "export-full.zip";
|
||||
|
@ -139,7 +160,7 @@ public class ExportImportTest {
|
|||
testFullExportImport();
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Test
|
||||
public void testZipRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
|
||||
String zipFilePath = getExportImportTestDirectory() + File.separator + "export-realm.zip";
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.apache.log.Logger;
|
|||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
||||
|
@ -77,9 +78,9 @@ public class CreateRealmsWorker implements Worker {
|
|||
|
||||
// Add required credentials
|
||||
if (createRequiredCredentials) {
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.PASSWORD);
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.TOTP);
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.CLIENT_CERT);
|
||||
RepresentationToModel.addRequiredCredential(realm, CredentialRepresentation.PASSWORD);
|
||||
RepresentationToModel.addRequiredCredential(realm, CredentialRepresentation.TOTP);
|
||||
RepresentationToModel.addRequiredCredential(realm, CredentialRepresentation.CLIENT_CERT);
|
||||
}
|
||||
|
||||
log.info("Finished creation of realm " + realmName);
|
||||
|
|
|
@ -283,7 +283,17 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-impl</artifactId>
|
||||
<artifactId>keycloak-export-import-dir</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-zip</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.test.tools;
|
||||
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportImportManager;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
@ -231,14 +232,7 @@ public class PerfTools {
|
|||
ExportImportConfig.setProvider("dir");
|
||||
ExportImportConfig.setDir(dir);
|
||||
|
||||
Iterator<ExportProvider> providers = ProviderLoader.load(ExportProvider.class).iterator();
|
||||
|
||||
if (providers.hasNext()) {
|
||||
ExportProvider exportImport = providers.next();
|
||||
exportImport.checkExportImport(sessionFactory);
|
||||
} else {
|
||||
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
new ExportImportManager().checkExportImport(sessionFactory);
|
||||
}
|
||||
|
||||
public static class JobRepresentation {
|
||||
|
|
Loading…
Reference in a new issue