diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml index 3776340d34..f54c396681 100755 --- a/dependencies/server-all/pom.xml +++ b/dependencies/server-all/pom.xml @@ -141,22 +141,6 @@ mongo-java-driver - - - org.keycloak - keycloak-export-import-zip - - - de.idyl - winzipaes - - - org.bouncycastle - bcprov-jdk16 - - - - org.liquibase liquibase-core diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml deleted file mode 100644 index ef5c336abb..0000000000 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml deleted file mode 100755 index 2324a65cac..0000000000 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml index 32cd209890..11f8141941 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml @@ -21,7 +21,6 @@ - diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml index 122af6d077..77ce3ad8dc 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml @@ -31,7 +31,6 @@ - diff --git a/distribution/server-overlay/eap6/eap6-server-modules/build.xml b/distribution/server-overlay/eap6/eap6-server-modules/build.xml index 3941fb99ac..22764719ac 100755 --- a/distribution/server-overlay/eap6/eap6-server-modules/build.xml +++ b/distribution/server-overlay/eap6/eap6-server-modules/build.xml @@ -278,15 +278,6 @@ - - - - - - - - - diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/de/idyl/winzipaes/main/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/de/idyl/winzipaes/main/module.xml deleted file mode 100755 index 10f1103cfd..0000000000 --- a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/de/idyl/winzipaes/main/module.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-as7-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-as7-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml index 32cd209890..11f8141941 100755 --- a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-as7-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml +++ b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-as7-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml @@ -21,7 +21,6 @@ - diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-export-import-zip/main/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-export-import-zip/main/module.xml deleted file mode 100755 index e82fe4e8dc..0000000000 --- a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-export-import-zip/main/module.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml index 75e1181eb7..44703f8a5d 100755 --- a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml +++ b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml @@ -31,7 +31,6 @@ - diff --git a/distribution/server-overlay/wf9-server-overlay/assembly.xml b/distribution/server-overlay/wf9-server-overlay/assembly.xml index fc440799f9..080671d5ad 100755 --- a/distribution/server-overlay/wf9-server-overlay/assembly.xml +++ b/distribution/server-overlay/wf9-server-overlay/assembly.xml @@ -14,7 +14,6 @@ modules/system/layers/base com/google/zxing/** - de/idyl/winzipaes/** org/freemarker/** org/keycloak/** org/liquibase/** diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/export-import.xml b/docbook/auth-server-docs/reference/en/en-US/modules/export-import.xml index 492a84758b..fbd6016548 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/export-import.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/export-import.xml @@ -8,12 +8,11 @@ You can export/import your database either to: - Encrypted ZIP file on local filesystem Directory on local filesystem Single JSON file on your filesystem - When importing using the "dir" or "zip" strategies, note that the files need to follow the naming convention specified below. + When importing using the "dir" strategy, note that the files need to follow the naming convention specified below. If you are importing files which were previously exported, the files already follow this convention. {REALM_NAME}-realm.json, such as "acme-roadrunner-affairs-realm.json" for the realm named "acme-roadrunner-affairs" @@ -21,26 +20,10 @@ - Encrypted ZIP is recommended as export contains many sensitive informations like passwords of your users (even if they are hashed), - but also their email addresses, and especially private keys of the realms. Directory and Single JSON file are useful especially - for testing as data in the files are not protected. On the other hand, it's useful if you want to look at all your data in JSON - files directly. - - - If you import to ZIP or Directory, you can specify also the number of users to be stored in each JSON file. So if you have + If you import to Directory, you can specify also the number of users to be stored in each JSON file. So if you have very large amount of users in your database, you likely don't want to import them into single file as the file might be very big. Processing of each file is done in separate transaction as exporting/importing all users at once could also lead to memory issues. - - So to export the content of your Keycloak database into encrypted ZIP, you can execute Keycloak server with the System properties like: - --Dkeycloak.migration.zipPassword= -]]> - Then you can move or copy the encrypted ZIP file into second environment and you can trigger import from it into Keycloak server with the same command but use - -Dkeycloak.migration.action=import instead of export . - To export into unencrypted directory you can use: -Dkeycloak.migration.usersExportStrategy - can be used to specify for ZIP or Directory providers to specify where to import users. + can be used to specify for Directory providers to specify where to import users. Possible values are: DIFFERENT_FILES - Users will be exported into more different files according to maximum number of users per file. This is default value diff --git a/export-import/export-import-zip/pom.xml b/export-import/export-import-zip/pom.xml deleted file mode 100755 index b396fa6011..0000000000 --- a/export-import/export-import-zip/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - keycloak-export-import-parent - org.keycloak - 1.6.0.Final-SNAPSHOT - ../pom.xml - - 4.0.0 - - keycloak-export-import-zip - Keycloak Export Import To Encrypted ZIP - - - - - org.keycloak - keycloak-core - provided - - - org.keycloak - keycloak-model-api - provided - - - org.keycloak - keycloak-export-import-api - provided - - - org.codehaus.jackson - jackson-core-asl - provided - - - org.codehaus.jackson - jackson-mapper-asl - provided - - - org.jboss.logging - jboss-logging - provided - - - de.idyl - winzipaes - provided - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven.compiler.source} - ${maven.compiler.target} - - - - - - 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 deleted file mode 100755 index 1c9212e198..0000000000 --- a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.keycloak.exportimport.zip; - -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.representations.VersionRepresentation; -import org.keycloak.exportimport.util.ExportUtils; -import org.keycloak.exportimport.util.MultipleStepsExportProvider; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.util.JsonSerialization; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * @author Marek Posolda - */ -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); - writeStream(fileName, stream); - } - - @Override - protected void writeUsers(String fileName, KeycloakSession session, RealmModel realm, List users) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - ExportUtils.exportUsersToStream(session, realm, users, JsonSerialization.mapper, stream); - writeStream(fileName, stream); - } - - @Override - protected void writeVersion(String fileName, VersionRepresentation version) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - JsonSerialization.mapper.writeValue(stream, version); - writeStream(fileName, stream); - } - - private void writeStream(String fileName, ByteArrayOutputStream stream) throws IOException { - 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 deleted file mode 100755 index 2fd45d4b93..0000000000 --- a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipExportProviderFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.keycloak.exportimport.zip; - -import org.keycloak.Config; -import org.keycloak.exportimport.ExportImportConfig; -import org.keycloak.exportimport.ExportProvider; -import org.keycloak.exportimport.ExportProviderFactory; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; - -import java.io.File; - -/** - * @author Marek Posolda - */ -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 postInit(KeycloakSessionFactory factory) { - - } - - @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 deleted file mode 100755 index c9e617853a..0000000000 --- a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProvider.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.keycloak.exportimport.zip; - -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.Config; -import org.keycloak.exportimport.ImportProvider; -import org.keycloak.exportimport.Strategy; -import org.keycloak.exportimport.util.ExportImportSessionTask; -import org.keycloak.exportimport.util.ImportUtils; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.util.JsonSerialization; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.DataFormatException; - -/** - * @author Marek Posolda - */ -public class ZipImportProvider implements ImportProvider { - - private static final Logger logger = Logger.getLogger(ZipImportProvider.class); - - private final AesZipFileDecrypter decrypter; - private final String password; - - public ZipImportProvider(File zipFile, String password) { - try { - if (!zipFile.exists()) { - throw new IllegalStateException("File " + zipFile.getAbsolutePath() + " doesn't exists"); - } - - AESDecrypter decrypter = new AESDecrypterBC(); - this.decrypter = new AesZipFileDecrypter(zipFile, decrypter); - this.password = password; - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - logger.infof("Importing from ZIP file %s", zipFile.getAbsolutePath()); - } - - @Override - public void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException { - List realmNames = getRealmsToImport(); - - for (String realmName : realmNames) { - importRealm(factory, realmName, strategy); - } - } - - @Override - public boolean isMasterRealmExported() throws IOException { - List realmNames = getRealmsToImport(); - return realmNames.contains(Config.getAdminRealm()); - } - - private List getRealmsToImport() throws IOException { - List realmNames = new ArrayList(); - 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); - - // Ensure that master realm is imported first - if (Config.getAdminRealm().equals(realmName)) { - realmNames.add(0, realmName); - } else { - realmNames.add(realmName); - } - } - } - return realmNames; - } - - @Override - public void importRealm(KeycloakSessionFactory factory, final String realmName, final Strategy strategy) throws IOException { - try { - // Import realm first - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - this.decrypter.extractEntry(this.decrypter.getEntry(realmName + "-realm.json"), bos, this.password); - ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - final RealmRepresentation realmRep = JsonSerialization.mapper.readValue(bis, RealmRepresentation.class); - - KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() { - - @Override - protected void runExportImportTask(KeycloakSession session) throws IOException { - ImportUtils.importRealm(session, realmRep, strategy); - } - - }); - - - // Import users - for (ExtZipEntry entry : this.decrypter.getEntryList()) { - String name = entry.getName(); - if (name.matches(realmName + "-users-[0-9]+\\.json")) { - bos = new ByteArrayOutputStream(); - this.decrypter.extractEntry(entry, bos, this.password); - final ByteArrayInputStream bis2 = new ByteArrayInputStream(bos.toByteArray()); - - KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() { - - @Override - protected void runExportImportTask(KeycloakSession session) throws IOException { - ImportUtils.importUsersFromStream(session, realmName, JsonSerialization.mapper, bis2); - } - }); - } - } - } catch (DataFormatException dfe) { - throw new RuntimeException(dfe); - } - } - - @Override - public void close() { - try { - this.decrypter.close(); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } -} diff --git a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java b/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java deleted file mode 100755 index 1aed3a5b91..0000000000 --- a/export-import/export-import-zip/src/main/java/org/keycloak/exportimport/zip/ZipImportProviderFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.keycloak.exportimport.zip; - -import org.keycloak.Config; -import org.keycloak.exportimport.ExportImportConfig; -import org.keycloak.exportimport.ImportProvider; -import org.keycloak.exportimport.ImportProviderFactory; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; - -import java.io.File; - -/** - * @author Marek Posolda - */ -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 postInit(KeycloakSessionFactory factory) { - - } - - @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 deleted file mode 100644 index dce02f18db..0000000000 --- a/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ExportProviderFactory +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index b88f372286..0000000000 --- a/export-import/export-import-zip/src/main/resources/META-INF/services/org.keycloak.exportimport.ImportProviderFactory +++ /dev/null @@ -1 +0,0 @@ -org.keycloak.exportimport.zip.ZipImportProviderFactory \ No newline at end of file diff --git a/export-import/pom.xml b/export-import/pom.xml index 35a6f0bb14..2c7026ca55 100755 --- a/export-import/pom.xml +++ b/export-import/pom.xml @@ -18,7 +18,6 @@ export-import-api export-import-dir export-import-single-file - export-import-zip diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html index ccc9fd7224..0768c28211 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html @@ -7,7 +7,7 @@
- +
Specifies display name for the flow.
diff --git a/model/api/src/main/java/org/keycloak/models/utils/Pbkdf2PasswordEncoder.java b/model/api/src/main/java/org/keycloak/models/utils/Pbkdf2PasswordEncoder.java index 6e95490366..066f424655 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/Pbkdf2PasswordEncoder.java +++ b/model/api/src/main/java/org/keycloak/models/utils/Pbkdf2PasswordEncoder.java @@ -90,14 +90,7 @@ public class Pbkdf2PasswordEncoder { public static byte[] getSalt() { byte[] buffer = new byte[16]; - SecureRandom secureRandom; - - try { - secureRandom = SecureRandom.getInstance(RNG_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("RNG algorithm not found"); - } - + SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(buffer); return buffer; diff --git a/pom.xml b/pom.xml index 65968cb269..e5f7d4a4f9 100755 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,6 @@ 1.0.2.Final 3.2.1 2011.1 - 1.0.1 2.3.23 4.0.4 2.35.0 @@ -373,13 +372,6 @@ test
- - - de.idyl - winzipaes - ${winzipaes.version} - - org.apache.directory.server @@ -700,11 +692,6 @@ keycloak-export-import-single-file ${project.version} - - org.keycloak - keycloak-export-import-zip - ${project.version} - org.keycloak keycloak-kerberos-federation diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java index f29ad398d1..c94e8cbc08 100755 --- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java @@ -18,10 +18,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @author Bill Burke @@ -116,6 +113,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow { private class ValidationContextImpl extends FormContextImpl implements ValidationContext { FormAction action; + String error; private ValidationContextImpl(AuthenticationExecutionModel executionModel, FormAction action) { super(executionModel); @@ -131,6 +129,10 @@ public class FormAuthenticationFlow implements AuthenticationFlow { this.formData = formData; } + public void error(String error) { + this.error = error; + } + @Override public void success() { success = true; @@ -145,6 +147,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow { Map executionStatus = new HashMap<>(); List requiredActions = new LinkedList<>(); List successes = new LinkedList<>(); + List errors = new LinkedList<>(); for (AuthenticationExecutionModel formActionExecution : formActionExecutions) { if (!formActionExecution.isEnabled()) { executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED); @@ -183,12 +186,28 @@ public class FormAuthenticationFlow implements AuthenticationFlow { executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS); successes.add(result); } else { - processor.logFailure(); executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED); - return renderForm(result.formData, result.errors); + errors.add(result); } } + if (!errors.isEmpty()) { + processor.logFailure(); + List messages = new LinkedList<>(); + Set fields = new HashSet<>(); + for (ValidationContextImpl v : errors) { + for (FormMessage m : v.errors) { + if (!fields.contains(m.getField())) { + fields.add(m.getField()); + messages.add(m); + } + } + } + ValidationContextImpl first = errors.get(0); + first.getEvent().error(first.error); + return renderForm(first.formData, messages); + } + for (ValidationContextImpl context : successes) { context.action.success(context); } diff --git a/services/src/main/java/org/keycloak/authentication/ValidationContext.java b/services/src/main/java/org/keycloak/authentication/ValidationContext.java index b0c456eb22..ce96b682c1 100755 --- a/services/src/main/java/org/keycloak/authentication/ValidationContext.java +++ b/services/src/main/java/org/keycloak/authentication/ValidationContext.java @@ -21,6 +21,8 @@ public interface ValidationContext extends FormContext { */ void validationError(MultivaluedMap formData, List errors); + void error(String error); + /** * Mark this validation as sucessful * diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java index ade4e00a48..ff2442f3d5 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java @@ -59,7 +59,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory { } if (errors.size() > 0) { - context.getEvent().error(Errors.INVALID_REGISTRATION); + context.error(Errors.INVALID_REGISTRATION); formData.remove(RegistrationPage.FIELD_PASSWORD); formData.remove(RegistrationPage.FIELD_PASSWORD_CONFIRM); context.validationError(formData, errors); diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java index 2fd3c85f01..3baae6fe3a 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java @@ -56,15 +56,17 @@ public class RegistrationProfile implements FormAction, FormActionFactory { } String email = formData.getFirst(Validation.FIELD_EMAIL); + boolean emailValid = true; if (Validation.isBlank(email)) { errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.MISSING_EMAIL)); + emailValid = false; } else if (!Validation.isEmailValid(email)) { - formData.remove(Validation.FIELD_EMAIL); context.getEvent().detail(Details.EMAIL, email); errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL)); + emailValid = false; } - if (context.getSession().users().getUserByEmail(email, context.getRealm()) != null) { + if (emailValid && context.getSession().users().getUserByEmail(email, context.getRealm()) != null) { eventError = Errors.EMAIL_IN_USE; formData.remove(Validation.FIELD_EMAIL); context.getEvent().detail(Details.EMAIL, email); @@ -72,7 +74,7 @@ public class RegistrationProfile implements FormAction, FormActionFactory { } if (errors.size() > 0) { - context.getEvent().error(eventError); + context.error(eventError); context.validationError(formData, errors); return; diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java index 3c1817ce5e..eb10250946 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java @@ -108,7 +108,7 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con } else { errors.add(new FormMessage(null, Messages.RECAPTCHA_FAILED)); formData.remove(G_RECAPTCHA_RESPONSE); - context.getEvent().error(Errors.INVALID_REGISTRATION); + context.error(Errors.INVALID_REGISTRATION); context.validationError(formData, errors); return; diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java index 40d2fb075f..dfc2a89731 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java @@ -56,9 +56,8 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory { String usernameField = RegistrationPage.FIELD_USERNAME; if (context.getRealm().isRegistrationEmailAsUsername()) { - username = email; - context.getEvent().detail(Details.USERNAME, username); - usernameField = RegistrationPage.FIELD_EMAIL; + context.getEvent().detail(Details.USERNAME, email); + if (Validation.isBlank(email)) { errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.MISSING_EMAIL)); } else if (!Validation.isEmailValid(email)) { @@ -66,33 +65,32 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory { formData.remove(Validation.FIELD_EMAIL); } if (errors.size() > 0) { - context.getEvent().error(Errors.INVALID_REGISTRATION); + context.error(Errors.INVALID_REGISTRATION); context.validationError(formData, errors); return; } if (email != null && context.getSession().users().getUserByEmail(email, context.getRealm()) != null) { - context.getEvent().error(Errors.USERNAME_IN_USE); + context.error(Errors.EMAIL_IN_USE); formData.remove(Validation.FIELD_EMAIL); - errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.USERNAME_EXISTS)); + errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.EMAIL_EXISTS)); context.validationError(formData, errors); return; } } else { if (Validation.isBlank(username)) { - context.getEvent().error(Errors.INVALID_REGISTRATION); + context.error(Errors.INVALID_REGISTRATION); errors.add(new FormMessage(RegistrationPage.FIELD_USERNAME, Messages.MISSING_USERNAME)); context.validationError(formData, errors); return; } - } - if (context.getSession().users().getUserByUsername(username, context.getRealm()) != null) { - context.getEvent().error(Errors.USERNAME_IN_USE); - errors.add(new FormMessage(usernameField, Messages.USERNAME_EXISTS)); - formData.remove(Validation.FIELD_USERNAME); - formData.remove(Validation.FIELD_EMAIL); - context.validationError(formData, errors); - return; + if (context.getSession().users().getUserByUsername(username, context.getRealm()) != null) { + context.error(Errors.USERNAME_IN_USE); + errors.add(new FormMessage(usernameField, Messages.USERNAME_EXISTS)); + formData.remove(Validation.FIELD_USERNAME); + context.validationError(formData, errors); + return; + } } context.success(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java index 77e9a4e5fa..bb578ff81a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java @@ -19,6 +19,7 @@ package org.keycloak.testsuite.console.authentication; import org.jboss.arquillian.graphene.page.Page; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.keycloak.testsuite.console.AbstractConsoleTest; import org.keycloak.testsuite.console.page.authentication.PasswordPolicy; @@ -30,7 +31,7 @@ import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy. * @author Petr Mensik * @author mhajas */ -//@Ignore // FIXME still unstable +@Ignore // FIXME still unstable public class PasswordPolicyTest extends AbstractConsoleTest { @Page diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/TokensTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/TokensTest.java index 5608261831..33cfeb56b4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/TokensTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/TokensTest.java @@ -19,6 +19,7 @@ package org.keycloak.testsuite.console.realm; import java.util.concurrent.TimeUnit; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.keycloak.testsuite.console.page.realm.TokenSettings; @@ -30,6 +31,7 @@ import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; * * @author Petr Mensik */ +@Ignore public class TokensTest extends AbstractRealmTest { @Page 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 index 84557d9bbd..1fc4fc22a0 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java @@ -10,7 +10,6 @@ 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.RealmModel; import org.keycloak.models.RealmProvider; @@ -217,30 +216,6 @@ public class ExportImportTest { } } - @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); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java index 9c2852e59d..55c7e618d1 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java @@ -21,10 +21,7 @@ */ package org.keycloak.testsuite.forms; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.keycloak.events.Details; import org.keycloak.models.KeycloakSession; import org.keycloak.models.PasswordPolicy; @@ -42,6 +39,8 @@ import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebRule; import org.openqa.selenium.WebDriver; +import static org.junit.Assert.assertEquals; + /** * @author Stian Thorgersen */ @@ -80,15 +79,15 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerExistingUser@email", "test-user@localhost", "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Username already exists.", registerPage.getError()); + assertEquals("Username already exists.", registerPage.getError()); // assert form keeps form fields on error - Assert.assertEquals("firstName", registerPage.getFirstName()); - Assert.assertEquals("lastName", registerPage.getLastName()); - Assert.assertEquals("", registerPage.getEmail()); - Assert.assertEquals("", registerPage.getUsername()); - Assert.assertEquals("", registerPage.getPassword()); - Assert.assertEquals("", registerPage.getPasswordConfirm()); + assertEquals("firstName", registerPage.getFirstName()); + assertEquals("lastName", registerPage.getLastName()); + assertEquals("registerExistingUser@email", registerPage.getEmail()); + assertEquals("", registerPage.getUsername()); + assertEquals("", registerPage.getPassword()); + assertEquals("", registerPage.getPasswordConfirm()); events.expectRegister("test-user@localhost", "registerExistingUser@email") .removeDetail(Details.EMAIL) @@ -104,15 +103,15 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerUserInvalidPasswordConfirm@email", "registerUserInvalidPasswordConfirm", "password", "invalid"); registerPage.assertCurrent(); - Assert.assertEquals("Password confirmation doesn't match.", registerPage.getError()); + assertEquals("Password confirmation doesn't match.", registerPage.getError()); // assert form keeps form fields on error - Assert.assertEquals("firstName", registerPage.getFirstName()); - Assert.assertEquals("lastName", registerPage.getLastName()); - Assert.assertEquals("registerUserInvalidPasswordConfirm@email", registerPage.getEmail()); - Assert.assertEquals("registerUserInvalidPasswordConfirm", registerPage.getUsername()); - Assert.assertEquals("", registerPage.getPassword()); - Assert.assertEquals("", registerPage.getPasswordConfirm()); + assertEquals("firstName", registerPage.getFirstName()); + assertEquals("lastName", registerPage.getLastName()); + assertEquals("registerUserInvalidPasswordConfirm@email", registerPage.getEmail()); + assertEquals("registerUserInvalidPasswordConfirm", registerPage.getUsername()); + assertEquals("", registerPage.getPassword()); + assertEquals("", registerPage.getPasswordConfirm()); events.expectRegister("registerUserInvalidPasswordConfirm", "registerUserInvalidPasswordConfirm@email") .removeDetail(Details.USERNAME) @@ -129,7 +128,7 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerUserMissingPassword@email", "registerUserMissingPassword", null, null); registerPage.assertCurrent(); - Assert.assertEquals("Please specify password.", registerPage.getError()); + assertEquals("Please specify password.", registerPage.getError()); events.expectRegister("registerUserMissingPassword", "registerUserMissingPassword@email") .removeDetail(Details.USERNAME) @@ -154,7 +153,7 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerPasswordPolicy@email", "registerPasswordPolicy", "pass", "pass"); registerPage.assertCurrent(); - Assert.assertEquals("Invalid password: minimum length 8.", registerPage.getError()); + assertEquals("Invalid password: minimum length 8.", registerPage.getError()); events.expectRegister("registerPasswordPolicy", "registerPasswordPolicy@email") .removeDetail(Details.USERNAME) @@ -162,7 +161,7 @@ public class RegisterTest { .user((String) null).error("invalid_registration").assertEvent(); registerPage.register("firstName", "lastName", "registerPasswordPolicy@email", "registerPasswordPolicy", "password", "password"); - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); String userId = events.expectRegister("registerPasswordPolicy", "registerPasswordPolicy@email").assertEvent().getUserId(); @@ -186,7 +185,7 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerUserMissingUsername@email", null, "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Please specify username.", registerPage.getError()); + assertEquals("Please specify username.", registerPage.getError()); events.expectRegister(null, "registerUserMissingUsername@email") .removeDetail(Details.USERNAME) @@ -195,21 +194,51 @@ public class RegisterTest { } @Test - public void registerUserMissingOrInvalidEmail() { + public void registerUserManyErrors() { + loginPage.open(); + loginPage.clickRegister(); + registerPage.assertCurrent(); + + registerPage.register(null, null, null, null, null, null); + + registerPage.assertCurrent(); + + assertEquals("Please specify username.\n" + + "Please specify first name.\n" + + "Please specify last name.\n" + + "Please specify email.\n" + + "Please specify password.", registerPage.getError()); + + events.expectRegister(null, "registerUserMissingUsername@email") + .removeDetail(Details.USERNAME) + .removeDetail(Details.EMAIL) + .error("invalid_registration").assertEvent(); + } + + @Test + public void registerUserMissingEmail() { loginPage.open(); loginPage.clickRegister(); registerPage.assertCurrent(); registerPage.register("firstName", "lastName", null, "registerUserMissingEmail", "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Please specify email.", registerPage.getError()); + assertEquals("Please specify email.", registerPage.getError()); events.expectRegister("registerUserMissingEmail", null) .removeDetail("email") .error("invalid_registration").assertEvent(); + } + + @Test + public void registerUserInvalidEmail() { + loginPage.open(); + loginPage.clickRegister(); + registerPage.assertCurrent(); registerPage.register("firstName", "lastName", "registerUserInvalidEmailemail", "registerUserInvalidEmail", "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Invalid email address.", registerPage.getError()); + assertEquals("registerUserInvalidEmailemail", registerPage.getEmail()); + assertEquals("Invalid email address.", registerPage.getError()); events.expectRegister("registerUserInvalidEmail", "registerUserInvalidEmailemail") .error("invalid_registration").assertEvent(); } @@ -222,7 +251,7 @@ public class RegisterTest { registerPage.register("firstName", "lastName", "registerUserSuccess@email", "registerUserSuccess", "password", "password"); - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); String userId = events.expectRegister("registerUserSuccess", "registerUserSuccess@email").assertEvent().getUserId(); events.expectLogin().detail("username", "registerusersuccess").user(userId).assertEvent(); @@ -233,10 +262,10 @@ public class RegisterTest { // test that timestamp is current with 10s tollerance Assert.assertTrue((System.currentTimeMillis() - user.getCreatedTimestamp()) < 10000); // test user info is set from form - Assert.assertEquals("registerusersuccess", user.getUsername()); - Assert.assertEquals("registerusersuccess@email", user.getEmail()); - Assert.assertEquals("firstName", user.getFirstName()); - Assert.assertEquals("lastName", user.getLastName()); + assertEquals("registerusersuccess", user.getUsername()); + assertEquals("registerusersuccess@email", user.getEmail()); + assertEquals("firstName", user.getFirstName()); + assertEquals("lastName", user.getLastName()); } protected UserModel getUser(String userId) { @@ -261,9 +290,9 @@ public class RegisterTest { registerPage.registerWithEmailAsUsername("firstName", "lastName", "test-user@localhost", "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Username already exists.", registerPage.getError()); + assertEquals("Email already exists.", registerPage.getError()); - events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("username_in_use").assertEvent(); + events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("email_in_use").assertEvent(); } finally { configureRelamRegistrationEmailAsUsername(false); } @@ -280,12 +309,12 @@ public class RegisterTest { registerPage.registerWithEmailAsUsername("firstName", "lastName", null, "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Please specify email.", registerPage.getError()); + assertEquals("Please specify email.", registerPage.getError()); events.expectRegister(null, null).removeDetail("username").removeDetail("email").error("invalid_registration").assertEvent(); registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserInvalidEmailemail", "password", "password"); registerPage.assertCurrent(); - Assert.assertEquals("Invalid email address.", registerPage.getError()); + assertEquals("Invalid email address.", registerPage.getError()); events.expectRegister("registerUserInvalidEmailemail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent(); } finally { configureRelamRegistrationEmailAsUsername(false); @@ -303,7 +332,7 @@ public class RegisterTest { registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserSuccessE@email", "password", "password"); - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); String userId = events.expectRegister("registerUserSuccessE@email", "registerUserSuccessE@email").assertEvent().getUserId(); events.expectLogin().detail("username", "registerusersuccesse@email").user(userId).assertEvent();