keycloak-uncached
Changes
export-import/export-import-api/pom.xml 26(+26 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportConfig.java 63(+56 -7)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportManager.java 63(+63 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportProvider.java 18(+18 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportProviderFactory.java 7(+2 -5)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProvider.java 17(+17 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProviderFactory.java 13(+4 -9)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java 15(+15 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java 47(+47 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportUtils.java 365(+365 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ImportUtils.java 211(+211 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java 116(+116 -0)
export-import/export-import-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi 2(+2 -0)
export-import/export-import-dir/pom.xml 66(+66 -0)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProvider.java 53(+22 -31)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProviderFactory.java 30(+15 -15)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java 107(+107 -0)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProviderFactory.java 34(+34 -0)
export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory 1(+1 -0)
export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory 1(+1 -0)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java 152(+0 -152)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java 83(+0 -83)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportUtils.java 20(+0 -20)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/directory/TmpDirImportReader.java 67(+0 -67)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ExportWriter.java 13(+0 -13)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/ImportReader.java 13(+0 -13)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPImportReader.java 70(+0 -70)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/io/zip/EncryptedZIPIOProvider.java 48(+0 -48)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java 335(+0 -335)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java 327(+0 -327)
export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportImportProvider 1(+0 -1)
export-import/export-import-impl/src/main/resources/META-INF/services/org.keycloak.exportimport.io.ExportImportIOProvider 2(+0 -2)
export-import/export-import-impl/src/test/java/org/keycloak/exportimport/ExportImportTestBase.java 115(+0 -115)
export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java 38(+0 -38)
export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java 71(+0 -71)
export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java 85(+85 -0)
export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProviderFactory.java 36(+36 -0)
export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProvider.java 59(+59 -0)
export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java 34(+34 -0)
export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory 1(+1 -0)
export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory 1(+1 -0)
export-import/export-import-zip/pom.xml 70(+70 -0)
export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProvider.java 61(+34 -27)
export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProviderFactory.java 44(+44 -0)
export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java 110(+110 -0)
export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java 41(+41 -0)
export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory 1(+1 -0)
export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory 1(+1 -0)
export-import/pom.xml 4(+3 -1)
model/api/pom.xml 5(+5 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheModelProvider.java 14(+14 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java 2(+1 -1)
picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java 2(+1 -1)
server/pom.xml 12(+11 -1)
testsuite/integration/pom.xml 12(+11 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java 3(+2 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java 330(+330 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java 11(+10 -1)
testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java 7(+4 -3)
testsuite/tools/pom.xml 12(+11 -1)
Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
index b0c37ac..99237ee 100755
--- a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
@@ -11,9 +11,16 @@ public class CredentialRepresentation {
public static final String CLIENT_CERT = "cert";
protected String type;
- protected String value;
protected String device;
+ // Plain-text value of credential (used for example during import from manually created JSON file)
+ protected String value;
+
+ // Value stored in DB (used for example during export/import)
+ protected String hashedSaltedValue;
+ protected String salt;
+ protected Integer hashIterations;
+
public String getType() {
return type;
}
@@ -37,4 +44,28 @@ public class CredentialRepresentation {
public void setDevice(String device) {
this.device = device;
}
+
+ public String getHashedSaltedValue() {
+ return hashedSaltedValue;
+ }
+
+ public void setHashedSaltedValue(String hashedSaltedValue) {
+ this.hashedSaltedValue = hashedSaltedValue;
+ }
+
+ public String getSalt() {
+ return salt;
+ }
+
+ public void setSalt(String salt) {
+ this.salt = salt;
+ }
+
+ public Integer getHashIterations() {
+ return hashIterations;
+ }
+
+ public void setHashIterations(Integer hashIterations) {
+ this.hashIterations = hashIterations;
+ }
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
index 8751a38..7511de6 100755
--- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
@@ -9,7 +9,6 @@ import java.util.List;
public class OAuthClientRepresentation {
protected String id;
protected String name;
- protected String baseUrl;
protected List<String> redirectUris;
protected List<String> webOrigins;
protected Boolean enabled;
@@ -44,14 +43,6 @@ public class OAuthClientRepresentation {
this.enabled = enabled;
}
- public String getBaseUrl() {
- return baseUrl;
- }
-
- public void setBaseUrl(String baseUrl) {
- this.baseUrl = baseUrl;
- }
-
public List<String> getRedirectUris() {
return redirectUris;
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 4b5380d..6d85877 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -423,4 +423,28 @@ public class RealmRepresentation {
public void setFailureFactor(Integer failureFactor) {
this.failureFactor = failureFactor;
}
+
+ public boolean isAuditEnabled() {
+ return auditEnabled;
+ }
+
+ public void setAuditEnabled(boolean auditEnabled) {
+ this.auditEnabled = auditEnabled;
+ }
+
+ public long getAuditExpiration() {
+ return auditExpiration;
+ }
+
+ public void setAuditExpiration(long auditExpiration) {
+ this.auditExpiration = auditExpiration;
+ }
+
+ public List<String> getAuditListeners() {
+ return auditListeners;
+ }
+
+ public void setAuditListeners(List<String> auditListeners) {
+ this.auditListeners = auditListeners;
+ }
}
export-import/export-import-api/pom.xml 26(+26 -0)
diff --git a/export-import/export-import-api/pom.xml b/export-import/export-import-api/pom.xml
index 19db6e5..1b4dc0a 100755
--- a/export-import/export-import-api/pom.xml
+++ b/export-import/export-import-api/pom.xml
@@ -26,6 +26,32 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-invalidation-cache-model</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </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>
</dependencies>
<build>
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportManager.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportManager.java
new file mode 100644
index 0000000..caedb36
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportImportManager.java
@@ -0,0 +1,63 @@
+package org.keycloak.exportimport;
+
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportManager {
+
+ private static final Logger logger = Logger.getLogger(ExportImportManager.class);
+
+ public void checkExportImport(KeycloakSessionFactory sessionFactory) {
+ String exportImportAction = ExportImportConfig.getAction();
+ String realmName = ExportImportConfig.getRealmName();
+
+ boolean export = false;
+ boolean importt = false;
+ if (ExportImportConfig.ACTION_EXPORT.equals(exportImportAction)) {
+ export = true;
+ } else if (ExportImportConfig.ACTION_IMPORT.equals(exportImportAction)) {
+ importt = true;
+ }
+
+ if (export || importt) {
+ String exportImportProviderId = ExportImportConfig.getProvider();
+ logger.debug("Will use provider: " + exportImportProviderId);
+ KeycloakSession session = sessionFactory.create();
+
+ try {
+ if (export) {
+ ExportProvider exportProvider = session.getProvider(ExportProvider.class, exportImportProviderId);
+
+ if (realmName == null) {
+ logger.info("Full model export requested");
+ exportProvider.exportModel(sessionFactory);
+ } else {
+ logger.infof("Export of realm '%s' requested", realmName);
+ exportProvider.exportRealm(sessionFactory, realmName);
+ }
+ logger.info("Export finished successfully");
+ } else {
+ ImportProvider importProvider = session.getProvider(ImportProvider.class, exportImportProviderId);
+ Strategy strategy = ExportImportConfig.getStrategy();
+ if (realmName == null) {
+ logger.infof("Full model import requested. Strategy: %s", strategy.toString());
+ importProvider.importModel(sessionFactory, strategy);
+ } else {
+ logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());
+ importProvider.importRealm(sessionFactory, realmName, strategy);
+ }
+ logger.info("Import finished successfully");
+ }
+ } catch (Throwable ioe) {
+ logger.error("Error during export/import", ioe);
+ } finally {
+ session.close();
+ }
+ }
+ }
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportProvider.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportProvider.java
new file mode 100644
index 0000000..1a0d6a0
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportProvider.java
@@ -0,0 +1,18 @@
+package org.keycloak.exportimport;
+
+import java.io.IOException;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportProvider extends Provider {
+
+ void exportModel(KeycloakSessionFactory factory) throws IOException;
+
+ void exportRealm(KeycloakSessionFactory factory, String realmName) throws IOException;
+
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
new file mode 100644
index 0000000..6ec2960
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
@@ -0,0 +1,26 @@
+package org.keycloak.exportimport;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportSpi implements Spi {
+
+ @Override
+ public String getName() {
+ return "export";
+ }
+
+ @Override
+ public Class<? extends Provider> getProviderClass() {
+ return ExportProvider.class;
+ }
+
+ @Override
+ public Class<? extends ProviderFactory> getProviderFactoryClass() {
+ return ExportProviderFactory.class;
+ }
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProvider.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProvider.java
new file mode 100644
index 0000000..9134516
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProvider.java
@@ -0,0 +1,17 @@
+package org.keycloak.exportimport;
+
+import java.io.IOException;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ImportProvider extends Provider {
+
+ void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException;
+
+ void importRealm(KeycloakSessionFactory factory, String realmName, Strategy strategy) throws IOException;
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
new file mode 100644
index 0000000..b562f3f
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
@@ -0,0 +1,26 @@
+package org.keycloak.exportimport;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ImportSpi implements Spi {
+
+ @Override
+ public String getName() {
+ return "import";
+ }
+
+ @Override
+ public Class<? extends Provider> getProviderClass() {
+ return ImportProvider.class;
+ }
+
+ @Override
+ public Class<? extends ProviderFactory> getProviderFactoryClass() {
+ return ImportProviderFactory.class;
+ }
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/Strategy.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/Strategy.java
new file mode 100644
index 0000000..6bbd70d
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/Strategy.java
@@ -0,0 +1,10 @@
+package org.keycloak.exportimport;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public enum Strategy {
+
+ IGNORE_EXISTING, // Ignore existing user entries
+ OVERWRITE_EXISTING // Overwrite existing user entries
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java
new file mode 100644
index 0000000..748fe1f
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java
@@ -0,0 +1,15 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * Task to be executed inside transaction
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportImportJob {
+
+ public void run(KeycloakSession session) throws IOException;
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java
new file mode 100644
index 0000000..b73a4c0
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java
@@ -0,0 +1,47 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportUtils {
+
+ /**
+ * Wrap given runnable job into KeycloakTransaction.
+ *
+ * @param factory
+ * @param job
+ */
+ public static void runJobInTransaction(KeycloakSessionFactory factory, ExportImportJob job) throws IOException {
+ KeycloakSession session = factory.create();
+ KeycloakTransaction tx = session.getTransaction();
+ try {
+ tx.begin();
+ job.run(session);
+
+ if (tx.isActive()) {
+ if (tx.getRollbackOnly()) {
+ tx.rollback();
+ } else {
+ tx.commit();
+ }
+ }
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ session.close();
+ }
+ }
+
+ public static String getMasterRealmAdminApplicationName(RealmModel realm) {
+ return realm.getName() + "-realm";
+ }
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportUtils.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
new file mode 100644
index 0000000..4c96812
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
@@ -0,0 +1,365 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.iharder.Base64;
+import org.codehaus.jackson.JsonEncoding;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.keycloak.exportimport.Strategy;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.OAuthClientModel;
+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.utils.ModelToRepresentation;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
+import org.keycloak.representations.idm.ClaimRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.OAuthClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.RolesRepresentation;
+import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.SocialLinkRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportUtils {
+
+ public static RealmRepresentation exportRealm(RealmModel realm, boolean includeUsers) {
+ RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm);
+
+ // Audit
+ rep.setAuditEnabled(realm.isAuditEnabled());
+ if (realm.getAuditExpiration() != 0) {
+ rep.setAuditExpiration(realm.getAuditExpiration());
+ }
+
+ if (realm.getAuditListeners() != null) {
+ rep.setAuditListeners(new LinkedList<String>(realm.getAuditListeners()));
+ }
+
+ // Applications
+ List<ApplicationModel> applications = realm.getApplications();
+ List<ApplicationRepresentation> appReps = new ArrayList<ApplicationRepresentation>();
+ for (ApplicationModel app : applications) {
+ ApplicationRepresentation appRep = exportApplication(app);
+ appReps.add(appRep);
+ }
+ rep.setApplications(appReps);
+
+ // OAuth clients
+ List<OAuthClientModel> oauthClients = realm.getOAuthClients();
+ List<OAuthClientRepresentation> oauthClientReps = new ArrayList<OAuthClientRepresentation>();
+ for (OAuthClientModel oauthClient : oauthClients) {
+ OAuthClientRepresentation clientRep = ModelToRepresentation.toRepresentation(oauthClient);
+ oauthClientReps.add(clientRep);
+ }
+ rep.setOauthClients(oauthClientReps);
+
+ // Roles
+ List<RoleRepresentation> realmRoleReps = null;
+ Map<String, List<RoleRepresentation>> appRolesReps = new HashMap<String, List<RoleRepresentation>>();
+
+ Set<RoleModel> realmRoles = realm.getRoles();
+ if (realmRoles != null && realmRoles.size() > 0) {
+ realmRoleReps = exportRoles(realmRoles);
+ }
+ for (ApplicationModel app : applications) {
+ Set<RoleModel> currentAppRoles = app.getRoles();
+ List<RoleRepresentation> currentAppRoleReps = exportRoles(currentAppRoles);
+ appRolesReps.put(app.getName(), currentAppRoleReps);
+ }
+
+ RolesRepresentation rolesRep = new RolesRepresentation();
+ if (realmRoleReps != null) {
+ rolesRep.setRealm(realmRoleReps);
+ }
+ if (appRolesReps.size() > 0) {
+ rolesRep.setApplication(appRolesReps);
+ }
+ rep.setRoles(rolesRep);
+
+ // Scopes
+ List<ClientModel> allClients = new ArrayList<ClientModel>(applications);
+ allClients.addAll(realm.getOAuthClients());
+ Map<String, List<ScopeMappingRepresentation>> appScopeReps = new HashMap<String, List<ScopeMappingRepresentation>>();
+
+ for (ClientModel client : allClients) {
+ Set<RoleModel> clientScopes = client.getScopeMappings();
+ ScopeMappingRepresentation scopeMappingRep = null;
+ for (RoleModel scope : clientScopes) {
+ if (scope.getContainer() instanceof RealmModel) {
+ if (scopeMappingRep == null) {
+ scopeMappingRep = rep.scopeMapping(client.getClientId());
+ }
+ scopeMappingRep.role(scope.getName());
+ } else {
+ ApplicationModel app = (ApplicationModel)scope.getContainer();
+ String appName = app.getName();
+ List<ScopeMappingRepresentation> currentAppScopes = appScopeReps.get(appName);
+ if (currentAppScopes == null) {
+ currentAppScopes = new ArrayList<ScopeMappingRepresentation>();
+ appScopeReps.put(appName, currentAppScopes);
+ }
+
+ ScopeMappingRepresentation currentClientScope = null;
+ for (ScopeMappingRepresentation scopeMapping : currentAppScopes) {
+ if (scopeMapping.getClient().equals(client.getClientId())) {
+ currentClientScope = scopeMapping;
+ break;
+ }
+ }
+ if (currentClientScope == null) {
+ currentClientScope = new ScopeMappingRepresentation();
+ currentClientScope.setClient(client.getClientId());
+ currentAppScopes.add(currentClientScope);
+ }
+ currentClientScope.role(scope.getName());
+ }
+ }
+ }
+
+ if (appScopeReps.size() > 0) {
+ rep.setApplicationScopeMappings(appScopeReps);
+ }
+
+ // Finally users if needed
+ if (includeUsers) {
+ List<UserModel> allUsers = realm.getUsers();
+ List<UserRepresentation> users = new ArrayList<UserRepresentation>();
+ for (UserModel user : allUsers) {
+ UserRepresentation userRep = exportUser(realm, user);
+ users.add(userRep);
+ }
+
+ if (users.size() > 0) {
+ rep.setUsers(users);
+ }
+ }
+
+ return rep;
+ }
+
+ /**
+ * Full export of application including claims and secret
+ * @param app
+ * @return full ApplicationRepresentation
+ */
+ public static ApplicationRepresentation exportApplication(ApplicationModel app) {
+ ApplicationRepresentation appRep = ModelToRepresentation.toRepresentation(app);
+
+ appRep.setSecret(app.getSecret());
+ ClaimRepresentation claimRep = ModelToRepresentation.toRepresentation((ClientModel)app);
+ appRep.setClaims(claimRep);
+ return appRep;
+ }
+
+ public static List<RoleRepresentation> exportRoles(Collection<RoleModel> roles) {
+ List<RoleRepresentation> roleReps = new ArrayList<RoleRepresentation>();
+
+ for (RoleModel role : roles) {
+ RoleRepresentation roleRep = exportRole(role);
+ roleReps.add(roleRep);
+ }
+ return roleReps;
+ }
+
+ public static List<String> getRoleNames(Collection<RoleModel> roles) {
+ List<String> roleNames = new ArrayList<String>();
+ for (RoleModel role : roles) {
+ roleNames.add(role.getName());
+ }
+ return roleNames;
+ }
+
+ /**
+ * Full export of role including composite roles
+ * @param role
+ * @return RoleRepresentation with all stuff filled (including composite roles)
+ */
+ public static RoleRepresentation exportRole(RoleModel role) {
+ RoleRepresentation roleRep = ModelToRepresentation.toRepresentation(role);
+
+ Set<RoleModel> composites = role.getComposites();
+ if (composites != null && composites.size() > 0) {
+ Set<String> compositeRealmRoles = null;
+ Map<String, List<String>> compositeAppRoles = null;
+
+ for (RoleModel composite : composites) {
+ RoleContainerModel crContainer = composite.getContainer();
+ if (crContainer instanceof RealmModel) {
+
+ if (compositeRealmRoles == null) {
+ compositeRealmRoles = new HashSet<String>();
+ }
+ compositeRealmRoles.add(composite.getName());
+ } else {
+ if (compositeAppRoles == null) {
+ compositeAppRoles = new HashMap<String, List<String>>();
+ }
+
+ ApplicationModel app = (ApplicationModel)crContainer;
+ String appName = app.getName();
+ List<String> currentAppComposites = compositeAppRoles.get(appName);
+ if (currentAppComposites == null) {
+ currentAppComposites = new ArrayList<String>();
+ compositeAppRoles.put(appName, currentAppComposites);
+ }
+ currentAppComposites.add(composite.getName());
+ }
+ }
+
+ RoleRepresentation.Composites compRep = new RoleRepresentation.Composites();
+ if (compositeRealmRoles != null) {
+ compRep.setRealm(compositeRealmRoles);
+ }
+ if (compositeAppRoles != null) {
+ compRep.setApplication(compositeAppRoles);
+ }
+
+ roleRep.setComposites(compRep);
+ }
+
+ return roleRep;
+ }
+
+ /**
+ * Full export of user (including role mappings and credentials)
+ *
+ * @param user
+ * @return fully exported user representation
+ */
+ public static UserRepresentation exportUser(RealmModel realm, UserModel user) {
+ UserRepresentation userRep = ModelToRepresentation.toRepresentation(user);
+
+ // AuthenticationLink
+ AuthenticationLinkModel authLink = user.getAuthenticationLink();
+ if (authLink != null) {
+ AuthenticationLinkRepresentation authLinkRepresentation = exportAuthLink(authLink);
+ userRep.setAuthenticationLink(authLinkRepresentation);
+ }
+
+ // Social links
+ Set<SocialLinkModel> socialLinks = realm.getSocialLinks(user);
+ List<SocialLinkRepresentation> socialLinkReps = new ArrayList<SocialLinkRepresentation>();
+ for (SocialLinkModel socialLink : socialLinks) {
+ SocialLinkRepresentation socialLinkRep = exportSocialLink(socialLink);
+ socialLinkReps.add(socialLinkRep);
+ }
+ if (socialLinkReps.size() > 0) {
+ userRep.setSocialLinks(socialLinkReps);
+ }
+
+ // Role mappings
+ Set<RoleModel> roles = user.getRoleMappings();
+ List<String> realmRoleNames = new ArrayList<String>();
+ Map<String, List<String>> appRoleNames = new HashMap<String, List<String>>();
+ for (RoleModel role : roles) {
+ if (role.getContainer() instanceof RealmModel) {
+ realmRoleNames.add(role.getName());
+ } else {
+ ApplicationModel app = (ApplicationModel)role.getContainer();
+ String appName = app.getName();
+ List<String> currentAppRoles = appRoleNames.get(appName);
+ if (currentAppRoles == null) {
+ currentAppRoles = new ArrayList<String>();
+ appRoleNames.put(appName, currentAppRoles);
+ }
+
+ currentAppRoles.add(role.getName());
+ }
+ }
+
+ if (realmRoleNames.size() > 0) {
+ userRep.setRealmRoles(realmRoleNames);
+ }
+ if (appRoleNames.size() > 0) {
+ userRep.setApplicationRoles(appRoleNames);
+ }
+
+ // Credentials
+ List<UserCredentialValueModel> creds = user.getCredentialsDirectly();
+ List<CredentialRepresentation> credReps = new ArrayList<CredentialRepresentation>();
+ for (UserCredentialValueModel cred : creds) {
+ CredentialRepresentation credRep = exportCredential(cred);
+ credReps.add(credRep);
+ }
+ userRep.setCredentials(credReps);
+
+ return userRep;
+ }
+
+ public static AuthenticationLinkRepresentation exportAuthLink(AuthenticationLinkModel authLinkModel) {
+ AuthenticationLinkRepresentation authLinkRep = new AuthenticationLinkRepresentation();
+ authLinkRep.setAuthProvider(authLinkModel.getAuthProvider());
+ authLinkRep.setAuthUserId(authLinkModel.getAuthUserId());
+ return authLinkRep;
+ }
+
+ public static SocialLinkRepresentation exportSocialLink(SocialLinkModel socialLink) {
+ SocialLinkRepresentation socialLinkRep = new SocialLinkRepresentation();
+ socialLinkRep.setSocialProvider(socialLink.getSocialProvider());
+ socialLinkRep.setSocialUserId(socialLink.getSocialUserId());
+ socialLinkRep.setSocialUsername(socialLink.getSocialUsername());
+ return socialLinkRep;
+ }
+
+ public static CredentialRepresentation exportCredential(UserCredentialValueModel userCred) {
+ CredentialRepresentation credRep = new CredentialRepresentation();
+ credRep.setType(userCred.getType());
+ credRep.setDevice(userCred.getDevice());
+ credRep.setHashedSaltedValue(userCred.getValue());
+ credRep.setSalt(Base64.encodeBytes(userCred.getSalt()));
+ credRep.setHashIterations(userCred.getHashIterations());
+ return credRep;
+ }
+
+ // Streaming API
+
+ public static void exportUsersToStream(RealmModel realm, List<UserModel> usersToExport, ObjectMapper mapper, OutputStream os) throws IOException {
+ JsonFactory factory = mapper.getJsonFactory();
+ JsonGenerator generator = factory.createJsonGenerator(os, JsonEncoding.UTF8);
+ try {
+ if (mapper.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
+ generator.useDefaultPrettyPrinter();
+ }
+ generator.writeStartObject();
+ generator.writeStringField("realm", realm.getName());
+ // generator.writeStringField("strategy", strategy.toString());
+ generator.writeFieldName("users");
+ generator.writeStartArray();
+
+ for (UserModel user : usersToExport) {
+ UserRepresentation userRep = ExportUtils.exportUser(realm, user);
+ generator.writeObject(userRep);
+ }
+
+ generator.writeEndArray();
+ generator.writeEndObject();
+ } finally {
+ generator.close();
+ }
+ }
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ImportUtils.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
new file mode 100644
index 0000000..e57c750
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
@@ -0,0 +1,211 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonEncoding;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.io.SerializedString;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.exportimport.Strategy;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelProvider;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ImportUtils {
+
+ private static final Logger logger = Logger.getLogger(ImportUtils.class);
+
+ /**
+ * Fully import realm from representation, save it to model and return model of newly created realm
+ *
+ * @param session
+ * @param rep
+ * @param strategy specifies whether to overwrite or ignore existing realm or user entries
+ * @return newly imported realm (or existing realm if ignoreExisting is true and realm of this name already exists)
+ */
+ public static RealmModel importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) {
+ String realmName = rep.getRealm();
+ ModelProvider model = session.model();
+ RealmModel realm = model.getRealmByName(realmName);
+
+ if (realm != null) {
+ if (strategy == Strategy.IGNORE_EXISTING) {
+ logger.infof("Realm '%s' already exists. Import skipped", realmName);
+ return realm;
+ } else {
+ logger.infof("Realm '%s' already exists. Removing it before import", realmName);
+ if (Config.getAdminRealm().equals(realm.getId())) {
+ realm.setMasterAdminApp(null);
+ }
+ model.removeRealm(realm.getId());
+ }
+ }
+
+ realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName);
+
+ RepresentationToModel.importRealm(rep, realm);
+
+ refreshMasterAdminApps(model, realm);
+
+ logger.infof("Realm '%s' imported", realmName);
+ return realm;
+ }
+
+ private static void refreshMasterAdminApps(ModelProvider model, RealmModel realm) {
+ String adminRealmId = Config.getAdminRealm();
+ if (adminRealmId.equals(realm.getId())) {
+ // We just imported master realm. All 'masterAdminApps' need to be refreshed
+ RealmModel adminRealm = realm;
+ for (RealmModel currentRealm : model.getRealms()) {
+ ApplicationModel masterApp = adminRealm.getApplicationByName(ExportImportUtils.getMasterRealmAdminApplicationName(currentRealm));
+ if (masterApp != null) {
+ currentRealm.setMasterAdminApp(masterApp);
+ } else {
+ setupMasterAdminManagement(model, currentRealm);
+ }
+ }
+ } else {
+ // Need to refresh masterApp for current realm
+ RealmModel adminRealm = model.getRealm(adminRealmId);
+ ApplicationModel masterApp = adminRealm.getApplicationByName(ExportImportUtils.getMasterRealmAdminApplicationName(realm));
+ if (masterApp != null) {
+ realm.setMasterAdminApp(masterApp);
+ } else {
+ setupMasterAdminManagement(model, realm);
+ }
+ }
+ }
+
+ // TODO: We need method here, so we are able to refresh masterAdmin applications after import. Should be RealmManager moved to model/api instead?
+ public static void setupMasterAdminManagement(ModelProvider model, RealmModel realm) {
+ RealmModel adminRealm;
+ RoleModel adminRole;
+
+ if (realm.getName().equals(Config.getAdminRealm())) {
+ adminRealm = realm;
+
+ adminRole = realm.addRole(AdminRoles.ADMIN);
+
+ RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
+ adminRole.addCompositeRole(createRealmRole);
+ } else {
+ adminRealm = model.getRealmByName(Config.getAdminRealm());
+ adminRole = adminRealm.getRole(AdminRoles.ADMIN);
+ }
+
+ ApplicationModel realmAdminApp = KeycloakModelUtils.createApplication(adminRealm, ExportImportUtils.getMasterRealmAdminApplicationName(realm));
+ realmAdminApp.setBearerOnly(true);
+ realm.setMasterAdminApp(realmAdminApp);
+
+ for (String r : AdminRoles.ALL_REALM_ROLES) {
+ RoleModel role = realmAdminApp.addRole(r);
+ adminRole.addCompositeRole(role);
+ }
+ }
+
+
+ /**
+ * Fully import realm (or more realms from particular stream)
+ *
+ * @param session
+ * @param mapper
+ * @param is
+ * @param strategy
+ * @throws IOException
+ */
+ public static void importFromStream(KeycloakSession session, ObjectMapper mapper, InputStream is, Strategy strategy) throws IOException {
+ JsonFactory factory = mapper.getJsonFactory();
+ JsonParser parser = factory.createJsonParser(is);
+ try {
+ parser.nextToken();
+
+ if (parser.getCurrentToken() == JsonToken.START_ARRAY) {
+ // Case with more realms in stream
+ parser.nextToken();
+ while (parser.getCurrentToken() == JsonToken.START_OBJECT) {
+ RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
+ parser.nextToken();
+ importRealm(session, realmRep, strategy);
+ }
+ } else if (parser.getCurrentToken() == JsonToken.START_OBJECT) {
+ // Case with single realm in stream
+ RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
+ importRealm(session, realmRep, strategy);
+ }
+ } finally {
+ parser.close();
+ }
+ }
+
+ // Assuming that it's invoked inside transaction
+ public static void importUsersFromStream(KeycloakSession session, String realmName, ObjectMapper mapper, InputStream is) throws IOException {
+ ModelProvider model = session.model();
+ JsonFactory factory = mapper.getJsonFactory();
+ JsonParser parser = factory.createJsonParser(is);
+ try {
+ parser.nextToken();
+
+ while (parser.nextToken() == JsonToken.FIELD_NAME) {
+ if ("realm".equals(parser.getText())) {
+ parser.nextToken();
+ String currRealmName = parser.getText();
+ if (!currRealmName.equals(realmName)) {
+ throw new IllegalStateException("Trying to import users into invalid realm. Realm name: " + realmName + ", Expected realm name: " + realmName);
+ }
+ } else if ("users".equals(parser.getText())) {
+ parser.nextToken();
+
+ if (parser.getCurrentToken() == JsonToken.START_ARRAY) {
+ parser.nextToken();
+ }
+
+ // TODO: support for more transactions per single users file (if needed)
+ List<UserRepresentation> userReps = new ArrayList<UserRepresentation>();
+ while (parser.getCurrentToken() == JsonToken.START_OBJECT) {
+ UserRepresentation user = parser.readValueAs(UserRepresentation.class);
+ userReps.add(user);
+ parser.nextToken();
+ }
+
+ importUsers(model, realmName, userReps);
+
+ if (parser.getCurrentToken() == JsonToken.END_ARRAY) {
+ parser.nextToken();
+ }
+ }
+ }
+ } finally {
+ parser.close();
+ }
+ }
+
+ private static void importUsers(ModelProvider model, String realmName, List<UserRepresentation> userReps) {
+ RealmModel realm = model.getRealmByName(realmName);
+ Map<String, ApplicationModel> apps = realm.getApplicationNameMap();
+ for (UserRepresentation user : userReps) {
+ RepresentationToModel.createUser(realm, user, apps);
+ }
+ }
+
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java
new file mode 100644
index 0000000..a98ee98
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java
@@ -0,0 +1,116 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ExportProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class MultipleStepsExportProvider implements ExportProvider {
+
+ protected final Logger logger = Logger.getLogger(getClass());
+
+ @Override
+ public void exportModel(KeycloakSessionFactory factory) throws IOException {
+ final RealmsHolder holder = new RealmsHolder();
+
+ // Import users into same file with realm
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) {
+ List<RealmModel> realms = session.model().getRealms();
+ holder.realms = realms;
+ }
+
+ });
+
+ for (RealmModel realm : holder.realms) {
+ exportRealm(factory, realm.getName());
+ }
+ }
+
+ @Override
+ public void exportRealm(KeycloakSessionFactory factory, final String realmName) throws IOException {
+ final int usersPerFile = ExportImportConfig.getUsersPerFile();
+ final UsersHolder usersHolder = new UsersHolder();
+ final boolean exportUsersIntoSameFile = usersPerFile < 0;
+
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ RealmModel realm = session.model().getRealmByName(realmName);
+ RealmRepresentation rep = ExportUtils.exportRealm(realm, exportUsersIntoSameFile);
+ writeRealm(realmName + "-realm.json", rep);
+ logger.info("Realm '" + realmName + "' - data exported");
+
+ // Count total number of users
+ if (!exportUsersIntoSameFile) {
+ // TODO: getUsersCount method on model
+ usersHolder.totalCount = realm.getUsers().size();
+ }
+ }
+
+ });
+
+ if (!exportUsersIntoSameFile) {
+
+ usersHolder.currentPageStart = 0;
+
+ // usersPerFile==0 means exporting all users into single file (but separate to realm)
+ final int countPerPage = usersPerFile == 0 ? usersHolder.totalCount : usersPerFile;
+
+ while (usersHolder.currentPageStart < usersHolder.totalCount) {
+ if (usersHolder.currentPageStart + countPerPage < usersHolder.totalCount) {
+ usersHolder.currentPageEnd = usersHolder.currentPageStart + countPerPage;
+ } else {
+ usersHolder.currentPageEnd = usersHolder.totalCount;
+ }
+
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ RealmModel realm = session.model().getRealmByName(realmName);
+ // TODO: pagination
+ List<UserModel> users = realm.getUsers();
+ usersHolder.users = users.subList(usersHolder.currentPageStart, usersHolder.currentPageEnd);
+
+ writeUsers(realmName + "-users-" + (usersHolder.currentPageStart / countPerPage) + ".json", realm, usersHolder.users);
+
+ logger.info("Users " + usersHolder.currentPageStart + "-" + usersHolder.currentPageEnd + " exported");
+ }
+
+ });
+
+ usersHolder.currentPageStart = usersHolder.currentPageEnd;
+ }
+ }
+ }
+
+ protected abstract void writeRealm(String fileName, RealmRepresentation rep) throws IOException;
+
+ protected abstract void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException;
+
+ public static class RealmsHolder {
+ List<RealmModel> realms;
+
+ }
+
+ public static class UsersHolder {
+ List<UserModel> users;
+ int totalCount;
+ int currentPageStart;
+ int currentPageEnd;
+ }
+}
diff --git a/export-import/export-import-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/export-import/export-import-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000..9302943
--- /dev/null
+++ b/export-import/export-import-api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,2 @@
+org.keycloak.exportimport.ExportSpi
+org.keycloak.exportimport.ImportSpi
\ No newline at end of file
export-import/export-import-dir/pom.xml 66(+66 -0)
diff --git a/export-import/export-import-dir/pom.xml b/export-import/export-import-dir/pom.xml
new file mode 100644
index 0000000..4cd8dc1
--- /dev/null
+++ b/export-import/export-import-dir/pom.xml
@@ -0,0 +1,66 @@
+<?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-dir</artifactId>
+ <name>Keycloak Export Import To Directory</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.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>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <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-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
new file mode 100644
index 0000000..ef29af9
--- /dev/null
+++ b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
@@ -0,0 +1,107 @@
+package org.keycloak.exportimport.dir;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.Strategy;
+import org.keycloak.exportimport.util.ExportImportJob;
+import org.keycloak.exportimport.util.ExportImportUtils;
+import org.keycloak.exportimport.util.ImportUtils;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DirImportProvider implements ImportProvider {
+
+ private static final Logger logger = Logger.getLogger(DirImportProvider.class);
+
+ private final File rootDirectory;
+
+ public DirImportProvider() {
+ // 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());
+ }
+
+ public DirImportProvider(File rootDirectory) {
+ this.rootDirectory = rootDirectory;
+
+ logger.infof("Importing from directory %s", this.rootDirectory.getAbsolutePath());
+ }
+
+ @Override
+ public void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException {
+ File[] realmFiles = this.rootDirectory.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return (name.endsWith("-realm.json"));
+ }
+ });
+
+ for (File file : realmFiles) {
+ String fileName = file.getName();
+
+ // Parse "foo" from "foo-realm.json"
+ String realmName = fileName.substring(0, fileName.length() - 11);
+ importRealm(factory, realmName, strategy);
+ }
+ }
+
+ @Override
+ public void importRealm(KeycloakSessionFactory factory, final String realmName, final Strategy strategy) throws IOException {
+ File realmFile = new File(this.rootDirectory + File.separator + realmName + "-realm.json");
+ File[] userFiles = this.rootDirectory.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return (name.startsWith(realmName)) && (name.endsWith(".json")) && (name.substring(realmName.length()).contains("-users-") );
+ }
+ });
+
+ // Import realm first
+ FileInputStream is = new FileInputStream(realmFile);
+ final RealmRepresentation realmRep = JsonSerialization.readValue(is, RealmRepresentation.class);
+
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ ImportUtils.importRealm(session, realmRep, strategy);
+ }
+
+ });
+
+ // Import users
+ for (File userFile : userFiles) {
+ final FileInputStream fis = new FileInputStream(userFile);
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ ImportUtils.importUsersFromStream(session, realmName, JsonSerialization.mapper, fis);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void close() {
+
+ }
+}
diff --git a/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProviderFactory.java b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProviderFactory.java
new file mode 100644
index 0000000..3e39a77
--- /dev/null
+++ b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProviderFactory.java
@@ -0,0 +1,34 @@
+package org.keycloak.exportimport.dir;
+
+import java.io.File;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.ImportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DirImportProviderFactory implements ImportProviderFactory {
+
+ @Override
+ public ImportProvider create(KeycloakSession session) {
+ String dir = ExportImportConfig.getDir();
+ return dir!=null ? new DirImportProvider(new File(dir)) : new DirImportProvider();
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return DirExportProviderFactory.PROVIDER_ID;
+ }
+}
diff --git a/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory b/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
new file mode 100644
index 0000000..8a8fea4
--- /dev/null
+++ b/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.dir.DirExportProviderFactory
\ No newline at end of file
diff --git a/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory b/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
new file mode 100644
index 0000000..ba9874e
--- /dev/null
+++ b/export-import/export-import-dir/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.dir.DirImportProviderFactory
\ No newline at end of file
diff --git a/export-import/export-import-single-file/pom.xml b/export-import/export-import-single-file/pom.xml
new file mode 100644
index 0000000..25d65c0
--- /dev/null
+++ b/export-import/export-import-single-file/pom.xml
@@ -0,0 +1,65 @@
+<?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-single-file</artifactId>
+ <name>Keycloak Export Import To Single File</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.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>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <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-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java
new file mode 100644
index 0000000..bd799b9
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java
@@ -0,0 +1,85 @@
+package org.keycloak.exportimport.singlefile;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ExportProvider;
+import org.keycloak.exportimport.util.ExportImportJob;
+import org.keycloak.exportimport.util.ExportImportUtils;
+import org.keycloak.exportimport.util.ExportUtils;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SingleFileExportProvider implements ExportProvider {
+
+ private static final Logger logger = Logger.getLogger(SingleFileExportProvider.class);
+
+ private File file;
+
+ public SingleFileExportProvider(File file) {
+ this.file = file;
+ }
+
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public void exportModel(KeycloakSessionFactory factory) throws IOException {
+ logger.infof("Exporting model into file %s", this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ List<RealmModel> realms = session.model().getRealms();
+ List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
+ for (RealmModel realm : realms) {
+ reps.add(ExportUtils.exportRealm(realm, true));
+ }
+
+ writeToFile(reps);
+ }
+
+ });
+
+ }
+
+ @Override
+ public void exportRealm(KeycloakSessionFactory factory, final String realmName) throws IOException {
+ logger.infof("Exporting realm '%s' into file %s", realmName, this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ RealmModel realm = session.model().getRealmByName(realmName);
+ RealmRepresentation realmRep = ExportUtils.exportRealm(realm, true);
+ writeToFile(realmRep);
+ }
+
+ });
+ }
+
+ @Override
+ public void close() {
+ }
+
+ private ObjectMapper getObjectMapper() {
+ return JsonSerialization.prettyMapper;
+ }
+
+ private void writeToFile(Object reps) throws IOException {
+ FileOutputStream stream = new FileOutputStream(this.file);
+ getObjectMapper().writeValue(stream, reps);
+ }
+}
diff --git a/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProviderFactory.java b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProviderFactory.java
new file mode 100644
index 0000000..614c3ba
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProviderFactory.java
@@ -0,0 +1,36 @@
+package org.keycloak.exportimport.singlefile;
+
+import java.io.File;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ExportProvider;
+import org.keycloak.exportimport.ExportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SingleFileExportProviderFactory implements ExportProviderFactory {
+
+ public static final String PROVIDER_ID = "singleFile";
+
+ @Override
+ public ExportProvider create(KeycloakSession session) {
+ String fileName = ExportImportConfig.getFile();
+ return new SingleFileExportProvider(new File(fileName));
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+}
diff --git a/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProvider.java b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProvider.java
new file mode 100644
index 0000000..07e8cb2
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProvider.java
@@ -0,0 +1,59 @@
+package org.keycloak.exportimport.singlefile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.Strategy;
+import org.keycloak.exportimport.util.ExportImportJob;
+import org.keycloak.exportimport.util.ExportImportUtils;
+import org.keycloak.exportimport.util.ExportUtils;
+import org.keycloak.exportimport.util.ImportUtils;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SingleFileImportProvider implements ImportProvider {
+
+ private static final Logger logger = Logger.getLogger(SingleFileImportProvider.class);
+
+ private File file;
+
+ public SingleFileImportProvider(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public void importModel(KeycloakSessionFactory factory, final Strategy strategy) throws IOException {
+ logger.infof("Full importing from file %s", this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ FileInputStream is = new FileInputStream(file);
+ ImportUtils.importFromStream(session, JsonSerialization.mapper, is, strategy);
+ }
+
+ });
+ }
+
+ @Override
+ public void importRealm(KeycloakSessionFactory factory, String realmName, Strategy strategy) throws IOException {
+ // TODO: import just that single realm in case that file contains many realms?
+ importModel(factory, strategy);
+ }
+
+ @Override
+ public void close() {
+
+ }
+}
diff --git a/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java
new file mode 100644
index 0000000..6e3e732
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java
@@ -0,0 +1,34 @@
+package org.keycloak.exportimport.singlefile;
+
+import java.io.File;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.ImportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SingleFileImportProviderFactory implements ImportProviderFactory {
+
+ @Override
+ public ImportProvider create(KeycloakSession session) {
+ String fileName = ExportImportConfig.getFile();
+ return new SingleFileImportProvider(new File(fileName));
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return SingleFileExportProviderFactory.PROVIDER_ID;
+ }
+}
diff --git a/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory b/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
new file mode 100644
index 0000000..82a1faf
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory
\ No newline at end of file
diff --git a/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory b/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
new file mode 100644
index 0000000..d2192b6
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.singlefile.SingleFileImportProviderFactory
\ No newline at end of file
export-import/export-import-zip/pom.xml 70(+70 -0)
diff --git a/export-import/export-import-zip/pom.xml b/export-import/export-import-zip/pom.xml
new file mode 100644
index 0000000..7738f85
--- /dev/null
+++ b/export-import/export-import-zip/pom.xml
@@ -0,0 +1,70 @@
+<?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-zip</artifactId>
+ <name>Keycloak Export Import To Encrypted ZIP</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.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>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>de.idyl</groupId>
+ <artifactId>winzipaes</artifactId>
+ <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-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProviderFactory.java b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProviderFactory.java
new file mode 100644
index 0000000..03f0147
--- /dev/null
+++ b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProviderFactory.java
@@ -0,0 +1,44 @@
+package org.keycloak.exportimport.zip;
+
+import java.io.File;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ExportProvider;
+import org.keycloak.exportimport.ExportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ZipExportProviderFactory implements ExportProviderFactory {
+
+
+ public static final String PROVIDER_ID = "zip";
+
+ @Override
+ public ExportProvider create(KeycloakSession session) {
+ String fileName = ExportImportConfig.getZipFile();
+ String password = ExportImportConfig.getZipPassword();
+ if (fileName == null) {
+ throw new IllegalArgumentException("ZIP file for export not provided");
+ }
+ if (password == null) {
+ throw new IllegalArgumentException("Password for encrypting ZIP not provided");
+ }
+ return new ZipExportProvider(new File(fileName), password);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+}
diff --git a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java
new file mode 100644
index 0000000..20d3dc7
--- /dev/null
+++ b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java
@@ -0,0 +1,110 @@
+package org.keycloak.exportimport.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.zip.DataFormatException;
+
+import de.idyl.winzipaes.AesZipFileDecrypter;
+import de.idyl.winzipaes.impl.AESDecrypter;
+import de.idyl.winzipaes.impl.AESDecrypterBC;
+import de.idyl.winzipaes.impl.ExtZipEntry;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.Strategy;
+import org.keycloak.exportimport.util.ExportImportJob;
+import org.keycloak.exportimport.util.ExportImportUtils;
+import org.keycloak.exportimport.util.ImportUtils;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ZipImportProvider implements ImportProvider {
+
+ private static final Logger logger = Logger.getLogger(ZipImportProvider.class);
+
+ private final AesZipFileDecrypter decrypter;
+ private final String password;
+
+ public ZipImportProvider(File zipFile, String password) {
+ try {
+ if (!zipFile.exists()) {
+ throw new IllegalStateException("File " + zipFile.getAbsolutePath() + " doesn't exists");
+ }
+
+ AESDecrypter decrypter = new AESDecrypterBC();
+ this.decrypter = new AesZipFileDecrypter(zipFile, decrypter);
+ this.password = password;
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ logger.infof("Importing from ZIP file %s", zipFile.getAbsolutePath());
+ }
+
+ @Override
+ public void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException {
+ for (ExtZipEntry entry : this.decrypter.getEntryList()) {
+ String entryName = entry.getName();
+ if (entryName.endsWith("-realm.json")) {
+ // Parse "foo" from "foo-realm.json"
+ String realmName = entryName.substring(0, entryName.length() - 11);
+ importRealm(factory, realmName, strategy);
+ }
+ }
+ }
+
+ @Override
+ public void importRealm(KeycloakSessionFactory factory, final String realmName, final Strategy strategy) throws IOException {
+ try {
+ // Import realm first
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ this.decrypter.extractEntry(this.decrypter.getEntry(realmName + "-realm.json"), bos, this.password);
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ final RealmRepresentation realmRep = JsonSerialization.mapper.readValue(bis, RealmRepresentation.class);
+
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ ImportUtils.importRealm(session, realmRep, strategy);
+ }
+
+ });
+
+
+ // Import users
+ for (ExtZipEntry entry : this.decrypter.getEntryList()) {
+ String name = entry.getName();
+ if ( (name.startsWith(realmName)) && (name.endsWith(".json")) && (name.substring(realmName.length()).contains("-users-")) ) {
+ bos = new ByteArrayOutputStream();
+ this.decrypter.extractEntry(entry, bos, this.password);
+ final ByteArrayInputStream bis2 = new ByteArrayInputStream(bos.toByteArray());
+
+ ExportImportUtils.runJobInTransaction(factory, new ExportImportJob() {
+
+ @Override
+ public void run(KeycloakSession session) throws IOException {
+ ImportUtils.importUsersFromStream(session, realmName, JsonSerialization.mapper, bis2);
+ }
+ });
+ }
+ }
+ } catch (DataFormatException dfe) {
+ throw new RuntimeException(dfe);
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ this.decrypter.close();
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+}
diff --git a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java
new file mode 100644
index 0000000..9127a8b
--- /dev/null
+++ b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java
@@ -0,0 +1,41 @@
+package org.keycloak.exportimport.zip;
+
+import java.io.File;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.ImportProvider;
+import org.keycloak.exportimport.ImportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ZipImportProviderFactory implements ImportProviderFactory {
+
+ @Override
+ public ImportProvider create(KeycloakSession session) {
+ String fileName = ExportImportConfig.getZipFile();
+ String password = ExportImportConfig.getZipPassword();
+ if (fileName == null) {
+ throw new IllegalArgumentException("ZIP file for import not provided");
+ }
+ if (password == null) {
+ throw new IllegalArgumentException("Password for decrypting ZIP not provided");
+ }
+ return new ZipImportProvider(new File(fileName), password);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return ZipExportProviderFactory.PROVIDER_ID;
+ }
+}
diff --git a/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory b/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
new file mode 100644
index 0000000..dce02f1
--- /dev/null
+++ b/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.zip.ZipExportProviderFactory
\ No newline at end of file
diff --git a/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory b/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
new file mode 100644
index 0000000..b88f372
--- /dev/null
+++ b/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory
@@ -0,0 +1 @@
+org.keycloak.exportimport.zip.ZipImportProviderFactory
\ No newline at end of file
export-import/pom.xml 4(+3 -1)
diff --git a/export-import/pom.xml b/export-import/pom.xml
index b9a5a4d..72468fa 100755
--- a/export-import/pom.xml
+++ b/export-import/pom.xml
@@ -16,7 +16,9 @@
<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>
</modules>
</project>
model/api/pom.xml 5(+5 -0)
diff --git a/model/api/pom.xml b/model/api/pom.xml
index f72d856..d0af4dc 100755
--- a/model/api/pom.xml
+++ b/model/api/pom.xml
@@ -31,6 +31,11 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
diff --git a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index 939eeba..e32fa3e 100644
--- a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -3,6 +3,9 @@ package org.keycloak.models.utils;
import java.io.IOException;
import java.io.StringWriter;
import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Set;
@@ -10,8 +13,11 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import org.bouncycastle.openssl.PEMWriter;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.util.PemUtils;
@@ -65,6 +71,30 @@ public final class KeycloakModelUtils {
return PemUtils.removeBeginEnd(s);
}
+ public static void generateRealmKeys(RealmModel realm) {
+ KeyPair keyPair = null;
+ try {
+ keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ realm.setPrivateKey(keyPair.getPrivate());
+ realm.setPublicKey(keyPair.getPublic());
+ }
+
+ public static UserCredentialModel generateSecret(ClientModel app) {
+ UserCredentialModel secret = UserCredentialModel.generateSecret();
+ app.setSecret(secret.getValue());
+ return secret;
+ }
+
+ public static ApplicationModel createApplication(RealmModel realm, String name) {
+ ApplicationModel app = realm.addApplication(name);
+ generateSecret(app);
+
+ return app;
+ }
+
/**
* Deep search if given role is descendant of composite role
*
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
new file mode 100644
index 0000000..b031eac
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -0,0 +1,671 @@
+package org.keycloak.models.utils;
+
+import java.io.IOException;
+import java.net.URI;
+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 net.iharder.Base64;
+import org.jboss.logging.Logger;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.AuthenticationProviderModel;
+import org.keycloak.models.ClaimMask;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+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.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
+import org.keycloak.representations.idm.AuthenticationProviderRepresentation;
+import org.keycloak.representations.idm.ClaimRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.OAuthClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.SocialLinkRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+public class RepresentationToModel {
+
+ private static Logger logger = Logger.getLogger(RepresentationToModel.class);
+
+ public static void importRealm(RealmRepresentation rep, RealmModel newRealm) {
+ newRealm.setName(rep.getRealm());
+ if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
+ if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
+ if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
+ if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
+ if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
+ if (rep.getWaitIncrementSeconds() != null) newRealm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
+ if (rep.getQuickLoginCheckMilliSeconds() != null) newRealm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
+ if (rep.getMaxDeltaTimeSeconds() != null) newRealm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
+ if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor());
+
+ if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore());
+
+ if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
+ else newRealm.setAccessTokenLifespan(300);
+
+ if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
+ else newRealm.setSsoSessionIdleTimeout(600);
+ if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
+ else newRealm.setSsoSessionMaxLifespan(36000);
+
+ if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
+ else newRealm.setAccessCodeLifespan(60);
+
+ if (rep.getAccessCodeLifespanUserAction() != null)
+ newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
+ else newRealm.setAccessCodeLifespanUserAction(300);
+
+ if (rep.isSslNotRequired() != null) newRealm.setSslNotRequired(rep.isSslNotRequired());
+ if (rep.isPasswordCredentialGrantAllowed() != null) newRealm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
+ if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
+ if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
+ if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
+ if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
+ if (rep.isUpdateProfileOnInitialSocialLogin() != null)
+ newRealm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
+ if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
+ KeycloakModelUtils.generateRealmKeys(newRealm);
+ } else {
+ newRealm.setPrivateKeyPem(rep.getPrivateKey());
+ newRealm.setPublicKeyPem(rep.getPublicKey());
+ }
+ if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
+ if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
+ if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
+ if (rep.getEmailTheme() != null) newRealm.setEmailTheme(rep.getEmailTheme());
+
+ if (rep.getRequiredCredentials() != null) {
+ for (String requiredCred : rep.getRequiredCredentials()) {
+ addRequiredCredential(newRealm, requiredCred);
+ }
+ } else {
+ addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
+ }
+
+ if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
+
+ if (rep.getApplications() != null) {
+ Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
+ }
+
+ if (rep.getRoles() != null) {
+ if (rep.getRoles().getRealm() != null) { // realm roles
+ for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
+ createRole(newRealm, roleRep);
+ }
+ }
+ if (rep.getRoles().getApplication() != null) {
+ for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
+ ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
+ if (app == null) {
+ throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
+ }
+ for (RoleRepresentation roleRep : entry.getValue()) {
+ // Application role may already exists (for example if it is defaultRole)
+ RoleModel role = app.getRole(roleRep.getName());
+ if (role == null) {
+ role = app.addRole(roleRep.getName());
+ }
+ role.setDescription(roleRep.getDescription());
+ }
+ }
+ }
+ // now that all roles are created, re-iterate and set up composites
+ if (rep.getRoles().getRealm() != null) { // realm roles
+ for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
+ RoleModel role = newRealm.getRole(roleRep.getName());
+ addComposites(role, roleRep, newRealm);
+ }
+ }
+ if (rep.getRoles().getApplication() != null) {
+ for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
+ ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
+ if (app == null) {
+ throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
+ }
+ for (RoleRepresentation roleRep : entry.getValue()) {
+ RoleModel role = app.getRole(roleRep.getName());
+ addComposites(role, roleRep, newRealm);
+ }
+ }
+ }
+ }
+
+
+ if (rep.getDefaultRoles() != null) {
+ for (String roleString : rep.getDefaultRoles()) {
+ newRealm.addDefaultRole(roleString.trim());
+ }
+ }
+
+ if (rep.getOauthClients() != null) {
+ createOAuthClients(rep, newRealm);
+ }
+
+
+ // Now that all possible roles and applications are created, create scope mappings
+
+ Map<String, ApplicationModel> appMap = newRealm.getApplicationNameMap();
+
+ if (rep.getApplicationScopeMappings() != null) {
+
+ for (Map.Entry<String, List<ScopeMappingRepresentation>> entry : rep.getApplicationScopeMappings().entrySet()) {
+ ApplicationModel app = appMap.get(entry.getKey());
+ if (app == null) {
+ throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
+ }
+ createApplicationScopeMappings(newRealm, app, entry.getValue());
+ }
+ }
+
+ if (rep.getScopeMappings() != null) {
+ for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
+ ClientModel client = newRealm.findClient(scope.getClient());
+ for (String roleString : scope.getRoles()) {
+ RoleModel role = newRealm.getRole(roleString.trim());
+ if (role == null) {
+ role = newRealm.addRole(roleString.trim());
+ }
+ client.addScopeMapping(role);
+ }
+
+ }
+ }
+
+ if (rep.getSmtpServer() != null) {
+ newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
+ }
+
+ if (rep.getSocialProviders() != null) {
+ newRealm.setSocialConfig(new HashMap(rep.getSocialProviders()));
+ }
+ if (rep.getLdapServer() != null) {
+ newRealm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
+ }
+
+ if (rep.getAuthenticationProviders() != null) {
+ List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
+ newRealm.setAuthenticationProviders(authProviderModels);
+ } else {
+ List<AuthenticationProviderModel> authProviderModels = Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER);
+ newRealm.setAuthenticationProviders(authProviderModels);
+ }
+
+ // create users and their role mappings and social mappings
+
+ if (rep.getUsers() != null) {
+ for (UserRepresentation userRep : rep.getUsers()) {
+ UserModel user = createUser(newRealm, userRep, appMap);
+ }
+ }
+ }
+
+ public static void updateRealm(RealmRepresentation rep, RealmModel realm) {
+ if (rep.getRealm() != null) {
+ realm.setName(rep.getRealm());
+ }
+ if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
+ if (rep.isSocial() != null) realm.setSocial(rep.isSocial());
+ if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected());
+ if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
+ if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
+ if (rep.getWaitIncrementSeconds() != null) realm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
+ if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
+ if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
+ if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor());
+ if (rep.isPasswordCredentialGrantAllowed() != null) realm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
+ if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
+ if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
+ if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
+ if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
+ if (rep.isUpdateProfileOnInitialSocialLogin() != null)
+ realm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
+ if (rep.isSslNotRequired() != null) realm.setSslNotRequired((rep.isSslNotRequired()));
+ if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
+ if (rep.getAccessCodeLifespanUserAction() != null)
+ realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
+ if (rep.getNotBefore() != null) realm.setNotBefore(rep.getNotBefore());
+ if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
+ if (rep.getSsoSessionIdleTimeout() != null) realm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
+ if (rep.getSsoSessionMaxLifespan() != null) realm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
+ if (rep.getRequiredCredentials() != null) {
+ realm.updateRequiredCredentials(rep.getRequiredCredentials());
+ }
+ if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
+ if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
+ if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
+ if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme());
+
+ if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
+
+ if (rep.getDefaultRoles() != null) {
+ realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
+ }
+
+ if (rep.getSmtpServer() != null) {
+ realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
+ }
+
+ if (rep.getSocialProviders() != null) {
+ realm.setSocialConfig(new HashMap(rep.getSocialProviders()));
+ }
+
+ if (rep.getLdapServer() != null) {
+ realm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
+ }
+ if (rep.getAuthenticationProviders() != null) {
+ List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
+ realm.setAuthenticationProviders(authProviderModels);
+ }
+
+ if ("GENERATE".equals(rep.getPublicKey())) {
+ KeycloakModelUtils.generateRealmKeys(realm);
+ }
+ }
+
+ // Basic realm stuff
+
+ public static void addRequiredCredential(RealmModel newRealm, String requiredCred) {
+ newRealm.addRequiredCredential(requiredCred);
+ }
+
+
+ private static List<AuthenticationProviderModel> convertAuthenticationProviders(List<AuthenticationProviderRepresentation> authenticationProviders) {
+ List<AuthenticationProviderModel> result = new ArrayList<AuthenticationProviderModel>();
+
+ for (AuthenticationProviderRepresentation representation : authenticationProviders) {
+ AuthenticationProviderModel model = new AuthenticationProviderModel(representation.getProviderName(),
+ representation.isPasswordUpdateSupported(), representation.getConfig());
+ result.add(model);
+ }
+ return result;
+ }
+
+ // Roles
+
+ public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
+ RoleModel role = roleRep.getId()!=null ? newRealm.addRole(roleRep.getId(), roleRep.getName()) : newRealm.addRole(roleRep.getName());
+ if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
+ }
+
+ private static void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
+ if (roleRep.getComposites() == null) return;
+ if (roleRep.getComposites().getRealm() != null) {
+ for (String roleStr : roleRep.getComposites().getRealm()) {
+ RoleModel realmRole = realm.getRole(roleStr);
+ if (realmRole == null) throw new RuntimeException("Unable to find composite realm role: " + roleStr);
+ role.addCompositeRole(realmRole);
+ }
+ }
+ if (roleRep.getComposites().getApplication() != null) {
+ for (Map.Entry<String, List<String>> entry : roleRep.getComposites().getApplication().entrySet()) {
+ ApplicationModel app = realm.getApplicationByName(entry.getKey());
+ if (app == null) {
+ throw new RuntimeException("App doesn't exist in role definitions: " + roleRep.getName());
+ }
+ for (String roleStr : entry.getValue()) {
+ RoleModel appRole = app.getRole(roleStr);
+ if (appRole == null) throw new RuntimeException("Unable to find composite app role: " + roleStr);
+ role.addCompositeRole(appRole);
+ }
+
+ }
+
+ }
+
+ }
+
+ // APPLICATIONS
+
+ private static Map<String, ApplicationModel> createApplications(RealmRepresentation rep, RealmModel realm) {
+ Map<String, ApplicationModel> appMap = new HashMap<String, ApplicationModel>();
+ for (ApplicationRepresentation resourceRep : rep.getApplications()) {
+ ApplicationModel app = createApplication(realm, resourceRep);
+ appMap.put(app.getName(), app);
+ }
+ return appMap;
+ }
+
+ /**
+ * Does not create scope or role mappings!
+ *
+ * @param realm
+ * @param resourceRep
+ * @return
+ */
+ public static ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
+ logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
+ ApplicationModel applicationModel = resourceRep.getId()!=null ? realm.addApplication(resourceRep.getId(), resourceRep.getName()) : realm.addApplication(resourceRep.getName());
+ if (resourceRep.isEnabled() != null) applicationModel.setEnabled(resourceRep.isEnabled());
+ applicationModel.setManagementUrl(resourceRep.getAdminUrl());
+ if (resourceRep.isSurrogateAuthRequired() != null)
+ applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
+ applicationModel.setBaseUrl(resourceRep.getBaseUrl());
+ if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
+ if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
+ applicationModel.updateApplication();
+
+ if (resourceRep.getNotBefore() != null) {
+ applicationModel.setNotBefore(resourceRep.getNotBefore());
+ }
+
+ applicationModel.setSecret(resourceRep.getSecret());
+ if (applicationModel.getSecret() == null) {
+ KeycloakModelUtils.generateSecret(applicationModel);
+ }
+
+
+ if (resourceRep.getRedirectUris() != null) {
+ for (String redirectUri : resourceRep.getRedirectUris()) {
+ applicationModel.addRedirectUri(redirectUri);
+ }
+ }
+ if (resourceRep.getWebOrigins() != null) {
+ for (String webOrigin : resourceRep.getWebOrigins()) {
+ logger.debugv("Application: {0} webOrigin: {1}", resourceRep.getName(), webOrigin);
+ applicationModel.addWebOrigin(webOrigin);
+ }
+ } else {
+ // add origins from redirect uris
+ if (resourceRep.getRedirectUris() != null) {
+ Set<String> origins = new HashSet<String>();
+ for (String redirectUri : resourceRep.getRedirectUris()) {
+ logger.info("add redirectUri to origin: " + redirectUri);
+ if (redirectUri.startsWith("http:")) {
+ URI uri = URI.create(redirectUri);
+ String origin = uri.getScheme() + "://" + uri.getHost();
+ if (uri.getPort() != -1) {
+ origin += ":" + uri.getPort();
+ }
+ logger.debugv("adding default application origin: {0}" , origin);
+ origins.add(origin);
+ }
+ }
+ if (origins.size() > 0) {
+ applicationModel.setWebOrigins(origins);
+ }
+ }
+ }
+
+ if (resourceRep.getDefaultRoles() != null) {
+ applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
+ }
+
+ if (resourceRep.getClaims() != null) {
+ setClaims(applicationModel, resourceRep.getClaims());
+ } else {
+ applicationModel.setAllowedClaimsMask(ClaimMask.USERNAME);
+ }
+
+ return applicationModel;
+ }
+
+ public static void updateApplication(ApplicationRepresentation rep, ApplicationModel resource) {
+ if (rep.getName() != null) resource.setName(rep.getName());
+ if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
+ if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
+ if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
+ if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl());
+ if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl());
+ if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
+ resource.updateApplication();
+
+ if (rep.getNotBefore() != null) {
+ resource.setNotBefore(rep.getNotBefore());
+ }
+ if (rep.getDefaultRoles() != null) {
+ resource.updateDefaultRoles(rep.getDefaultRoles());
+ }
+
+ List<String> redirectUris = rep.getRedirectUris();
+ if (redirectUris != null) {
+ resource.setRedirectUris(new HashSet<String>(redirectUris));
+ }
+
+ List<String> webOrigins = rep.getWebOrigins();
+ if (webOrigins != null) {
+ resource.setWebOrigins(new HashSet<String>(webOrigins));
+ }
+
+ if (rep.getClaims() != null) {
+ setClaims(resource, rep.getClaims());
+ }
+ }
+
+ public static void setClaims(ClientModel model, ClaimRepresentation rep) {
+ long mask = model.getAllowedClaimsMask();
+ if (rep.getAddress()) {
+ mask |= ClaimMask.ADDRESS;
+ } else {
+ mask &= ~ClaimMask.ADDRESS;
+ }
+ if (rep.getEmail()) {
+ mask |= ClaimMask.EMAIL;
+ } else {
+ mask &= ~ClaimMask.EMAIL;
+ }
+ if (rep.getGender()) {
+ mask |= ClaimMask.GENDER;
+ } else {
+ mask &= ~ClaimMask.GENDER;
+ }
+ if (rep.getLocale()) {
+ mask |= ClaimMask.LOCALE;
+ } else {
+ mask &= ~ClaimMask.LOCALE;
+ }
+ if (rep.getName()) {
+ mask |= ClaimMask.NAME;
+ } else {
+ mask &= ~ClaimMask.NAME;
+ }
+ if (rep.getPhone()) {
+ mask |= ClaimMask.PHONE;
+ } else {
+ mask &= ~ClaimMask.PHONE;
+ }
+ if (rep.getPicture()) {
+ mask |= ClaimMask.PICTURE;
+ } else {
+ mask &= ~ClaimMask.PICTURE;
+ }
+ if (rep.getProfile()) {
+ mask |= ClaimMask.PROFILE;
+ } else {
+ mask &= ~ClaimMask.PROFILE;
+ }
+ if (rep.getUsername()) {
+ mask |= ClaimMask.USERNAME;
+ } else {
+ mask &= ~ClaimMask.USERNAME;
+ }
+ if (rep.getWebsite()) {
+ mask |= ClaimMask.WEBSITE;
+ } else {
+ mask &= ~ClaimMask.WEBSITE;
+ }
+ model.setAllowedClaimsMask(mask);
+ }
+
+ // OAuth clients
+
+ private static void createOAuthClients(RealmRepresentation realmRep, RealmModel realm) {
+ for (OAuthClientRepresentation rep : realmRep.getOauthClients()) {
+ createOAuthClient(rep, realm);
+ }
+ }
+
+ public static OAuthClientModel createOAuthClient(String id, String name, RealmModel realm) {
+ OAuthClientModel model = id!=null ? realm.addOAuthClient(id, name) : realm.addOAuthClient(name);
+ KeycloakModelUtils.generateSecret(model);
+ return model;
+ }
+
+ public static OAuthClientModel createOAuthClient(OAuthClientRepresentation rep, RealmModel realm) {
+ OAuthClientModel model = createOAuthClient(rep.getId(), rep.getName(), realm);
+ updateOAuthClient(rep, model);
+ return model;
+ }
+
+ public static void updateOAuthClient(OAuthClientRepresentation rep, OAuthClientModel model) {
+ if (rep.getName() != null) model.setClientId(rep.getName());
+ if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
+ if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient());
+ if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly());
+ if (rep.getClaims() != null) {
+ setClaims(model, rep.getClaims());
+ }
+ if (rep.getNotBefore() != null) {
+ model.setNotBefore(rep.getNotBefore());
+ }
+ if (rep.getSecret() != null) model.setSecret(rep.getSecret());
+ List<String> redirectUris = rep.getRedirectUris();
+ if (redirectUris != null) {
+ model.setRedirectUris(new HashSet<String>(redirectUris));
+ }
+
+ List<String> webOrigins = rep.getWebOrigins();
+ if (webOrigins != null) {
+ model.setWebOrigins(new HashSet<String>(webOrigins));
+ }
+
+ if (rep.getClaims() != null) {
+ setClaims(model, rep.getClaims());
+ }
+
+ if (rep.getNotBefore() != null) {
+ model.setNotBefore(rep.getNotBefore());
+ }
+
+ }
+
+ // Scope mappings
+
+ public static void createApplicationScopeMappings(RealmModel realm, ApplicationModel applicationModel, List<ScopeMappingRepresentation> mappings) {
+ for (ScopeMappingRepresentation mapping : mappings) {
+ ClientModel client = realm.findClient(mapping.getClient());
+ for (String roleString : mapping.getRoles()) {
+ RoleModel role = applicationModel.getRole(roleString.trim());
+ if (role == null) {
+ role = applicationModel.addRole(roleString.trim());
+ }
+ client.addScopeMapping(role);
+ }
+ }
+ }
+
+ // Users
+
+ public static UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
+ UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false);
+ user.setEnabled(userRep.isEnabled());
+ user.setEmail(userRep.getEmail());
+ user.setFirstName(userRep.getFirstName());
+ user.setLastName(userRep.getLastName());
+ if (userRep.getAttributes() != null) {
+ for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
+ user.setAttribute(entry.getKey(), entry.getValue());
+ }
+ }
+ if (userRep.getRequiredActions() != null) {
+ for (String requiredAction : userRep.getRequiredActions()) {
+ user.addRequiredAction(UserModel.RequiredAction.valueOf(requiredAction));
+ }
+ }
+ if (userRep.getCredentials() != null) {
+ for (CredentialRepresentation cred : userRep.getCredentials()) {
+ updateCredential(user, cred);
+ }
+ }
+ if (userRep.getAuthenticationLink() != null) {
+ AuthenticationLinkRepresentation link = userRep.getAuthenticationLink();
+ AuthenticationLinkModel authLink = new AuthenticationLinkModel(link.getAuthProvider(), link.getAuthUserId());
+ user.setAuthenticationLink(authLink);
+ }
+ if (userRep.getSocialLinks() != null) {
+ for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
+ SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
+ newRealm.addSocialLink(user, mappingModel);
+ }
+ }
+ if (userRep.getRealmRoles() != null) {
+ for (String roleString : userRep.getRealmRoles()) {
+ RoleModel role = newRealm.getRole(roleString.trim());
+ if (role == null) {
+ role = newRealm.addRole(roleString.trim());
+ }
+ user.grantRole(role);
+ }
+ }
+ if (userRep.getApplicationRoles() != null) {
+ for (Map.Entry<String, List<String>> entry : userRep.getApplicationRoles().entrySet()) {
+ ApplicationModel app = appMap.get(entry.getKey());
+ if (app == null) {
+ throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
+ }
+ createApplicationRoleMappings(app, user, entry.getValue());
+ }
+ }
+ return user;
+ }
+
+ // Detect if it is "plain-text" or "hashed" representation and update model according to it
+ private static void updateCredential(UserModel user, CredentialRepresentation cred) {
+ if (cred.getValue() != null) {
+ UserCredentialModel plainTextCred = convertCredential(cred);
+ user.updateCredential(plainTextCred);
+ } else {
+ UserCredentialValueModel hashedCred = new UserCredentialValueModel();
+ hashedCred.setType(cred.getType());
+ hashedCred.setDevice(cred.getDevice());
+ hashedCred.setHashIterations(cred.getHashIterations());
+ try {
+ hashedCred.setSalt(Base64.decode(cred.getSalt()));
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ hashedCred.setValue(cred.getHashedSaltedValue());
+ user.updateCredentialDirectly(hashedCred);
+ }
+ }
+
+ public static UserCredentialModel convertCredential(CredentialRepresentation cred) {
+ UserCredentialModel credential = new UserCredentialModel();
+ credential.setType(cred.getType());
+ credential.setValue(cred.getValue());
+ return credential;
+ }
+
+ // Role mappings
+
+ public static void createApplicationRoleMappings(ApplicationModel applicationModel, UserModel user, List<String> roleNames) {
+ if (user == null) {
+ throw new RuntimeException("User not found");
+ }
+
+ for (String roleName : roleNames) {
+ RoleModel role = applicationModel.getRole(roleName.trim());
+ if (role == null) {
+ role = applicationModel.addRole(roleName.trim());
+ }
+ user.grantRole(role);
+
+ }
+ }
+
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheModelProvider.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheModelProvider.java
index d116744..edc79e2 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheModelProvider.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheModelProvider.java
@@ -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;
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
index f40723b..3982020 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
@@ -226,7 +226,7 @@ public class SimpleCache implements KeycloakCache {
@Override
public void invalidateRole(CachedRole role) {
- roleCache.remove(role);
+ roleCache.remove(role.getId());
}
@Override
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 a656b0a..dd32a84 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
@@ -745,7 +745,7 @@ public class RealmAdapter implements RealmModel {
public boolean removeOAuthClient(String id) {
OAuthClientModel oauth = getOAuthClientById(id);
if (oauth == null) return false;
- OAuthClientEntity client = (OAuthClientEntity) ((OAuthClientAdapter) oauth).getEntity();
+ OAuthClientEntity client = em.getReference(OAuthClientEntity.class, oauth.getId());
em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where client = :client").setParameter("client", client).executeUpdate();
em.remove(client);
return true;
@@ -1065,7 +1065,8 @@ public class RealmAdapter implements RealmModel {
@Override
public void setMasterAdminApp(ApplicationModel app) {
- realm.setMasterAdminApp(((ApplicationAdapter) app).getJpaEntity());
+ ApplicationEntity appEntity = app!=null ? em.getReference(ApplicationEntity.class, app.getId()) : null;
+ realm.setMasterAdminApp(appEntity);
em.flush();
}
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 361d269..2a56586 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
@@ -986,7 +986,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
@Override
public void setMasterAdminApp(ApplicationModel app) {
- realm.setAdminAppId(app.getId());
+ String adminAppId = app != null ? app.getId() : null;
+ realm.setAdminAppId(adminAppId);
updateRealm();
}
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 7593ae5..412ef28 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
@@ -5,7 +5,6 @@ import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Constants;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
@@ -16,10 +15,8 @@ import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.UserSessionProvider;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.managers.RealmManager;
import java.util.ArrayList;
@@ -151,8 +148,9 @@ public class AdapterTest extends AbstractModelTest {
public void testOAuthClient() throws Exception {
test1CreateRealm();
- OAuthClientModel oauth = new OAuthClientManager(realmModel).create("oauth-client");
- oauth = realmModel.getOAuthClient("oauth-client");
+ RepresentationToModel.createOAuthClient(null, "oauth-client", realmModel);
+ OAuthClientModel oauth = realmModel.getOAuthClient("oauth-client");
+ Assert.assertNotNull(oauth);
}
@Test
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 f8869bc..58c0444 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
@@ -7,6 +7,8 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.ApplicationManager;
@@ -57,10 +59,10 @@ public class ApplicationModelTest extends AbstractModelTest {
@Test
public void json() {
- ApplicationRepresentation representation = appManager.toRepresentation(application);
+ ApplicationRepresentation representation = ModelToRepresentation.toRepresentation(application);
RealmModel realm = realmManager.createRealm("copy");
- ApplicationModel copy = appManager.createApplication(realm, representation);
+ ApplicationModel copy = RepresentationToModel.createApplication(realm, representation);
assertEquals(application, copy);
}
diff --git a/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
index 05fee92..9d53df1 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
@@ -4,13 +4,10 @@ import org.junit.Assert;
import org.junit.Test;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
public class ModelTest extends AbstractModelTest {
diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
index 6f13dac..cf4d70c 100644
--- a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
+++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java
@@ -37,7 +37,7 @@ public class LDAPKeycloakCredentialHandler extends LDAPPlainTextPasswordCredenti
@Override
public void setup(LDAPIdentityStore store) {
- // TODO: Don't setup it here once PLIDM-508 is fixed
+ // TODO: Don't setup it here once PLINK-508 is fixed
if (store.getConfig().isActiveDirectory() || Boolean.getBoolean("keycloak.ldap.ad.skipUserAccountControlAfterPasswordUpdate")) {
String userAccountControlProp = System.getProperty("keycloak.ldap.ad.userAccountControlAfterPasswordUpdate");
this.userAccountControlAfterPasswordUpdate = userAccountControlProp!=null ? userAccountControlProp : "512";
diff --git a/project-integrations/aerogear-ups/auth-server/pom.xml b/project-integrations/aerogear-ups/auth-server/pom.xml
index 2ea0015..a689697 100755
--- a/project-integrations/aerogear-ups/auth-server/pom.xml
+++ b/project-integrations/aerogear-ups/auth-server/pom.xml
@@ -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>
server/pom.xml 12(+11 -1)
diff --git a/server/pom.xml b/server/pom.xml
index a086cee..7ab2cbb 100755
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -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>
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 56cee64..ebaf3d7 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -12,6 +12,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.CredentialRepresentation;
import java.util.Arrays;
@@ -58,7 +59,7 @@ public class ApplianceBootstrap {
realm.setAccessCodeLifespanUserAction(300);
realm.setSslNotRequired(true);
realm.setRegistrationAllowed(false);
- manager.generateRealmKeys(realm);
+ KeycloakModelUtils.generateRealmKeys(realm);
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
realm.setAuditListeners(Collections.singleton("jboss-logging"));
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index 1f186b1..a9eecf0 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -4,26 +4,15 @@ import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
import org.jboss.logging.Logger;
import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.ClaimMask;
-import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.adapters.config.BaseRealmConfig;
-import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.ScopeMappingRepresentation;
-import org.keycloak.representations.idm.UserRoleMappingRepresentation;
import java.net.URI;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -41,114 +30,8 @@ public class ApplicationManager {
public ApplicationManager() {
}
-
- /**
- * Does not create scope or role mappings!
- *
- * @param realm
- * @param resourceRep
- * @return
- */
- public ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
- logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
- ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
- if (resourceRep.isEnabled() != null) applicationModel.setEnabled(resourceRep.isEnabled());
- applicationModel.setManagementUrl(resourceRep.getAdminUrl());
- if (resourceRep.isSurrogateAuthRequired() != null)
- applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
- applicationModel.setBaseUrl(resourceRep.getBaseUrl());
- if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
- if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
- applicationModel.updateApplication();
-
- if (resourceRep.getNotBefore() != null) {
- applicationModel.setNotBefore(resourceRep.getNotBefore());
- }
-
- applicationModel.setSecret(resourceRep.getSecret());
- if (applicationModel.getSecret() == null) {
- generateSecret(applicationModel);
- }
-
-
- if (resourceRep.getRedirectUris() != null) {
- for (String redirectUri : resourceRep.getRedirectUris()) {
- applicationModel.addRedirectUri(redirectUri);
- }
- }
- if (resourceRep.getWebOrigins() != null) {
- for (String webOrigin : resourceRep.getWebOrigins()) {
- logger.debugv("Application: {0} webOrigin: {1}", resourceRep.getName(), webOrigin);
- applicationModel.addWebOrigin(webOrigin);
- }
- } else {
- // add origins from redirect uris
- if (resourceRep.getRedirectUris() != null) {
- Set<String> origins = new HashSet<String>();
- for (String redirectUri : resourceRep.getRedirectUris()) {
- logger.info("add redirectUri to origin: " + redirectUri);
- if (redirectUri.startsWith("http:")) {
- URI uri = URI.create(redirectUri);
- String origin = uri.getScheme() + "://" + uri.getHost();
- if (uri.getPort() != -1) {
- origin += ":" + uri.getPort();
- }
- logger.debugv("adding default application origin: {0}" , origin);
- origins.add(origin);
- }
- }
- if (origins.size() > 0) {
- applicationModel.setWebOrigins(origins);
- }
- }
- }
-
- if (resourceRep.getDefaultRoles() != null) {
- applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
- }
-
- if (resourceRep.getClaims() != null) {
- ClaimManager.setClaims(applicationModel, resourceRep.getClaims());
- } else {
- applicationModel.setAllowedClaimsMask(ClaimMask.USERNAME);
- }
-
- return applicationModel;
- }
-
- public void createRoleMappings(ApplicationModel applicationModel, UserModel user, List<String> roleNames) {
- for (String roleName : roleNames) {
- if (user == null) {
- throw new RuntimeException("User not found");
- }
-
- RoleModel role = applicationModel.getRole(roleName.trim());
- if (role == null) {
- role = applicationModel.addRole(roleName.trim());
- }
- user.grantRole(role);
-
- }
- }
-
- public void createScopeMappings(RealmModel realm, ApplicationModel applicationModel, List<ScopeMappingRepresentation> mappings) {
- for (ScopeMappingRepresentation mapping : mappings) {
- for (String roleString : mapping.getRoles()) {
- RoleModel role = applicationModel.getRole(roleString.trim());
- if (role == null) {
- role = applicationModel.addRole(roleString.trim());
- }
- ClientModel client = realm.findClient(mapping.getClient());
- client.addScopeMapping(role);
- }
- }
- }
-
public ApplicationModel createApplication(RealmModel realm, String name) {
- ApplicationModel app = realm.addApplication(name);
- generateSecret(app);
-
- return app;
+ return KeycloakModelUtils.createApplication(realm, name);
}
public boolean removeApplication(RealmModel realm, ApplicationModel application) {
@@ -163,74 +46,6 @@ public class ApplicationManager {
}
}
- public UserCredentialModel generateSecret(ApplicationModel app) {
- UserCredentialModel secret = UserCredentialModel.generateSecret();
- app.setSecret(secret.getValue());
- return secret;
- }
-
- public void updateApplication(ApplicationRepresentation rep, ApplicationModel resource) {
- if (rep.getName() != null) resource.setName(rep.getName());
- if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
- if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
- if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
- if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl());
- if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl());
- if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
- resource.updateApplication();
-
- if (rep.getNotBefore() != null) {
- resource.setNotBefore(rep.getNotBefore());
- }
- if (rep.getDefaultRoles() != null) {
- resource.updateDefaultRoles(rep.getDefaultRoles());
- }
-
- List<String> redirectUris = rep.getRedirectUris();
- if (redirectUris != null) {
- resource.setRedirectUris(new HashSet<String>(redirectUris));
- }
-
- List<String> webOrigins = rep.getWebOrigins();
- if (webOrigins != null) {
- resource.setWebOrigins(new HashSet<String>(webOrigins));
- }
-
- if (rep.getClaims() != null) {
- ClaimManager.setClaims(resource, rep.getClaims());
- }
- }
-
- public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
- ApplicationRepresentation rep = new ApplicationRepresentation();
- rep.setId(applicationModel.getId());
- rep.setName(applicationModel.getName());
- rep.setEnabled(applicationModel.isEnabled());
- rep.setAdminUrl(applicationModel.getManagementUrl());
- rep.setPublicClient(applicationModel.isPublicClient());
- rep.setBearerOnly(applicationModel.isBearerOnly());
- rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
- rep.setBaseUrl(applicationModel.getBaseUrl());
- rep.setNotBefore(applicationModel.getNotBefore());
-
- Set<String> redirectUris = applicationModel.getRedirectUris();
- if (redirectUris != null) {
- rep.setRedirectUris(new LinkedList<String>(redirectUris));
- }
-
- Set<String> webOrigins = applicationModel.getWebOrigins();
- if (webOrigins != null) {
- rep.setWebOrigins(new LinkedList<String>(webOrigins));
- }
-
- if (!applicationModel.getDefaultRoles().isEmpty()) {
- rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
- }
-
- return rep;
-
- }
-
@JsonPropertyOrder({"realm", "realm-public-key", "bearer-only", "auth-server-url", "ssl-not-required",
"resource", "public-client", "credentials",
"use-resource-role-mappings"})
diff --git a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
index df13eb4..f69df51 100755
--- a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
@@ -2,22 +2,15 @@ package org.keycloak.services.managers;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
-import org.keycloak.models.ApplicationModel;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.representations.adapters.config.BaseRealmConfig;
import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.OAuthClientRepresentation;
import java.net.URI;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -26,35 +19,14 @@ import java.util.Set;
public class OAuthClientManager {
private RealmManager realmManager;
- protected RealmModel realm;
- public OAuthClientManager(RealmModel realm) {
- this.realm = realm;
+ public OAuthClientManager() {
}
public OAuthClientManager(RealmManager realmManager) {
this.realmManager = realmManager;
}
- public UserCredentialModel generateSecret(OAuthClientModel app) {
- UserCredentialModel secret = UserCredentialModel.generateSecret();
- app.setSecret(secret.getValue());
- return secret;
- }
-
-
- public OAuthClientModel create(String name) {
- OAuthClientModel model = realm.addOAuthClient(name);
- generateSecret(model);
- return model;
- }
-
- public OAuthClientModel create(OAuthClientRepresentation rep) {
- OAuthClientModel model = create(rep.getName());
- update(rep, model);
- return model;
- }
-
public boolean removeClient(RealmModel realm, OAuthClientModel client) {
if (realm.removeOAuthClient(client.getId())) {
UserSessionProvider sessions = realmManager.getSession().sessions();
@@ -67,58 +39,6 @@ public class OAuthClientManager {
}
}
- public void update(OAuthClientRepresentation rep, OAuthClientModel model) {
- if (rep.getName() != null) model.setClientId(rep.getName());
- if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
- if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient());
- if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly());
- if (rep.getClaims() != null) {
- ClaimManager.setClaims(model, rep.getClaims());
- }
- if (rep.getNotBefore() != null) {
- model.setNotBefore(rep.getNotBefore());
- }
- if (rep.getSecret() != null) model.setSecret(rep.getSecret());
- List<String> redirectUris = rep.getRedirectUris();
- if (redirectUris != null) {
- model.setRedirectUris(new HashSet<String>(redirectUris));
- }
-
- List<String> webOrigins = rep.getWebOrigins();
- if (webOrigins != null) {
- model.setWebOrigins(new HashSet<String>(webOrigins));
- }
-
- if (rep.getClaims() != null) {
- ClaimManager.setClaims(model, rep.getClaims());
- }
-
- if (rep.getNotBefore() != null) {
- model.setNotBefore(rep.getNotBefore());
- }
-
- }
-
- public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
- OAuthClientRepresentation rep = new OAuthClientRepresentation();
- rep.setId(model.getId());
- rep.setName(model.getClientId());
- rep.setEnabled(model.isEnabled());
- rep.setPublicClient(model.isPublicClient());
- rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
- Set<String> redirectUris = model.getRedirectUris();
- if (redirectUris != null) {
- rep.setRedirectUris(new LinkedList<String>(redirectUris));
- }
-
- Set<String> webOrigins = model.getWebOrigins();
- if (webOrigins != null) {
- rep.setWebOrigins(new LinkedList<String>(webOrigins));
- }
- rep.setNotBefore(model.getNotBefore());
- return rep;
- }
-
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
"resource", "public-client", "credentials"})
public static class InstallationAdapterConfig extends BaseRealmConfig {
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 29cc8b2..15ef125 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -1,48 +1,26 @@
package org.keycloak.services.managers;
import org.jboss.logging.Logger;
+import org.keycloak.exportimport.util.ExportImportUtils;
+import org.keycloak.exportimport.util.ImportUtils;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.AdminRoles;
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.Constants;
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.RoleModel;
-import org.keycloak.models.SocialLinkModel;
-import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.representations.idm.ApplicationRepresentation;
-import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
-import org.keycloak.representations.idm.AuthenticationProviderRepresentation;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.OAuthClientRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.representations.idm.ScopeMappingRepresentation;
-import org.keycloak.representations.idm.SocialLinkRepresentation;
-import org.keycloak.representations.idm.UserRepresentation;
-
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
/**
* Per request object
@@ -128,10 +106,6 @@ public class RealmManager {
adminConsole.addScopeMapping(adminRole);
}
- public String getMasterRealmAdminApplicationName(RealmModel realm) {
- return realm.getName() + "-realm";
- }
-
public String getRealmAdminApplicationName(RealmModel realm) {
return "realm-management";
}
@@ -162,80 +136,6 @@ public class RealmManager {
return removed;
}
- public void generateRealmKeys(RealmModel realm) {
- KeyPair keyPair = null;
- try {
- keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- realm.setPrivateKey(keyPair.getPrivate());
- realm.setPublicKey(keyPair.getPublic());
- }
-
- public void updateRealm(RealmRepresentation rep, RealmModel realm) {
- if (rep.getRealm() != null) {
- realm.setName(rep.getRealm());
- }
- if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
- if (rep.isSocial() != null) realm.setSocial(rep.isSocial());
- if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected());
- if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
- if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
- if (rep.getWaitIncrementSeconds() != null) realm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
- if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
- if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
- if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor());
- if (rep.isPasswordCredentialGrantAllowed() != null) realm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
- if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
- if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
- if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
- if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
- if (rep.isUpdateProfileOnInitialSocialLogin() != null)
- realm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
- if (rep.isSslNotRequired() != null) realm.setSslNotRequired((rep.isSslNotRequired()));
- if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
- if (rep.getAccessCodeLifespanUserAction() != null)
- realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
- if (rep.getNotBefore() != null) realm.setNotBefore(rep.getNotBefore());
- if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
- if (rep.getSsoSessionIdleTimeout() != null) realm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
- if (rep.getSsoSessionMaxLifespan() != null) realm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
- if (rep.getRequiredCredentials() != null) {
- realm.updateRequiredCredentials(rep.getRequiredCredentials());
- }
- if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
- if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
- if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
- if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme());
-
- if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
-
- if (rep.getDefaultRoles() != null) {
- realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
- }
-
- if (rep.getSmtpServer() != null) {
- realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
- }
-
- if (rep.getSocialProviders() != null) {
- realm.setSocialConfig(new HashMap(rep.getSocialProviders()));
- }
-
- if (rep.getLdapServer() != null) {
- realm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
- }
- if (rep.getAuthenticationProviders() != null) {
- List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
- realm.setAuthenticationProviders(authProviderModels);
- }
-
- if ("GENERATE".equals(rep.getPublicKey())) {
- generateRealmKeys(realm);
- }
- }
-
public void updateRealmAudit(RealmAuditRepresentation rep, RealmModel realm) {
realm.setAuditEnabled(rep.isAuditEnabled());
realm.setAuditExpiration(rep.getAuditExpiration() != null ? rep.getAuditExpiration() : 0);
@@ -244,32 +144,9 @@ public class RealmManager {
}
}
+ // Should be RealmManager moved to model/api instead of referencing methods this way?
private void setupMasterAdminManagement(RealmModel realm) {
- RealmModel adminRealm;
- RoleModel adminRole;
-
- if (realm.getName().equals(Config.getAdminRealm())) {
- adminRealm = realm;
-
- adminRole = realm.addRole(AdminRoles.ADMIN);
-
- RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
- adminRole.addCompositeRole(createRealmRole);
- } else {
- adminRealm = model.getRealmByName(Config.getAdminRealm());
- adminRole = adminRealm.getRole(AdminRoles.ADMIN);
- }
-
- ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
-
- ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getMasterRealmAdminApplicationName(realm));
- realmAdminApp.setBearerOnly(true);
- realm.setMasterAdminApp(realmAdminApp);
-
- for (String r : AdminRoles.ALL_REALM_ROLES) {
- RoleModel role = realmAdminApp.addRole(r);
- adminRole.addCompositeRole(role);
- }
+ ImportUtils.setupMasterAdminManagement(model, realm);
}
private void setupRealmAdminManagement(RealmModel realm) {
@@ -319,273 +196,7 @@ public class RealmManager {
}
public void importRealm(RealmRepresentation rep, RealmModel newRealm) {
- newRealm.setName(rep.getRealm());
- if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
- if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
- if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
- if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
- if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
- if (rep.getWaitIncrementSeconds() != null) newRealm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
- if (rep.getQuickLoginCheckMilliSeconds() != null) newRealm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
- if (rep.getMaxDeltaTimeSeconds() != null) newRealm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
- if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor());
-
- if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore());
-
- if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
- else newRealm.setAccessTokenLifespan(300);
-
- if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
- else newRealm.setSsoSessionIdleTimeout(600);
- if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
- else newRealm.setSsoSessionMaxLifespan(36000);
-
- if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
- else newRealm.setAccessCodeLifespan(60);
-
- if (rep.getAccessCodeLifespanUserAction() != null)
- newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
- else newRealm.setAccessCodeLifespanUserAction(300);
-
- if (rep.isSslNotRequired() != null) newRealm.setSslNotRequired(rep.isSslNotRequired());
- if (rep.isPasswordCredentialGrantAllowed() != null) newRealm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
- if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
- if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
- if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
- if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
- if (rep.isUpdateProfileOnInitialSocialLogin() != null)
- newRealm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
- if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
- generateRealmKeys(newRealm);
- } else {
- newRealm.setPrivateKeyPem(rep.getPrivateKey());
- newRealm.setPublicKeyPem(rep.getPublicKey());
- }
- if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
- if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
- if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
- if (rep.getEmailTheme() != null) newRealm.setEmailTheme(rep.getEmailTheme());
-
- if (rep.getRequiredCredentials() != null) {
- for (String requiredCred : rep.getRequiredCredentials()) {
- addRequiredCredential(newRealm, requiredCred);
- }
- } else {
- addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
- }
-
- if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
-
- if (rep.getApplications() != null) {
- Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
- }
-
- if (rep.getRoles() != null) {
- if (rep.getRoles().getRealm() != null) { // realm roles
- for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
- createRole(newRealm, roleRep);
- }
- }
- if (rep.getRoles().getApplication() != null) {
- for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
- ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
- if (app == null) {
- throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
- }
- for (RoleRepresentation roleRep : entry.getValue()) {
- RoleModel role = app.addRole(roleRep.getName());
- role.setDescription(roleRep.getDescription());
- }
- }
- }
- // now that all roles are created, re-iterate and set up composites
- if (rep.getRoles().getRealm() != null) { // realm roles
- for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
- RoleModel role = newRealm.getRole(roleRep.getName());
- addComposites(role, roleRep, newRealm);
- }
- }
- if (rep.getRoles().getApplication() != null) {
- for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
- ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
- if (app == null) {
- throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
- }
- for (RoleRepresentation roleRep : entry.getValue()) {
- RoleModel role = app.getRole(roleRep.getName());
- addComposites(role, roleRep, newRealm);
- }
- }
- }
- }
-
-
- if (rep.getDefaultRoles() != null) {
- for (String roleString : rep.getDefaultRoles()) {
- newRealm.addDefaultRole(roleString.trim());
- }
- }
-
- if (rep.getOauthClients() != null) {
- createOAuthClients(rep, newRealm);
- }
-
-
- // Now that all possible roles and applications are created, create scope mappings
-
- Map<String, ApplicationModel> appMap = newRealm.getApplicationNameMap();
-
- if (rep.getApplicationScopeMappings() != null) {
- ApplicationManager manager = new ApplicationManager(this);
- for (Map.Entry<String, List<ScopeMappingRepresentation>> entry : rep.getApplicationScopeMappings().entrySet()) {
- ApplicationModel app = appMap.get(entry.getKey());
- if (app == null) {
- throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
- }
- manager.createScopeMappings(newRealm, app, entry.getValue());
- }
- }
-
- if (rep.getScopeMappings() != null) {
- for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
- for (String roleString : scope.getRoles()) {
- RoleModel role = newRealm.getRole(roleString.trim());
- if (role == null) {
- role = newRealm.addRole(roleString.trim());
- }
- ClientModel client = newRealm.findClient(scope.getClient());
- client.addScopeMapping(role);
- }
-
- }
- }
-
- if (rep.getSmtpServer() != null) {
- newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
- }
-
- if (rep.getSocialProviders() != null) {
- newRealm.setSocialConfig(new HashMap(rep.getSocialProviders()));
- }
- if (rep.getLdapServer() != null) {
- newRealm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
- }
-
- if (rep.getAuthenticationProviders() != null) {
- List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
- newRealm.setAuthenticationProviders(authProviderModels);
- } else {
- List<AuthenticationProviderModel> authProviderModels = Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER);
- newRealm.setAuthenticationProviders(authProviderModels);
- }
-
- // create users and their role mappings and social mappings
-
- if (rep.getUsers() != null) {
- for (UserRepresentation userRep : rep.getUsers()) {
- UserModel user = createUser(newRealm, userRep, appMap);
- }
- }
- }
-
- public void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
- if (roleRep.getComposites() == null) return;
- if (roleRep.getComposites().getRealm() != null) {
- for (String roleStr : roleRep.getComposites().getRealm()) {
- RoleModel realmRole = realm.getRole(roleStr);
- if (realmRole == null) throw new RuntimeException("Unable to find composite realm role: " + roleStr);
- role.addCompositeRole(realmRole);
- }
- }
- if (roleRep.getComposites().getApplication() != null) {
- for (Map.Entry<String, List<String>> entry : roleRep.getComposites().getApplication().entrySet()) {
- ApplicationModel app = realm.getApplicationByName(entry.getKey());
- if (app == null) {
- throw new RuntimeException("App doesn't exist in role definitions: " + roleRep.getName());
- }
- for (String roleStr : entry.getValue()) {
- RoleModel appRole = app.getRole(roleStr);
- if (appRole == null) throw new RuntimeException("Unable to find composite app role: " + roleStr);
- role.addCompositeRole(appRole);
- }
-
- }
-
- }
-
- }
-
- public void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
- RoleModel role = newRealm.addRole(roleRep.getName());
- if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
- }
-
- public void createRole(RealmModel newRealm, ApplicationModel app, RoleRepresentation roleRep) {
- RoleModel role = app.addRole(roleRep.getName());
- if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
- }
-
-
- public UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
- UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false);
- user.setEnabled(userRep.isEnabled());
- user.setEmail(userRep.getEmail());
- user.setFirstName(userRep.getFirstName());
- user.setLastName(userRep.getLastName());
- if (userRep.getAttributes() != null) {
- for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
- user.setAttribute(entry.getKey(), entry.getValue());
- }
- }
- if (userRep.getRequiredActions() != null) {
- for (String requiredAction : userRep.getRequiredActions()) {
- user.addRequiredAction(RequiredAction.valueOf(requiredAction));
- }
- }
- if (userRep.getCredentials() != null) {
- for (CredentialRepresentation cred : userRep.getCredentials()) {
- UserCredentialModel credential = fromRepresentation(cred);
- user.updateCredential(credential);
- }
- }
- if (userRep.getAuthenticationLink() != null) {
- AuthenticationLinkRepresentation link = userRep.getAuthenticationLink();
- AuthenticationLinkModel authLink = new AuthenticationLinkModel(link.getAuthProvider(), link.getAuthUserId());
- user.setAuthenticationLink(authLink);
- }
- if (userRep.getSocialLinks() != null) {
- for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
- SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
- newRealm.addSocialLink(user, mappingModel);
- }
- }
- if (userRep.getRealmRoles() != null) {
- for (String roleString : userRep.getRealmRoles()) {
- RoleModel role = newRealm.getRole(roleString.trim());
- if (role == null) {
- role = newRealm.addRole(roleString.trim());
- }
- user.grantRole(role);
- }
- }
- if (userRep.getApplicationRoles() != null) {
- ApplicationManager manager = new ApplicationManager(this);
- for (Map.Entry<String, List<String>> entry : userRep.getApplicationRoles().entrySet()) {
- ApplicationModel app = appMap.get(entry.getKey());
- if (app == null) {
- throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
- }
- manager.createRoleMappings(app, user, entry.getValue());
- }
- }
- return user;
- }
-
- public static UserCredentialModel fromRepresentation(CredentialRepresentation cred) {
- UserCredentialModel credential = new UserCredentialModel();
- credential.setType(cred.getType());
- credential.setValue(cred.getValue());
- return credential;
+ RepresentationToModel.importRealm(rep, newRealm);
}
/**
@@ -606,37 +217,4 @@ public class RealmManager {
return realmModel.searchForUser(searchString.trim());
}
- public void addRequiredCredential(RealmModel newRealm, String requiredCred) {
- newRealm.addRequiredCredential(requiredCred);
- }
-
- protected Map<String, ApplicationModel> createApplications(RealmRepresentation rep, RealmModel realm) {
- Map<String, ApplicationModel> appMap = new HashMap<String, ApplicationModel>();
- ApplicationManager manager = new ApplicationManager(this);
- for (ApplicationRepresentation resourceRep : rep.getApplications()) {
- ApplicationModel app = manager.createApplication(realm, resourceRep);
- appMap.put(app.getName(), app);
- }
- return appMap;
- }
-
- protected void createOAuthClients(RealmRepresentation realmRep, RealmModel realm) {
- OAuthClientManager manager = new OAuthClientManager(realm);
- for (OAuthClientRepresentation rep : realmRep.getOauthClients()) {
- OAuthClientModel app = manager.create(rep);
- }
- }
-
- protected List<AuthenticationProviderModel> convertAuthenticationProviders(List<AuthenticationProviderRepresentation> authenticationProviders) {
- List<AuthenticationProviderModel> result = new ArrayList<AuthenticationProviderModel>();
-
- for (AuthenticationProviderRepresentation representation : authenticationProviders) {
- AuthenticationProviderModel model = new AuthenticationProviderModel(representation.getProviderName(),
- representation.isPasswordUpdateSupported(), representation.getConfig());
- result.add(model);
- }
- return result;
- }
-
-
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 68fe12f..19c7c58 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -53,7 +53,7 @@ import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthRedirect;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index 919fcce..5308112 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -10,13 +10,15 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.adapters.action.UserStats;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.managers.ApplicationManager;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication;
@@ -97,7 +99,7 @@ public class ApplicationResource {
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
try {
- applicationManager.updateApplication(rep, application);
+ RepresentationToModel.updateApplication(rep, application);
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Application " + rep.getName() + " already exists");
@@ -116,8 +118,7 @@ public class ApplicationResource {
public ApplicationRepresentation getApplication() {
auth.requireView();
- ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
- return applicationManager.toRepresentation(application);
+ return ModelToRepresentation.toRepresentation(application);
}
@@ -184,7 +185,7 @@ public class ApplicationResource {
auth.requireManage();
logger.debug("regenerateSecret");
- UserCredentialModel cred = new ApplicationManager().generateSecret(application);
+ UserCredentialModel cred = KeycloakModelUtils.generateSecret(application);
CredentialRepresentation rep = ModelToRepresentation.toRepresentation(cred);
return rep;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
index f83bfc7..c303847 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
@@ -8,6 +8,8 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
@@ -60,12 +62,11 @@ public class ApplicationsResource {
List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>();
List<ApplicationModel> applicationModels = realm.getApplications();
- ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
boolean view = auth.hasView();
for (ApplicationModel applicationModel : applicationModels) {
if (view) {
- rep.add(resourceManager.toRepresentation(applicationModel));
+ rep.add(ModelToRepresentation.toRepresentation(applicationModel));
} else {
ApplicationRepresentation app = new ApplicationRepresentation();
app.setName(applicationModel.getName());
@@ -87,9 +88,8 @@ public class ApplicationsResource {
public Response createApplication(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) {
auth.requireManage();
- ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
try {
- ApplicationModel applicationModel = resourceManager.createApplication(realm, rep);
+ ApplicationModel applicationModel = RepresentationToModel.createApplication(realm, rep);
return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getName()).build()).build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Application " + rep.getName() + " already exists");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java
index 9a9ebaa..0353bad 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java
@@ -1,9 +1,9 @@
package org.keycloak.services.resources.admin;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClaimRepresentation;
-import org.keycloak.services.managers.ClaimManager;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -47,6 +47,6 @@ public class ClaimResource {
@Consumes(MediaType.APPLICATION_JSON)
public void updateClaims(ClaimRepresentation rep) {
auth.requireManage();
- ClaimManager.setClaims(model, rep);
+ RepresentationToModel.setClaims(model, rep);
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
index d8b6d65..e7722d2 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
@@ -8,9 +8,10 @@ import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.OAuthClientRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
@@ -82,9 +83,8 @@ public class OAuthClientResource {
public Response update(final OAuthClientRepresentation rep) {
auth.requireManage();
- OAuthClientManager manager = new OAuthClientManager(realm);
try {
- manager.update(rep, oauthClient);
+ RepresentationToModel.updateOAuthClient(rep, oauthClient);
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Client " + rep.getName() + " already exists");
@@ -102,7 +102,7 @@ public class OAuthClientResource {
public OAuthClientRepresentation getOAuthClient() {
auth.requireView();
- return OAuthClientManager.toRepresentation(oauthClient);
+ return ModelToRepresentation.toRepresentation(oauthClient);
}
/**
@@ -118,7 +118,7 @@ public class OAuthClientResource {
public String getInstallation() throws IOException {
auth.requireView();
- OAuthClientManager manager = new OAuthClientManager(realm);
+ OAuthClientManager manager = new OAuthClientManager();
Object rep = manager.toInstallationRepresentation(realm, oauthClient, getApplication().getBaseUri(uriInfo));
// TODO Temporary solution to pretty-print
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
index f80a8c9..dd081f0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
@@ -8,6 +8,8 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.OAuthClientRepresentation;
import org.keycloak.services.managers.OAuthClientManager;
import org.keycloak.services.resources.flows.Flows;
@@ -65,7 +67,7 @@ public class OAuthClientsResource {
boolean view = auth.hasView();
for (OAuthClientModel oauth : oauthModels) {
if (view) {
- rep.add(OAuthClientManager.toRepresentation(oauth));
+ rep.add(ModelToRepresentation.toRepresentation(oauth));
} else {
OAuthClientRepresentation client = new OAuthClientRepresentation();
client.setName(oauth.getClientId());
@@ -87,9 +89,8 @@ public class OAuthClientsResource {
public Response createOAuthClient(final @Context UriInfo uriInfo, final OAuthClientRepresentation rep) {
auth.requireManage();
- OAuthClientManager resourceManager = new OAuthClientManager(realm);
try {
- OAuthClientModel oauth = resourceManager.create(rep);
+ OAuthClientModel oauth = RepresentationToModel.createOAuthClient(rep, realm);
return Response.created(uriInfo.getAbsolutePathBuilder().path(oauth.getId()).build()).build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Client " + rep.getName() + " already exists");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index b924349..79a0bcd 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -13,11 +13,12 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.LDAPConnectionTestManager;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.TokenManager;
@@ -138,7 +139,7 @@ public class RealmAdminResource {
logger.debug("updating realm: " + realm.getName());
try {
- new RealmManager(session).updateRealm(rep, realm);
+ RepresentationToModel.updateRealm(rep, realm);
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("Realm " + rep.getRealm() + " already exists");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index 35f8176..de7f157 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -14,7 +14,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.ForbiddenException;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.KeycloakApplication;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index d1bb149..cf43306 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -2,13 +2,12 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
-import org.keycloak.models.Constants;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.resources.flows.Flows;
import javax.ws.rs.Consumes;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
index 8ef17d8..18599de 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -5,7 +5,7 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import java.util.Collections;
import java.util.HashSet;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index 92b129c..96a225b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -7,12 +7,10 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
-import org.keycloak.services.managers.RealmManager;
+import org.keycloak.models.utils.ModelToRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index e86781d..32ccf7f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -17,6 +17,7 @@ import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.adapters.action.UserStats;
import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -26,7 +27,7 @@ import org.keycloak.representations.idm.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.managers.AccessCodeEntry;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.TokenManager;
@@ -760,7 +761,7 @@ public class UsersResource {
throw new BadRequestException("No password provided");
}
- UserCredentialModel cred = RealmManager.fromRepresentation(pass);
+ UserCredentialModel cred = RepresentationToModel.convertCredential(pass);
user.updateCredential(cred);
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
}
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 c868e3f..f4094af 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -7,7 +7,7 @@ import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.Config;
import org.keycloak.SkeletonKeyContextResolver;
-import org.keycloak.exportimport.ExportImportProvider;
+import org.keycloak.exportimport.ExportImportManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
@@ -24,7 +24,6 @@ import org.keycloak.services.scheduled.ScheduledTaskRunner;
import org.keycloak.services.util.JsonConfigProvider;
import org.keycloak.timer.TimerProvider;
import org.keycloak.util.JsonSerialization;
-import org.keycloak.util.ProviderLoader;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
@@ -38,7 +37,6 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
@@ -81,7 +79,7 @@ public class KeycloakApplication extends Application {
classes.add(JsResource.class);
classes.add(WelcomeResource.class);
- checkExportImportProvider();
+ new ExportImportManager().checkExportImport(this.sessionFactory);
setupDefaultRealm(context.getContextPath());
@@ -235,16 +233,4 @@ 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(sessionFactory);
- } else {
- log.warn("No ExportImportProvider found!");
- }
- }
-
-
}
testsuite/integration/pom.xml 12(+11 -1)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index acb145b..6507a5e 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -289,7 +289,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-single-file</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-export-import-zip</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
index 5c7bc52..f33a43e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
@@ -33,6 +33,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.RealmManager;
@@ -59,7 +60,7 @@ public class CompositeRoleTest {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmModel realm = manager.createRealm("Test");
- manager.generateRealmKeys(realm);
+ KeycloakModelUtils.generateRealmKeys(realm);
realmPublicKey = realm.getPublicKey();
realm.setSsoSessionIdleTimeout(3000);
realm.setAccessTokenLifespan(10000);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
new file mode 100644
index 0000000..a3e9df9
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
@@ -0,0 +1,330 @@
+package org.keycloak.testsuite.exportimport;
+
+import java.io.File;
+import java.util.Properties;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.keycloak.Config;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.dir.DirExportProvider;
+import org.keycloak.exportimport.dir.DirExportProviderFactory;
+import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
+import org.keycloak.exportimport.zip.ZipExportProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelProvider;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.rule.KeycloakRule;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportTest {
+
+ // We want data to be persisted among server restarts
+ private static ExternalResource hibernateSetupRule = new ExternalResource() {
+
+ private boolean setupDone = false;
+
+ @Override
+ protected void before() throws Throwable {
+ if (System.getProperty("hibernate.connection.url") == null) {
+ String baseExportImportDir = getExportImportTestDirectory();
+
+ File oldDBFile = new File(baseExportImportDir, "keycloakDB.h2.db");
+ if (oldDBFile.exists()) {
+ oldDBFile.delete();
+ }
+
+ String dbDir = baseExportImportDir + "/keycloakDB";
+ System.setProperty("hibernate.connection.url", "jdbc:h2:file:" + dbDir + ";DB_CLOSE_DELAY=-1");
+ System.setProperty("hibernate.hbm2ddl.auto", "update");
+ setupDone = true;
+ }
+ }
+
+ @Override
+ protected void after() {
+ if (setupDone) {
+ Properties sysProps = System.getProperties();
+ sysProps.remove("hibernate.connection.url");
+ sysProps.remove("hibernate.hbm2ddl.auto");
+ }
+ }
+ };
+
+ // 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
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ addUser(appRealm, "user1", "password");
+ addUser(appRealm, "user2", "password");
+ addUser(appRealm, "user3", "password");
+ addUser(adminstrationRealm, "admin2", "admin2");
+ }
+
+ });
+
+ @ClassRule
+ public static TestRule chain = RuleChain
+ .outerRule(hibernateSetupRule)
+ .around(mongoRule)
+ .around(keycloakRule);
+
+ @Test
+ public void testDirFullExportImport() throws Throwable {
+ ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
+ String targetDirPath = getExportImportTestDirectory() + File.separator + "dirExport";
+ DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+ ExportImportConfig.setDir(targetDirPath);
+ ExportImportConfig.setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
+
+ testFullExportImport();
+
+ // There should be 4 files in target directory (2 realm, 2 user)
+ Assert.assertEquals(4, new File(targetDirPath).listFiles().length);
+ }
+
+ @Test
+ public void testDirRealmExportImport() throws Throwable {
+ ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
+ String targetDirPath = getExportImportTestDirectory() + File.separator + "dirRealmExport";
+ DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+ ExportImportConfig.setDir(targetDirPath);
+ ExportImportConfig.setUsersPerFile(3);
+
+ testRealmExportImport();
+
+ // There should be 3 files in target directory (1 realm, 2 user)
+ Assert.assertEquals(3, new File(targetDirPath).listFiles().length);
+ }
+
+ @Test
+ public void testSingleFileFullExportImport() throws Throwable {
+ ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+ String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-full.json";
+ ExportImportConfig.setFile(targetFilePath);
+
+ testFullExportImport();
+ }
+
+ @Test
+ public void testSingleFileRealmExportImport() throws Throwable {
+ ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+ String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
+ ExportImportConfig.setFile(targetFilePath);
+
+ testRealmExportImport();
+ }
+
+ @Test
+ public void testZipFullExportImport() throws Throwable {
+ ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
+ String zipFilePath = getExportImportTestDirectory() + File.separator + "export-full.zip";
+ new File(zipFilePath).delete();
+ ExportImportConfig.setZipFile(zipFilePath);
+ ExportImportConfig.setZipPassword("encPassword");
+ ExportImportConfig.setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
+
+ testFullExportImport();
+ }
+
+ @Test
+ public void testZipRealmExportImport() throws Throwable {
+ ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
+ String zipFilePath = getExportImportTestDirectory() + File.separator + "export-realm.zip";
+ new File(zipFilePath).delete();
+ ExportImportConfig.setZipFile(zipFilePath);
+ ExportImportConfig.setZipPassword("encPassword");
+ ExportImportConfig.setUsersPerFile(3);
+
+ testRealmExportImport();
+ }
+
+ private void testFullExportImport() {
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
+ ExportImportConfig.setRealmName(null);
+
+ // Restart server, which triggers export
+ keycloakRule.restartServer();
+
+ // Delete some realm (and some data in admin realm)
+ KeycloakSession session = keycloakRule.startSession();
+ try {
+ ModelProvider model = session.model();
+ new RealmManager(session).removeRealm(model.getRealmByName("test"));
+ Assert.assertEquals(1, model.getRealms().size());
+
+ RealmModel master = model.getRealmByName(Config.getAdminRealm());
+ master.removeUser("admin2");
+
+ assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
+ assertNotAuthenticated(model, "test", "test-user@localhost", "password");
+ assertNotAuthenticated(model, "test", "user1", "password");
+ assertNotAuthenticated(model, "test", "user2", "password");
+ assertNotAuthenticated(model, "test", "user3", "password");
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+
+ // Configure import
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+
+ // Restart server, which triggers import
+ keycloakRule.restartServer();
+
+ // Ensure data are imported back
+ session = keycloakRule.startSession();
+ try {
+ ModelProvider model = session.model();
+ Assert.assertEquals(2, model.getRealms().size());
+
+ assertAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
+ assertAuthenticated(model, "test", "test-user@localhost", "password");
+ assertAuthenticated(model, "test", "user1", "password");
+ assertAuthenticated(model, "test", "user2", "password");
+ assertAuthenticated(model, "test", "user3", "password");
+
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+ }
+
+ private void testRealmExportImport() {
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
+ ExportImportConfig.setRealmName("test");
+
+ // Restart server, which triggers export
+ keycloakRule.restartServer();
+
+ // Delete some realm (and some data in admin realm)
+ KeycloakSession session = keycloakRule.startSession();
+ try {
+ ModelProvider model = session.model();
+ new RealmManager(session).removeRealm(model.getRealmByName("test"));
+ Assert.assertEquals(1, model.getRealms().size());
+
+ RealmModel master = model.getRealmByName(Config.getAdminRealm());
+ master.removeUser("admin2");
+
+ assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
+ assertNotAuthenticated(model, "test", "test-user@localhost", "password");
+ assertNotAuthenticated(model, "test", "user1", "password");
+ assertNotAuthenticated(model, "test", "user2", "password");
+ assertNotAuthenticated(model, "test", "user3", "password");
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+
+ // Configure import
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+
+ // Restart server, which triggers import
+ keycloakRule.restartServer();
+
+ // Ensure data are imported back, but just for "test" realm
+ session = keycloakRule.startSession();
+ try {
+ ModelProvider model = session.model();
+ Assert.assertEquals(2, model.getRealms().size());
+
+ assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
+ assertAuthenticated(model, "test", "test-user@localhost", "password");
+ assertAuthenticated(model, "test", "user1", "password");
+ assertAuthenticated(model, "test", "user2", "password");
+ assertAuthenticated(model, "test", "user3", "password");
+
+ addUser(model.getRealmByName(Config.getAdminRealm()), "admin2", "admin2");
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+ }
+
+ private void assertAuthenticated(ModelProvider model, String realmName, String username, String password) {
+ RealmModel realm = model.getRealmByName(realmName);
+ if (realm == null) {
+ Assert.fail("realm " + realmName + " not found");
+ }
+
+ UserModel user = realm.getUser(username);
+ if (user == null) {
+ Assert.fail("user " + username + " not found");
+ }
+
+ Assert.assertTrue(realm.validatePassword(user, password));
+ }
+
+ private void assertNotAuthenticated(ModelProvider model, String realmName, String username, String password) {
+ RealmModel realm = model.getRealmByName(realmName);
+ if (realm == null) {
+ return;
+ }
+
+ UserModel user = realm.getUser(username);
+ if (user == null) {
+ return;
+ }
+
+ Assert.assertFalse(realm.validatePassword(user, password));
+ }
+
+ private static void addUser(RealmModel appRealm, String username, String password) {
+ UserModel user = appRealm.addUser(username);
+ user.setEmail(username + "@test.com");
+ user.setEnabled(true);
+
+ UserCredentialModel creds = new UserCredentialModel();
+ creds.setType(CredentialRepresentation.PASSWORD);
+ creds.setValue(password);
+ user.updateCredential(creds);
+ }
+
+ private static String getExportImportTestDirectory() {
+ String dirPath = null;
+ String relativeDirExportImportPath = "testsuite" + File.separator + "integration" + File.separator + "target" + File.separator + "export-import";
+
+ if (System.getProperties().containsKey("maven.home")) {
+ dirPath = System.getProperty("user.dir").replaceFirst("testsuite.integration.*", relativeDirExportImportPath);
+ } else {
+ for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) {
+ if (c.contains(File.separator + "testsuite" + File.separator + "integration")) {
+ dirPath = c.replaceFirst("testsuite.integration.*", relativeDirExportImportPath);
+ }
+ }
+ }
+
+ String absolutePath = new File(dirPath).getAbsolutePath();
+ return absolutePath;
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index 0ba9ed3..f79358f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -12,7 +12,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
-import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testutils.KeycloakServer;
import org.keycloak.util.JsonSerialization;
@@ -146,4 +146,13 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
}
session.close();
}
+
+ public void restartServer() {
+ try {
+ server.stop();
+ server.start();
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
}
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
index 8deadb7..14a106c 100755
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java
@@ -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);
testsuite/tools/pom.xml 12(+11 -1)
diff --git a/testsuite/tools/pom.xml b/testsuite/tools/pom.xml
index c630624..d3b9867 100755
--- a/testsuite/tools/pom.xml
+++ b/testsuite/tools/pom.xml
@@ -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>
diff --git a/testsuite/tools/src/main/java/org/keycloak/test/tools/PerfTools.java b/testsuite/tools/src/main/java/org/keycloak/test/tools/PerfTools.java
index 4b89245..793c8c3 100644
--- a/testsuite/tools/src/main/java/org/keycloak/test/tools/PerfTools.java
+++ b/testsuite/tools/src/main/java/org/keycloak/test/tools/PerfTools.java
@@ -1,7 +1,8 @@
package org.keycloak.test.tools;
import org.keycloak.exportimport.ExportImportConfig;
-import org.keycloak.exportimport.ExportImportProvider;
+import org.keycloak.exportimport.ExportImportManager;
+import org.keycloak.exportimport.ExportProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
@@ -231,14 +232,7 @@ public class PerfTools {
ExportImportConfig.setProvider("dir");
ExportImportConfig.setDir(dir);
- Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
-
- if (providers.hasNext()) {
- ExportImportProvider exportImport = providers.next();
- exportImport.checkExportImport(sessionFactory);
- } else {
- throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
- }
+ new ExportImportManager().checkExportImport(sessionFactory);
}
public static class JobRepresentation {