From 3336d4d7ac64192254143942e87e7f789b786646 Mon Sep 17 00:00:00 2001 From: mposolda Date: Tue, 12 Jan 2016 13:04:22 +0100 Subject: [PATCH] KEYCLOAK-2290 bulk update of algorithm field during migration from 1.7 --- .../META-INF/jpa-changelog-1.8.0.xml | 4 ++ .../jpa/updater/JpaUpdaterProvider.java | 2 +- .../impl/DefaultMongoUpdaterProvider.java | 3 +- .../updater/impl/updates/Update1_8_0.java | 44 +++++++++++++++++++ .../idm/RealmRepresentation.java | 10 ++++- .../models/utils/RepresentationToModel.java | 16 +++++-- 6 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_8_0.java diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml index d0893a3830..5771c12ba9 100755 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml @@ -105,6 +105,10 @@ + + + TYPE in ('password-history', 'password') AND ALGORITHM is NULL + \ No newline at end of file diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java index a5429e4685..255bec40a5 100755 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java @@ -12,7 +12,7 @@ public interface JpaUpdaterProvider extends Provider { public String FIRST_VERSION = "1.0.0.Final"; - public String LAST_VERSION = "1.7.0"; + public String LAST_VERSION = "1.8.0"; public String getCurrentVersionSql(String defaultSchema); diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java index e66e16d28d..7c0cd4866a 100644 --- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java +++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java @@ -29,7 +29,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider { Update1_2_0_CR1.class, Update1_3_0.class, Update1_4_0.class, - Update1_7_0.class + Update1_7_0.class, + Update1_8_0.class }; @Override diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_8_0.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_8_0.java new file mode 100644 index 0000000000..25c583580f --- /dev/null +++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_8_0.java @@ -0,0 +1,44 @@ +package org.keycloak.connections.mongo.updater.impl.updates; + +import com.mongodb.BasicDBList; +import com.mongodb.BasicDBObject; +import com.mongodb.DBCollection; +import com.mongodb.WriteResult; +import org.keycloak.hash.Pbkdf2PasswordHashProvider; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.UserCredentialModel; + +/** + * @author Marek Posolda + */ +public class Update1_8_0 extends Update { + + @Override + public String getId() { + return "1.8.0"; + } + + @Override + public void update(KeycloakSession session) { + BasicDBList orArgs = new BasicDBList(); + orArgs.add(new BasicDBObject("type", UserCredentialModel.PASSWORD)); + orArgs.add(new BasicDBObject("type", UserCredentialModel.PASSWORD_HISTORY)); + + BasicDBObject elemMatch = new BasicDBObject("$or", orArgs); + elemMatch.put("algorithm", new BasicDBObject("$exists", false)); + + BasicDBObject query = new BasicDBObject("credentials", new BasicDBObject("$elemMatch", elemMatch)); + + BasicDBObject update = new BasicDBObject("$set", new BasicDBObject("credentials.$.algorithm", Pbkdf2PasswordHashProvider.ID)); + + DBCollection users = db.getCollection("users"); + + // Not sure how to do in single query + int countModified = 1; + while (countModified > 0) { + WriteResult wr = users.update(query, update, false, true); + countModified = wr.getN(); + log.debugf("%d credentials modified in current iteration during upgrade to 1.8", countModified); + } + } +} 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 ed5fd9351e..2c83d3f509 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -2,6 +2,8 @@ package org.keycloak.representations.idm; import java.util.*; +import org.codehaus.jackson.annotate.JsonIgnore; + /** * @author Bill Burke * @version $Revision: 1 $ @@ -88,8 +90,6 @@ public class RealmRepresentation { private List identityProviders; private List identityProviderMappers; private List protocolMappers; - @Deprecated - private Boolean identityFederationEnabled; protected Boolean internationalizationEnabled; protected Set supportedLocales; protected String defaultLocale; @@ -826,4 +826,10 @@ public class RealmRepresentation { public void setClientTemplates(List clientTemplates) { this.clientTemplates = clientTemplates; } + + @JsonIgnore + public boolean isIdentityFederationEnabled() { + return identityProviders != null && !identityProviders.isEmpty(); + } + } 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 index 87394a1347..612daba51d 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -1,6 +1,7 @@ package org.keycloak.models.utils; import org.keycloak.Config; +import org.keycloak.hash.Pbkdf2PasswordHashProvider; import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.Constants; import org.keycloak.common.util.Base64; @@ -1253,14 +1254,21 @@ public class RepresentationToModel { hashedCred.setValue(cred.getHashedSaltedValue()); if (cred.getCounter() != null) hashedCred.setCounter(cred.getCounter()); if (cred.getDigits() != null) hashedCred.setDigits(cred.getDigits()); - if (cred.getAlgorithm() != null) hashedCred.setAlgorithm(cred.getAlgorithm()); + + if (cred.getAlgorithm() != null) { + hashedCred.setAlgorithm(cred.getAlgorithm()); + } else { + if (UserCredentialModel.PASSWORD.equals(cred.getType()) || UserCredentialModel.PASSWORD_HISTORY.equals(cred.getType())) { + hashedCred.setAlgorithm(Pbkdf2PasswordHashProvider.ID); + } else if (UserCredentialModel.isOtp(cred.getType())) { + hashedCred.setAlgorithm(HmacOTP.HMAC_SHA1); + } + } + if (cred.getPeriod() != null) hashedCred.setPeriod(cred.getPeriod()); if (cred.getDigits() == null && UserCredentialModel.isOtp(cred.getType())) { hashedCred.setDigits(6); } - if (cred.getAlgorithm() == null && UserCredentialModel.isOtp(cred.getType())) { - hashedCred.setAlgorithm(HmacOTP.HMAC_SHA1); - } if (cred.getPeriod() == null && UserCredentialModel.TOTP.equals(cred.getType())) { hashedCred.setPeriod(30); }