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 16(+16 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProviderFactory.java 9(+9 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java 13(+13 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java 45(+45 -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 170(+170 -0)
export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java 115(+115 -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 73(+73 -0)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProviderFactory.java 36(+36 -0)
export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java 109(+109 -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/ExportImportProviderImpl.java 3(+1 -2)
export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportUtils.java 20(+0 -20)
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 26(+1 -25)
export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java 56(+1 -55)
export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java 84(+84 -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 58(+58 -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 73(+73 -0)
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 109(+109 -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 3(+3 -0)
model/api/pom.xml 5(+5 -0)
picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPKeycloakCredentialHandler.java 2(+1 -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 269(+269 -0)
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..a15a1ce
--- /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(session);
+ } else {
+ logger.infof("Export of realm '%s' requested", realmName);
+ exportProvider.exportRealm(session, 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(session, strategy);
+ } else {
+ logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());
+ importProvider.importRealm(session, 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..4171b89
--- /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(KeycloakSession session) throws IOException;
+
+ void exportRealm(KeycloakSession session, 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..5283977
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProvider.java
@@ -0,0 +1,16 @@
+package org.keycloak.exportimport;
+
+import java.io.IOException;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ImportProvider extends Provider {
+
+ void importModel(KeycloakSession session, Strategy strategy) throws IOException;
+
+ void importRealm(KeycloakSession session, String realmName, Strategy strategy) throws IOException;
+}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProviderFactory.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProviderFactory.java
new file mode 100644
index 0000000..ecb1bd3
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportProviderFactory.java
@@ -0,0 +1,9 @@
+package org.keycloak.exportimport;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ImportProviderFactory extends ProviderFactory<ImportProvider> {
+}
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..12922b4
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportJob.java
@@ -0,0 +1,13 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+
+/**
+ * Task to be executed inside transaction
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ExportImportJob {
+
+ public void run() 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..2c0ab44
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ExportImportUtils.java
@@ -0,0 +1,45 @@
+package org.keycloak.exportimport.util;
+
+import java.io.IOException;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+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. Assumption is that session already exists and it doesn't need to be closed when finished
+ *
+ * @param session
+ * @param job
+ */
+ public static void runJobInTransaction(KeycloakSession session, ExportImportJob job) throws IOException {
+ KeycloakTransaction tx = session.getTransaction();
+ try {
+ tx.begin();
+
+ job.run();
+
+ if (tx.isActive()) {
+ if (tx.getRollbackOnly()) {
+ tx.rollback();
+ } else {
+ tx.commit();
+ }
+ }
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ 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..2747987
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
@@ -0,0 +1,170 @@
+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.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelProvider;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+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.getModel();
+ 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);
+ 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));
+ currentRealm.setMasterAdminApp(masterApp);
+ }
+ } else {
+ // Need to refresh masterApp for current realm
+ RealmModel adminRealm = model.getRealm(adminRealmId);
+ ApplicationModel masterApp = adminRealm.getApplicationByName(ExportImportUtils.getMasterRealmAdminApplicationName(realm));
+ realm.setMasterAdminApp(masterApp);
+ }
+ }
+
+
+ /**
+ * 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.getModel();
+ 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..145ba52
--- /dev/null
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/util/MultipleStepsExportProvider.java
@@ -0,0 +1,115 @@
+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.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(final KeycloakSession session) throws IOException {
+ final RealmsHolder holder = new RealmsHolder();
+
+ // Import users into same file with realm
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() {
+ List<RealmModel> realms = session.getModel().getRealms();
+ holder.realms = realms;
+ }
+
+ });
+
+ for (RealmModel realm : holder.realms) {
+ exportRealm(session, realm.getName());
+ }
+ }
+
+ @Override
+ public void exportRealm(final KeycloakSession session, final String realmName) throws IOException {
+ final int usersPerFile = ExportImportConfig.getUsersPerFile();
+ final UsersHolder usersHolder = new UsersHolder();
+ final boolean exportUsersIntoSameFile = usersPerFile < 0;
+
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ RealmModel realm = session.getModel().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(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ RealmModel realm = session.getModel().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/DirExportProvider.java b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProvider.java
new file mode 100644
index 0000000..48dcf56
--- /dev/null
+++ b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProvider.java
@@ -0,0 +1,73 @@
+package org.keycloak.exportimport.dir;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.keycloak.exportimport.util.ExportUtils;
+import org.keycloak.exportimport.util.MultipleStepsExportProvider;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DirExportProvider extends MultipleStepsExportProvider {
+
+ private final File rootDirectory;
+
+ public DirExportProvider() {
+ // Determine system tmp directory
+ String tempDir = System.getProperty("java.io.tmpdir");
+
+ this.rootDirectory = new File(tempDir + "/keycloak-export");
+ this.rootDirectory.mkdirs();
+
+ logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
+ }
+
+ public DirExportProvider(File rootDirectory) {
+ this.rootDirectory = rootDirectory;
+ this.rootDirectory.mkdirs();
+
+ logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
+ }
+
+ public static boolean recursiveDeleteDir(File dirPath) {
+ if (dirPath.exists()) {
+ File[] files = dirPath.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ recursiveDeleteDir(files[i]);
+ } else {
+ files[i].delete();
+ }
+ }
+ }
+ if (dirPath.exists())
+ return dirPath.delete();
+ else
+ return true;
+ }
+
+ @Override
+ public void writeRealm(String fileName, RealmRepresentation rep) throws IOException {
+ File file = new File(this.rootDirectory, fileName);
+ FileOutputStream stream = new FileOutputStream(file);
+ JsonSerialization.prettyMapper.writeValue(stream, rep);
+ }
+
+ @Override
+ protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
+ File file = new File(this.rootDirectory, fileName);
+ FileOutputStream os = new FileOutputStream(file);
+ ExportUtils.exportUsersToStream(realm, users, JsonSerialization.prettyMapper, os);
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProviderFactory.java b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProviderFactory.java
new file mode 100644
index 0000000..74e7eb4
--- /dev/null
+++ b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirExportProviderFactory.java
@@ -0,0 +1,36 @@
+package org.keycloak.exportimport.dir;
+
+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 DirExportProviderFactory implements ExportProviderFactory {
+
+ public static final String PROVIDER_ID = "dir";
+
+ @Override
+ public ExportProvider create(KeycloakSession session) {
+ String dir = ExportImportConfig.getDir();
+ return dir!=null ? new DirExportProvider(new File(dir)) : new DirExportProvider();
+ }
+
+ @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-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..3f6fc90
--- /dev/null
+++ b/export-import/export-import-dir/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
@@ -0,0 +1,109 @@
+package org.keycloak.exportimport.dir;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.ExportImportConfig;
+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.RealmModel;
+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(KeycloakSession session, 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(session, realmName, strategy);
+ }
+ }
+
+ @Override
+ public void importRealm(final KeycloakSession session, 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(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ ImportUtils.importRealm(session, realmRep, strategy);
+ }
+
+ });
+
+ // Import users
+ for (File userFile : userFiles) {
+ final FileInputStream fis = new FileInputStream(userFile);
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() 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-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
index 03c9dda..c43d3c5 100644
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportProviderImpl.java
@@ -12,14 +12,13 @@ import org.keycloak.util.ProviderLoader;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
-public class ExportImportProviderImpl implements ExportImportProvider {
+public class ExportImportProviderImpl {
private static final Logger logger = Logger.getLogger(ExportImportProviderImpl.class);
public static final String ACTION_EXPORT = "export";
public static final String ACTION_IMPORT = "import";
- @Override
public void checkExportImport(KeycloakSessionFactory sessionFactory) {
String exportImportAction = ExportImportConfig.getAction();
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
index 9705ea6..32be243 100644
--- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java
@@ -10,29 +10,5 @@ import org.keycloak.models.KeycloakSessionFactory;
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@Ignore
-public class JPAToMongoExportImportTest extends ExportImportTestBase {
-
- @Override
- protected String getExportModelProvider() {
- return "jpa";
- }
-
- @Override
- protected String getImportModelProvider() {
- return "mongo";
- }
-
- @Override
- protected void exportModel(KeycloakSessionFactory factory) {
- ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
- ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
- getExportImportProvider().checkExportImport(factory);
- }
-
- @Override
- protected void importModel(KeycloakSessionFactory factory) {
- ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
- ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
- getExportImportProvider().checkExportImport(factory);
- }
+public class JPAToMongoExportImportTest {
}
diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
index 978872f..686722a 100644
--- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
+++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java
@@ -13,59 +13,5 @@ import java.io.File;
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@Ignore
-public class MongoToJPAExportImportTest extends ExportImportTestBase {
-
- private static final String zipFile = "keycloak-export.zip";
-
- @Override
- protected String getExportModelProvider() {
- return "mongo";
- }
-
- @Override
- protected String getImportModelProvider() {
- return "jpa";
- }
-
- @Override
- protected void exportModel(KeycloakSessionFactory factory) {
- ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
- ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
- File zipFile = getZipFile();
- ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
- ExportImportConfig.setZipPassword("password123");
-
- if (zipFile.exists()) {
- zipFile.delete();
- }
-
- new ExportImportProviderImpl().checkExportImport(factory);
- }
-
- @Override
- protected void importModel(KeycloakSessionFactory factory) {
- ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
- ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
- File zipFile = getZipFile();
- ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
- ExportImportConfig.setZipPassword("password-invalid");
-
- // Try invalid password
- try {
- new ExportImportProviderImpl().checkExportImport(factory);
- Assert.fail("Not expected to be here. Exception should be thrown");
- } catch (Exception e) {};
-
- ExportImportConfig.setZipPassword("password123");
- new ExportImportProviderImpl().checkExportImport(factory);
-
- if (zipFile.exists()) {
- zipFile.delete();
- }
- }
-
- private File getZipFile() {
- String tempDir = System.getProperty("java.io.tmpdir");
- return new File(tempDir + File.separator + "keycloak-export.zip");
- }
+public class MongoToJPAExportImportTest {
}
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..4a63ca0
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileExportProvider.java
@@ -0,0 +1,84 @@
+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.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(final KeycloakSession session) throws IOException {
+ logger.infof("Exporting model into file %s", this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ List<RealmModel> realms = session.getModel().getRealms();
+ List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
+ for (RealmModel realm : realms) {
+ reps.add(ExportUtils.exportRealm(realm, true));
+ }
+
+ writeToFile(reps);
+ }
+
+ });
+
+ }
+
+ @Override
+ public void exportRealm(final KeycloakSession session, final String realmName) throws IOException {
+ logger.infof("Exporting realm '%s' into file %s", realmName, this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ RealmModel realm = session.getModel().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..5ac38f4
--- /dev/null
+++ b/export-import/export-import-single-file/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProvider.java
@@ -0,0 +1,58 @@
+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.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(final KeycloakSession session, final Strategy strategy) throws IOException {
+ logger.infof("Full importing from file %s", this.file.getAbsolutePath());
+ ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
+
+ @Override
+ public void run() throws IOException {
+ FileInputStream is = new FileInputStream(file);
+ ImportUtils.importFromStream(session, JsonSerialization.mapper, is, strategy);
+ }
+
+ });
+ }
+
+ @Override
+ public void importRealm(KeycloakSession session, String realmName, Strategy strategy) throws IOException {
+ // TODO: just that single realm in case that file contains many realms?
+ importModel(session, 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/ZipExportProvider.java b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProvider.java
new file mode 100644
index 0000000..ac0e0df
--- /dev/null
+++ b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProvider.java
@@ -0,0 +1,73 @@
+package org.keycloak.exportimport.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import de.idyl.winzipaes.AesZipFileEncrypter;
+import de.idyl.winzipaes.impl.AESEncrypter;
+import de.idyl.winzipaes.impl.AESEncrypterBC;
+import org.jboss.logging.Logger;
+import org.keycloak.exportimport.util.ExportUtils;
+import org.keycloak.exportimport.util.MultipleStepsExportProvider;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ZipExportProvider extends MultipleStepsExportProvider {
+
+ private static final Logger logger = Logger.getLogger(ZipExportProvider.class);
+
+ private final AesZipFileEncrypter encrypter;
+ private final String password;
+
+ public ZipExportProvider(File zipFile, String password) {
+ if (zipFile.exists()) {
+ throw new IllegalStateException("File " + zipFile.getAbsolutePath() + " already exists");
+ }
+ this.password = password;
+
+ try {
+ AESEncrypter encrypter = new AESEncrypterBC();
+ this.encrypter = new AesZipFileEncrypter(zipFile, encrypter);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ logger.infof("Exporting into zip file %s", zipFile.getAbsolutePath());
+ }
+
+ @Override
+ protected void writeRealm(String fileName, RealmRepresentation rep) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ JsonSerialization.mapper.writeValue(stream, rep);
+
+ byte[] byteArray = stream.toByteArray();
+ ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
+ this.encrypter.add(fileName, bis, this.password);
+ }
+
+ @Override
+ protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ ExportUtils.exportUsersToStream(realm, users, JsonSerialization.mapper, stream);
+
+ byte[] byteArray = stream.toByteArray();
+ ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
+ this.encrypter.add(fileName, bis, this.password);
+ }
+
+ @Override
+ public void close() {
+ try {
+ this.encrypter.close();
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+}
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..6ff1f5a
--- /dev/null
+++ b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java
@@ -0,0 +1,109 @@
+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.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(KeycloakSession session, 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(session, realmName, strategy);
+ }
+ }
+ }
+
+ @Override
+ public void importRealm(final KeycloakSession session, 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(session, new ExportImportJob() {
+
+ @Override
+ public void run() 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(session, new ExportImportJob() {
+
+ @Override
+ public void run() 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 3(+3 -0)
diff --git a/export-import/pom.xml b/export-import/pom.xml
index b9a5a4d..15d39f6 100755
--- a/export-import/pom.xml
+++ b/export-import/pom.xml
@@ -17,6 +17,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..68eda42 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,23 @@ 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;
+ }
+
/**
* 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/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/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..3f9daca 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,112 +30,9 @@ 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);
+ KeycloakModelUtils.generateSecret(app);
return app;
}
@@ -163,74 +49,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..b8c1c88 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,11 @@ import java.util.Set;
public class OAuthClientManager {
private RealmManager realmManager;
- protected RealmModel realm;
-
- public OAuthClientManager(RealmModel realm) {
- this.realm = realm;
- }
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 +36,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..dcdc276 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,25 @@
package org.keycloak.services.managers;
import org.jboss.logging.Logger;
+import org.keycloak.exportimport.util.ExportImportUtils;
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 +105,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 +135,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);
@@ -262,7 +161,7 @@ public class RealmManager {
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
- ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getMasterRealmAdminApplicationName(realm));
+ ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, ExportImportUtils.getMasterRealmAdminApplicationName(realm));
realmAdminApp.setBearerOnly(true);
realm.setMasterAdminApp(realmAdminApp);
@@ -319,273 +218,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 +239,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..688b54c
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
@@ -0,0 +1,269 @@
+package org.keycloak.testsuite.exportimport;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
+import org.junit.Test;
+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;
+import org.keycloak.testutils.KeycloakServer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ExportImportTest {
+
+ @ClassRule
+ public 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");
+ }
+
+ });
+
+ @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.getModel();
+ model.removeRealm(model.getRealmByName("test").getId());
+ 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.getModel();
+ 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.getModel();
+ model.removeRealm(model.getRealmByName("test").getId());
+ 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.getModel();
+ 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 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/tools/src/main/java/org/keycloak/test/tools/PerfTools.java b/testsuite/tools/src/main/java/org/keycloak/test/tools/PerfTools.java
index 4b89245..4077f6b 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,7 @@
package org.keycloak.test.tools;
import org.keycloak.exportimport.ExportImportConfig;
-import org.keycloak.exportimport.ExportImportProvider;
+import org.keycloak.exportimport.ExportProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
@@ -231,10 +231,10 @@ public class PerfTools {
ExportImportConfig.setProvider("dir");
ExportImportConfig.setDir(dir);
- Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
+ Iterator<ExportProvider> providers = ProviderLoader.load(ExportProvider.class).iterator();
if (providers.hasNext()) {
- ExportImportProvider exportImport = providers.next();
+ ExportProvider exportImport = providers.next();
exportImport.checkExportImport(sessionFactory);
} else {
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);