keycloak-uncached
Changes
model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java 21(+16 -5)
Details
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
index d247c8d..acc75d2 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
@@ -186,8 +186,9 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
<term>databaseSchema</term>
<listitem>
<para>
- Specify if schema should be updated or validated. Valid values are "update" and "validate". Value "update is default and means that DB schema will be updated to latest version.
- Value "validate" won't touch database schema, but it will fail to start if schema is not updated to latest version.
+ Specify if schema should be updated or validated. Valid values are <literal>update</literal> and <literal>validate</literal>.
+ Value <literal>update</literal> is default and means that DB schema will be updated to latest version.
+ Value <literal>validate</literal> won't touch database schema, but it will fail to start if schema is not updated to latest version.
</para>
</listitem>
</varlistentry>
@@ -304,7 +305,11 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
},
"user": {
- "provider": "${keycloak.user.provider:jpa}"
+ "provider": "jpa"
+},
+
+"userSessionPersister": {
+ "provider": "jpa"
},
]]></programlisting>
@@ -325,6 +330,10 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
"user": {
"provider": "mongo"
},
+
+"userSessionPersister": {
+ "provider": "mongo"
+},
]]></programlisting>
And at the end of the file add the snippet like this where you can configure details about your Mongo database:
@@ -334,7 +343,8 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
"host": "127.0.0.1",
"port": "27017",
"db": "keycloak",
- "connectionsPerHost": 100
+ "connectionsPerHost": 100,
+ "databaseSchema": "update"
}
}
]]></programlisting>
@@ -344,6 +354,14 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
if you want authenticate against your MongoDB. If user and password are not specified, Keycloak will connect
unauthenticated to your MongoDB.
</para>
+ <para>
+ Option <literal>databaseSchema</literal> specify if mongo database "schema" should be updated or validated. Valid values are <literal>update</literal> and <literal>validate</literal>.
+ Value <literal>update</literal> means that DB schema will be updated to latest version.
+ Value <literal>validate</literal> won't touch database schema, but it will fail to start if schema is not updated to latest version.
+ </para>
+ <note>
+ Mongo doesn't have real database schema, but 'schema' in this case means to which Keycloak version the data in the Mongo database corresponds.
+ </note>
<para>Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. Supported int options are:
<literal>connectionsPerHost</literal>, <literal>threadsAllowedToBlockForConnectionMultiplier</literal>, <literal>maxWaitTime</literal>, <literal>connectTimeout</literal>
<literal>socketTimeout</literal>. Supported boolean options are: <literal>socketKeepAlive</literal>, <literal>autoConnectRetry</literal>.
@@ -360,7 +378,8 @@ bin/add-user-keycloak.[sh|bat] -r master -u <username> -p <password>
"connectionsMongo": {
"default": {
"uri": "mongodb://user:password@127.0.0.1/authentication",
- "db": "keycloak"
+ "db": "keycloak",
+ "databaseSchema": "update"
}
}
]]></programlisting>
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 70359df..f66c989 100755
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -156,13 +156,24 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
}
private void update(KeycloakSession session) {
- MongoUpdaterProvider mongoUpdater = session.getProvider(MongoUpdaterProvider.class);
+ String databaseSchema = config.get("databaseSchema");
- if (mongoUpdater == null) {
- throw new RuntimeException("Can't update database: Mongo updater provider not found");
- }
+ if (databaseSchema == null) {
+ throw new RuntimeException("Property 'databaseSchema' needs to be specified in the configuration of mongo connections");
+ } else {
+ MongoUpdaterProvider mongoUpdater = session.getProvider(MongoUpdaterProvider.class);
+ if (mongoUpdater == null) {
+ throw new RuntimeException("Can't update database: Mongo updater provider not found");
+ }
- mongoUpdater.update(session, db);
+ if (databaseSchema.equals("update")) {
+ mongoUpdater.update(session, db);
+ } else if (databaseSchema.equals("validate")) {
+ mongoUpdater.validate(session, db);
+ } else {
+ throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+ }
+ }
}
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
index 889281c..aa4130d 100755
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
@@ -65,38 +65,19 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
log.debug("Starting database update");
try {
boolean changeLogExists = db.collectionExists(CHANGE_LOG_COLLECTION);
- boolean realmExists = db.collectionExists("realms");
-
DBCollection changeLog = db.getCollection(CHANGE_LOG_COLLECTION);
- List<String> executed = new LinkedList<String>();
- if (!changeLogExists && realmExists) {
- Update1_0_0_Final u = new Update1_0_0_Final();
- executed.add(u.getId());
- createLog(changeLog, u, 1);
- } else if (changeLogExists) {
- DBCursor cursor = changeLog.find().sort(new BasicDBObject("orderExecuted", 1));
- while (cursor.hasNext()) {
- executed.add((String) cursor.next().get("_id"));
- }
- }
-
- List<Update> updatesToRun = new LinkedList<Update>();
- for (Class<? extends Update> updateClass : updates) {
- Update u = updateClass.newInstance();
- if (!executed.contains(u.getId())) {
- updatesToRun.add(u);
- }
- }
+ List<String> executed = getExecuted(db, changeLogExists, changeLog);
+ List<Update> updatesToRun = getUpdatesToRun(executed);
if (!updatesToRun.isEmpty()) {
if (executed.isEmpty()) {
log.info("Initializing database schema");
} else {
if (log.isDebugEnabled()) {
- log.infov("Updating database from {0} to {1}", executed.get(executed.size() - 1), updatesToRun.get(updatesToRun.size() - 1).getId());
+ log.debugv("Updating database from {0} to {1}", executed.get(executed.size() - 1), updatesToRun.get(updatesToRun.size() - 1).getId());
} else {
- log.debugv("Updating database");
+ log.info("Updating database");
}
}
@@ -121,10 +102,66 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
}
}
+
+ @Override
+ public void validate(KeycloakSession session, DB db) {
+ log.debug("Validating database");
+
+ boolean changeLogExists = db.collectionExists(CHANGE_LOG_COLLECTION);
+ DBCollection changeLog = db.getCollection(CHANGE_LOG_COLLECTION);
+
+ List<String> executed = getExecuted(db, changeLogExists, changeLog);
+ List<Update> updatesToRun = getUpdatesToRun(executed);
+
+ if (!updatesToRun.isEmpty()) {
+ String errorMessage = String.format("Failed to validate Mongo database schema. Schema needs updating database from %s to %s. Please change databaseSchema to 'update'",
+ executed.get(executed.size() - 1), updatesToRun.get(updatesToRun.size() - 1).getId());
+ throw new RuntimeException(errorMessage);
+ } else {
+ log.debug("Validation passed. Database is up to date");
+ }
+ }
+
+
+ private List<String> getExecuted(DB db, boolean changeLogExists, DBCollection changeLog) {
+ boolean realmExists = db.collectionExists("realms");
+
+ List<String> executed = new LinkedList<>();
+ if (!changeLogExists && realmExists) {
+ Update1_0_0_Final u = new Update1_0_0_Final();
+ executed.add(u.getId());
+ createLog(changeLog, u, 1);
+ } else if (changeLogExists) {
+ DBCursor cursor = changeLog.find().sort(new BasicDBObject("orderExecuted", 1));
+ while (cursor.hasNext()) {
+ executed.add((String) cursor.next().get("_id"));
+ }
+ }
+ return executed;
+ }
+
+
+ private List<Update> getUpdatesToRun(List<String> executed) {
+ try {
+ List<Update> updatesToRun = new LinkedList<>();
+ for (Class<? extends Update> updateClass : updates) {
+ Update u = updateClass.newInstance();
+ if (!executed.contains(u.getId())) {
+ updatesToRun.add(u);
+ }
+ }
+ return updatesToRun;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
private void createLog(DBCollection changeLog, Update update, int orderExecuted) {
changeLog.insert(new BasicDBObject("_id", update.getId()).append("dateExecuted", new Date()).append("orderExecuted", orderExecuted));
}
+
@Override
public void close() {
}
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
index b5000ec..e7224c9 100644
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
@@ -26,6 +26,8 @@ import org.keycloak.provider.Provider;
*/
public interface MongoUpdaterProvider extends Provider {
- public void update(KeycloakSession session, DB db);
+ void update(KeycloakSession session, DB db);
+
+ void validate(KeycloakSession session, DB db);
}
diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
index 443f3e1..ec76904 100755
--- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
@@ -73,6 +73,7 @@
"host": "${keycloak.connectionsMongo.host:127.0.0.1}",
"port": "${keycloak.connectionsMongo.port:27017}",
"db": "${keycloak.connectionsMongo.db:keycloak}",
+ "databaseSchema": "${keycloak.connectionsMongo.databaseSchema:update}",
"connectionsPerHost": "${keycloak.connectionsMongo.connectionsPerHost:100}"
}
},
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
index c20c075..9208927 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -94,6 +94,7 @@
"host": "${keycloak.connectionsMongo.host:127.0.0.1}",
"port": "${keycloak.connectionsMongo.port:27017}",
"db": "${keycloak.connectionsMongo.db:keycloak}",
+ "databaseSchema": "${keycloak.connectionsMongo.databaseSchema:update}",
"connectionsPerHost": "${keycloak.connectionsMongo.connectionsPerHost:100}"
}
},