keycloak-aplcache

Details

diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index f517782..e0fdcbc 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -18,7 +18,6 @@
 package org.keycloak.models.jpa;
 
 import org.jboss.logging.Logger;
-import org.keycloak.connections.jpa.util.JpaUtils;
 import org.keycloak.common.enums.SslRequired;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
@@ -30,6 +29,7 @@ import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.OTPPolicy;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
@@ -39,12 +39,26 @@ import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderCreationEventImpl;
 import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.jpa.entities.*;
+import org.keycloak.models.jpa.entities.AuthenticationExecutionEntity;
+import org.keycloak.models.jpa.entities.AuthenticationFlowEntity;
+import org.keycloak.models.jpa.entities.AuthenticatorConfigEntity;
+import org.keycloak.models.jpa.entities.ClientEntity;
+import org.keycloak.models.jpa.entities.ClientTemplateEntity;
+import org.keycloak.models.jpa.entities.GroupEntity;
+import org.keycloak.models.jpa.entities.IdentityProviderEntity;
+import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity;
+import org.keycloak.models.jpa.entities.RealmAttributeEntity;
+import org.keycloak.models.jpa.entities.RealmAttributes;
+import org.keycloak.models.jpa.entities.RealmEntity;
+import org.keycloak.models.jpa.entities.RequiredActionProviderEntity;
+import org.keycloak.models.jpa.entities.RequiredCredentialEntity;
+import org.keycloak.models.jpa.entities.RoleEntity;
+import org.keycloak.models.jpa.entities.UserFederationMapperEntity;
+import org.keycloak.models.jpa.entities.UserFederationProviderEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
-
 import java.security.Key;
 import java.security.PrivateKey;
 import java.security.PublicKey;
@@ -1716,8 +1730,11 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
 
     @Override
     public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+        if (KeycloakModelUtils.isFlowUsed(this, model)) {
+            throw new ModelException("Cannot remove authentication flow, it is currently in use");
+        }
         AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, model.getId());
-        if (entity == null) return;
+
         em.remove(entity);
         em.flush();
     }
@@ -2063,6 +2080,9 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         if (id == null) return false;
         ClientTemplateModel client = getClientTemplateById(id);
         if (client == null) return false;
+        if (KeycloakModelUtils.isClientTemplateUsed(this, client)) {
+            throw new ModelException("Cannot remove client template, it is currently in use");
+        }
 
         ClientTemplateEntity clientEntity = null;
         Iterator<ClientTemplateEntity> it = realm.getClientTemplates().iterator();
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index b5d6d7c..2d54715 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -19,9 +19,8 @@ package org.keycloak.models.mongo.keycloak.adapters;
 
 import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
-
-import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -32,6 +31,7 @@ import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.OTPPolicy;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
@@ -53,7 +53,6 @@ import org.keycloak.models.entities.UserFederationMapperEntity;
 import org.keycloak.models.entities.UserFederationProviderEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
-import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
@@ -1558,6 +1557,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+        if (KeycloakModelUtils.isFlowUsed(this, model)) {
+            throw new ModelException("Cannot remove authentication flow, it is currently in use");
+        }
         AuthenticationFlowEntity toDelete = getFlowEntity(model.getId());
         if (toDelete == null) return;
         getMongoEntity().getAuthenticationFlows().remove(toDelete);
@@ -2032,6 +2034,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         ClientTemplateModel client = getClientTemplateById(id);
         if (client == null) return false;
 
+        if (KeycloakModelUtils.isClientTemplateUsed(this, client)) {
+            throw new ModelException("Cannot remove client template, it is currently in use");
+        }
 
         return getMongoStore().removeEntity(MongoClientTemplateEntity.class, id, invocationContext);
     }
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index f75bf11..938a710 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -19,11 +19,15 @@ package org.keycloak.models.utils;
 
 import org.bouncycastle.openssl.PEMWriter;
 import org.keycloak.common.util.Base64Url;
+import org.keycloak.common.util.CertificateUtils;
+import org.keycloak.common.util.PemUtils;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.GroupModel;
+import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakSessionTask;
@@ -40,8 +44,6 @@ import org.keycloak.models.UserFederationProviderFactory;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.CertificateRepresentation;
-import org.keycloak.common.util.CertificateUtils;
-import org.keycloak.common.util.PemUtils;
 
 import javax.crypto.spec.SecretKeySpec;
 import java.io.IOException;
@@ -598,4 +600,37 @@ public final class KeycloakModelUtils {
         }
     }
 
+    /**
+     * Check to see if a flow is currently in use
+     *
+     * @param realm
+     * @param model
+     * @return
+     */
+    public static boolean isFlowUsed(RealmModel realm, AuthenticationFlowModel model) {
+        AuthenticationFlowModel realmFlow = null;
+
+        if ((realmFlow = realm.getBrowserFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
+        if ((realmFlow = realm.getRegistrationFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
+        if ((realmFlow = realm.getClientAuthenticationFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
+        if ((realmFlow = realm.getDirectGrantFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
+        if ((realmFlow = realm.getResetCredentialsFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
+
+        for (IdentityProviderModel idp : realm.getIdentityProviders()) {
+            if (model.getId().equals(idp.getFirstBrokerLoginFlowId())) return true;
+            if (model.getId().equals(idp.getPostBrokerLoginFlowId())) return true;
+        }
+
+        return false;
+
+    }
+
+    public static boolean isClientTemplateUsed(RealmModel realm, ClientTemplateModel template) {
+        for (ClientModel client : realm.getClients()) {
+            if (client.getClientTemplate() != null && client.getClientTemplate().getId().equals(template.getId())) return true;
+        }
+        return false;
+    }
+
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
index 24161a2..595dccd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
@@ -21,6 +21,8 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.utils.ModelToRepresentation;
@@ -101,6 +103,24 @@ public class ClientModelTest extends AbstractModelTest {
         Assert.assertNotNull(client);
     }
 
+    @Test
+    public void testCannotRemoveBoundClientTemplate() {
+        ClientModel client = realm.addClient("templatized");
+        ClientTemplateModel template = realm.addClientTemplate("template");
+        client.setClientTemplate(template);
+        commit();
+        realm = realmManager.getRealmByName("original");
+        try {
+            realm.removeClientTemplate(template.getId());
+            Assert.fail();
+        } catch (ModelException e) {
+
+        }
+        realm.removeClient(client.getId());
+        realm.removeClientTemplate(template.getId());
+        commit();
+    }
+
 
     public static void assertEquals(ClientModel expected, ClientModel actual) {
         Assert.assertEquals(expected.getClientId(), actual.getClientId());