keycloak-uncached

Changes

Details

diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakSubsystemParser.java b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakSubsystemParser.java
index 4f36b99..999e430 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakSubsystemParser.java
+++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakSubsystemParser.java
@@ -86,7 +86,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
 
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
             //TODO: externalize the message
-            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
+            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
 
         list.add(addRealm);
@@ -117,7 +117,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
          * TODO need to check realm-ref first.
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
             //TODO: externalize the message
-            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none  and disable-trust-maanger is false.");
+            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
          */
 
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/RealmAddHandler.java b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/RealmAddHandler.java
index 37218be..bbb834e 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/RealmAddHandler.java
+++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/RealmAddHandler.java
@@ -46,7 +46,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
 
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
             //TODO: externalize message
-            throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
+            throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
     }
 
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakSubsystemParser.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakSubsystemParser.java
index 1ed792d..79ddd72 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakSubsystemParser.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakSubsystemParser.java
@@ -87,7 +87,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
 
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
             //TODO: externalize the message
-            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
+            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
 
         list.add(addRealm);
@@ -118,7 +118,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
          * TODO need to check realm-ref first.
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
             //TODO: externalize the message
-            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none  and disable-trust-maanger is false.");
+            throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
          */
 
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/RealmAddHandler.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/RealmAddHandler.java
index e94fffe..edc8d37 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/RealmAddHandler.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/RealmAddHandler.java
@@ -54,7 +54,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
 
         if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
             //TODO: externalize message
-            throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
+            throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
         }
     }
 
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java
index f028c46..23ccbe4 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java
@@ -85,9 +85,6 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
     @Option(shortName = 'm', name = "merge", description = "Merge new values with existing configuration on the server", hasValue = false)
     private boolean mergeMode = true;
 
-    @Option(shortName = 'u', name = "unsafe", description = "Allow updating without registration access token - no optimistic locking", hasValue = false)
-    private boolean allowUnsafe = true;
-
     @Option(shortName = 'o', name = "output", description = "After update output the new client configuration", hasValue = false)
     private boolean outputClient = false;
 
@@ -280,8 +277,6 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
                     saveMergeConfig(cfg -> {
                         setRegistrationToken(cfg.ensureRealmConfigData(server, realm), clientToUpdate, newToken);
                     });
-                } else if (!allowUnsafe) {
-                    throw new RuntimeException("No Registration Access Token found for client: " + clientId + ". Provide one or use --unsafe.");
                 }
 
                 // merge local representation over remote one
@@ -373,7 +368,6 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
         out.println("    -f, --file FILENAME   Use the file or standard input if '-' is specified");
         out.println("    -m, --merge           Merge new values with existing configuration on the server");
         out.println("                          Merge is automatically enabled unless --file is specified");
-        out.println("    -u, --unsafe          Allow updating without registration access token - no optimistic locking");
         out.println("    -o, --output          After update output the new client configuration");
         out.println("    -c, --compressed      Don't pretty print the output");
         out.println();
@@ -389,9 +383,9 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
         out.println("and the following items are shifted.");
         out.println();
         out.println("Merged mode fetches current configuration from the server, applies attribute changes to it, and sends it");
-        out.println("back to the server, overwriting existing configuration there. To ensure there are no unexpected changes");
-        out.println("Registration Access Token is used for authorization when doing changes. Alternatively, one can specify to use");
-        out.println("unsafe mode in which case login session's authorization is used - user requires manage-clients permission.");
+        out.println("back to the server, overwriting existing configuration there. If available, Registration Access Token is used ");
+        out.println("for authorization when doing changes. Otherwise current session's authorization is used in which case user needs");
+        out.println("manage-clients permission for update to work.");
         out.println();
         out.println();
         out.println("Examples:");
diff --git a/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java b/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
index a6dbd77..c452e78 100755
--- a/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
+++ b/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.provider;
 
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -62,6 +63,15 @@ public class ProviderConfigProperty {
         this.defaultValue = defaultValue;
     }
 
+    public ProviderConfigProperty(String name, String label, String helpText, String type, Object defaultValue, String... options) {
+        this.name = name;
+        this.label = label;
+        this.helpText = helpText;
+        this.type = type;
+        this.defaultValue = defaultValue;
+        this.options = Arrays.asList(options);
+    }
+
     public ProviderConfigProperty(String name, String label, String helpText, String type, Object defaultValue, boolean secret) {
         this(name, label, helpText, type, defaultValue);
         this.secret = secret;
diff --git a/services/src/main/java/org/keycloak/keys/Attributes.java b/services/src/main/java/org/keycloak/keys/Attributes.java
index 758ec95..bc66dd3 100644
--- a/services/src/main/java/org/keycloak/keys/Attributes.java
+++ b/services/src/main/java/org/keycloak/keys/Attributes.java
@@ -19,9 +19,9 @@ package org.keycloak.keys;
 
 import org.keycloak.provider.ProviderConfigProperty;
 
-import static org.keycloak.provider.ProviderConfigProperty.BOOLEAN_TYPE;
-import static org.keycloak.provider.ProviderConfigProperty.FILE_TYPE;
-import static org.keycloak.provider.ProviderConfigProperty.STRING_TYPE;
+import java.util.LinkedList;
+
+import static org.keycloak.provider.ProviderConfigProperty.*;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -44,6 +44,6 @@ public interface Attributes {
     ProviderConfigProperty CERTIFICATE_PROPERTY = new ProviderConfigProperty(CERTIFICATE_KEY, "X509 Certificate", "X509 Certificate encoded in PEM format", FILE_TYPE, null);
 
     String KEY_SIZE_KEY = "keySize";
-    ProviderConfigProperty KEY_SIZE_PROPERTY = new ProviderConfigProperty(KEY_SIZE_KEY, "Keysize", "Size for the generated keys (1024, 2048 or 4096)", STRING_TYPE, null);
+    ProviderConfigProperty KEY_SIZE_PROPERTY = new ProviderConfigProperty(KEY_SIZE_KEY, "Keysize", "Size for the generated keys (1024, 2048 or 4096)", LIST_TYPE, "2048", "1024", "2048", "4096");
 
 }
diff --git a/testsuite/integration-arquillian/servers/migration/pom.xml b/testsuite/integration-arquillian/servers/migration/pom.xml
index 7db2623..e625b7f 100644
--- a/testsuite/integration-arquillian/servers/migration/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/pom.xml
@@ -216,4 +216,18 @@
             </plugin>
         </plugins>
     </build>
+    
+    <profiles>
+        <profile>
+            <id>productized-server</id>
+            <activation>
+                <property>
+                    <name>previous.product.unpacked.folder.name</name>
+                </property>
+            </activation>
+            <properties>
+                <keycloak.server.home>${project.build.directory}/unpacked/${previous.product.unpacked.folder.name}</keycloak.server.home>
+            </properties>
+        </profile>
+    </profiles>
 </project>
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java
index a94737d..d712cfe 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java
@@ -17,6 +17,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
 @Inherited
 public @interface UseServletFilter {
 
+    String filterDependency();
     String filterName();
     String filterClass();
     String filterPattern() default "/*";
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
index fe3bce8..00deb0a 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
@@ -42,15 +42,7 @@ import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.hasAppServ
 import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isRelative;
 import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isTomcatAppServer;
 import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
-import static org.keycloak.testsuite.util.IOUtil.appendChildInDocument;
-import static org.keycloak.testsuite.util.IOUtil.documentToString;
-import static org.keycloak.testsuite.util.IOUtil.getElementTextContent;
-import static org.keycloak.testsuite.util.IOUtil.loadJson;
-import static org.keycloak.testsuite.util.IOUtil.loadXML;
-import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
-import static org.keycloak.testsuite.util.IOUtil.modifyDocElementValue;
-import static org.keycloak.testsuite.util.IOUtil.removeElementsFromDoc;
-
+import static org.keycloak.testsuite.util.IOUtil.*;
 
 
 /**
@@ -68,6 +60,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
     public static final String ADAPTER_CONFIG_PATH_TENANT2 = "/WEB-INF/classes/tenant2-keycloak.json";
     public static final String ADAPTER_CONFIG_PATH_JS = "/keycloak.json";
     public static final String SAML_ADAPTER_CONFIG_PATH = "/WEB-INF/keycloak-saml.xml";
+    public static final String JBOSS_DEPLOYMENT_XML_PATH = "/WEB-INF/jboss-deployment-structure.xml";
 
     @Override
     public void process(Archive<?> archive, TestClass testClass) {
@@ -122,9 +115,6 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
 
                 // For running SAML tests it is necessary to have few dependencies on app-server side.
                 // Few of them are not in adapter zip so we need to add them manually here
-                log.info("Adding SAMLFilter dependencies to " + archive.getName());
-                ((WebArchive) archive).addAsLibraries(KeycloakDependenciesResolver.resolveDependencies("org.keycloak:keycloak-saml-servlet-filter-adapter:" + System.getProperty("project.version")));
-
             } else { // OIDC adapter config
                 try {
                     AdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
@@ -148,17 +138,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
                 } catch (IOException ex) {
                     log.log(Level.FATAL, "Cannot serialize adapter config to JSON.", ex);
                 }
-
-                log.info("Adding OIDCFilter dependencies to " + archive.getName());
-                ((WebArchive) archive).addAsLibraries(KeycloakDependenciesResolver.resolveDependencies("org.keycloak:keycloak-servlet-filter-adapter:" + System.getProperty("project.version")));
-
             }
-
-        } else if (archive.getName().equals("customer-portal-subsystem.war")) {
-
-            log.info("Adding OIDCFilter dependencies to " + archive.getName());
-            ((WebArchive) archive).addAsLibraries(KeycloakDependenciesResolver.resolveDependencies("org.keycloak:keycloak-servlet-filter-adapter:" + System.getProperty("project.version")));
-
         }
     }
 
@@ -176,6 +156,23 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
         return libs;
     }
 
+    public void addFilterDependencies(Archive<?> archive, TestClass testClass) {
+        log.info("Adding filter dependencies to " + archive.getName());
+        String dependency = testClass.getAnnotation(UseServletFilter.class).filterDependency();
+        ((WebArchive) archive).addAsLibraries(KeycloakDependenciesResolver.resolveDependencies((dependency + ":" + System.getProperty("project.version"))));
+
+        try {
+            Document jbossXmlDoc = loadXML(archive.get(JBOSS_DEPLOYMENT_XML_PATH).getAsset().openStream());
+            removeNodeByAttributeValue(jbossXmlDoc, "dependencies", "module", "name", "org.keycloak.keycloak-saml-core");
+            removeNodeByAttributeValue(jbossXmlDoc, "dependencies", "module", "name", "org.keycloak.keycloak-adapter-spi");
+            archive.add(new StringAsset((documentToString(jbossXmlDoc))), JBOSS_DEPLOYMENT_XML_PATH);
+        } catch (TransformerException e) {
+            log.error("Can't transform document to String");
+            throw new RuntimeException(e);
+        }
+
+    }
+
     protected void modifyWebXml(Archive<?> archive, TestClass testClass) {
         try {
             Document webXmlDoc = loadXML(
@@ -185,6 +182,9 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
             }
 
             if (testClass.getJavaClass().isAnnotationPresent(UseServletFilter.class)) {
+
+                addFilterDependencies(archive, testClass);
+
                 //We need to add filter declaration to web.xml
                 log.info("Adding filter to " + testClass.getAnnotation(UseServletFilter.class).filterClass() + " with mapping " + testClass.getAnnotation(UseServletFilter.class).filterPattern() + " for " + archive.getName());
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
index 345e77e..9148ce1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
@@ -113,6 +113,29 @@ public class IOUtil {
         node.setTextContent(node.getTextContent().replace(regex, replacement));
     }
 
+    public static void removeNodeByAttributeValue(Document doc, String parentTag, String tagName, String attributeName, String value){
+        NodeList parentNodes = doc.getElementsByTagName(parentTag);
+        if (parentNodes.getLength() != 1) {
+            log.warn("Not able or ambiguous to find element: " + parentTag);
+            return;
+        }
+
+        Element parentElement = (Element) parentNodes.item(0);
+        if (parentElement == null) {
+            log.warn("Not able to find element: " + parentTag);
+            return;
+        }
+
+        NodeList nodes = doc.getElementsByTagName(tagName);
+        for (int i = 0; i < nodes.getLength(); i++){
+            Node node = nodes.item(i).getAttributes().getNamedItem(attributeName);
+            if (node.getTextContent().equals(value)){
+                parentElement.removeChild(nodes.item(i));
+                return;
+            }
+        }
+    }
+
     public static void modifyDocElementValue(Document doc, String tagName, String regex, String replacement) {
         NodeList nodes = doc.getElementsByTagName(tagName);
         if (nodes.getLength() != 1) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
index b53fdcc..fed5ab7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
@@ -8,7 +8,8 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
  * Created by zschwarz on 9/14/16.
  */
 
-@UseServletFilter(filterName = "oidc-filter", filterClass = "org.keycloak.adapters.servlet.KeycloakOIDCFilter")
+@UseServletFilter(filterName = "oidc-filter", filterClass = "org.keycloak.adapters.servlet.KeycloakOIDCFilter",
+        filterDependency = "org.keycloak:keycloak-servlet-filter-adapter")
 public abstract class AbstractDemoFilterServletAdapterTest extends AbstractDemoServletsAdapterTest {
 
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
index 268285a..5adfb94 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
@@ -10,7 +10,8 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
  * @author mhajas
  */
 
-@UseServletFilter(filterName = "saml-filter", filterClass = "org.keycloak.adapters.saml.servlet.SamlFilter")
+@UseServletFilter(filterName = "saml-filter", filterClass = "org.keycloak.adapters.saml.servlet.SamlFilter",
+        filterDependency = "org.keycloak:keycloak-saml-servlet-filter-adapter")
 public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLServletsAdapterTest {
 
     @Before
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/AbstractCliTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/AbstractCliTest.java
index e44a348..ce6cd05 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/AbstractCliTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/AbstractCliTest.java
@@ -430,7 +430,7 @@ public abstract class AbstractCliTest extends AbstractKeycloakTest {
 
         exe = execute("get test-client --no-config --server " + serverUrl + " --realm test " + credentials + " " + extraOptions);
 
-        Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
+        assertExitCodeAndStdErrSize(exe, 0, 1);
 
         ClientRepresentation client2 = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
         Assert.assertEquals("clientId", "test-client", client2.getClientId());
@@ -449,7 +449,7 @@ public abstract class AbstractCliTest extends AbstractKeycloakTest {
         // because the previous invocation didn't use a registration access token
         exe = execute("get test-client --no-config --server " + serverUrl + " --realm test " + extraOptions + " -t " + client.getRegistrationAccessToken());
 
-        Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
+        assertExitCodeAndStdErrSize(exe, 0, 0);
 
         ClientRepresentation client3 = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
         Assert.assertEquals("clientId", "test-client", client3.getClientId());
@@ -466,9 +466,9 @@ public abstract class AbstractCliTest extends AbstractKeycloakTest {
 
 
         exe = execute("update test-client --no-config --server " + serverUrl + " --realm test " +
-                credentials + " " + extraOptions + " -s enabled=false -o --unsafe");
+                credentials + " " + extraOptions + " -s enabled=false -o");
 
-        Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
+        assertExitCodeAndStdErrSize(exe, 0, 1);
 
         ClientRepresentation client4 = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
         Assert.assertEquals("clientId", "test-client", client4.getClientId());
@@ -488,7 +488,7 @@ public abstract class AbstractCliTest extends AbstractKeycloakTest {
         exe = execute("update test-client --no-config --server " + serverUrl + " --realm test " + extraOptions +
                 " -s enabled=true -o -t " + client3.getRegistrationAccessToken());
 
-        Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
+        assertExitCodeAndStdErrSize(exe, 0, 0);
 
         ClientRepresentation client5 = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
         Assert.assertEquals("clientId", "test-client", client5.getClientId());
@@ -527,10 +527,29 @@ public abstract class AbstractCliTest extends AbstractKeycloakTest {
         Assert.assertEquals("config file not modified", lastModified, lastModified2);
     }
 
+    void assertExitCodeAndStdOutSize(KcRegExec exe, int exitCode, int stdOutLineCount) {
+        assertExitCodeAndStreamSizes(exe, exitCode, stdOutLineCount, -1);
+    }
+
+    void assertExitCodeAndStdErrSize(KcRegExec exe, int exitCode, int stdErrLineCount) {
+        assertExitCodeAndStreamSizes(exe, exitCode, -1, stdErrLineCount);
+    }
+
     void assertExitCodeAndStreamSizes(KcRegExec exe, int exitCode, int stdOutLineCount, int stdErrLineCount) {
         Assert.assertEquals("exitCode == " + exitCode, exitCode, exe.exitCode());
-        Assert.assertTrue("stdout output has " + stdOutLineCount + " lines", exe.stdoutLines().size() == stdOutLineCount);
-        Assert.assertTrue("stderr output has " + stdErrLineCount + " lines", exe.stderrLines().size() == stdErrLineCount);
-
+        if (stdOutLineCount != -1) {
+            try {
+                Assert.assertTrue("stdout output has " + stdOutLineCount + " lines", exe.stdoutLines().size() == stdOutLineCount);
+            } catch (Throwable e) {
+                throw new AssertionError("STDOUT: " + exe.stdoutString(), e);
+            }
+        }
+        if (stdErrLineCount != -1) {
+            try {
+                Assert.assertTrue("stderr output has " + stdErrLineCount + " lines", exe.stderrLines().size() == stdErrLineCount);
+            } catch (Throwable e) {
+                throw new AssertionError("STDERR: " + exe.stderrString(), e);
+            }
+        }
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTest.java
index d21c1a3..cebc5fc 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTest.java
@@ -148,23 +148,6 @@ public class KcRegUpdateTest extends AbstractCliTest {
             Assert.assertTrue("stderr is empty", exe.stderrLines().isEmpty());
 
             Assert.assertNull("my_client registration token", handler.loadConfig().ensureRealmConfigData(serverUrl, realm).getClients().get("my_client"));
-
-
-
-            // test update without registration access token to produce 'unsafe' error
-            exe = execute("update my_client --config '" + configFile.getName() + "' -o -s bearerOnly=true");
-
-            Assert.assertEquals("exitCode == 1", 1, exe.exitCode());
-            Assert.assertFalse("stderr is not empty", exe.stderrLines().isEmpty());
-            Assert.assertEquals("error message", "No Registration Access Token found for client: my_client. Provide one or use --unsafe.", exe.stderrLines().get(0));
-
-
-            // test using unsafe to perform update
-            exe = execute("update my_client --config '" + configFile.getName() + "' -o -s bearerOnly=true --unsafe");
-
-            Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
-            Assert.assertTrue("stderr is empty", exe.stderrLines().isEmpty());
-
         }
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
index 6b5322d..9a09a89 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
@@ -27,6 +27,8 @@
             <module name="org.codehaus.jackson.jackson-mapper-asl" />
             <module name="org.bouncycastle" />
             <module name="org.jboss.xnio" />
+            <module name="org.keycloak.keycloak-adapter-spi" />
+            <module name="org.keycloak.keycloak-saml-core" />
 
         </dependencies>
     </deployment>
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 15f6089..bfea8e3 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -421,63 +421,65 @@
                 <skip.add.user.json>true</skip.add.user.json>
             </properties>
             <build>
-                <plugins>
-                    <plugin>
-                        <artifactId>maven-enforcer-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <goals>
-                                    <goal>enforce</goal>
-                                </goals>
-                                <configuration>
-                                    <rules>
-                                        <requireProperty>
-                                            <property>migrated.auth.server.version</property>
-                                        </requireProperty>
-                                        <requireProperty>
-                                            <property>migration.mode</property>
-                                        </requireProperty>
-                                    </rules>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-dependency-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>unpack-migrated-auth-server-jboss</id>
-                                <phase>generate-resources</phase>
-                                <goals>
-                                    <goal>unpack</goal>
-                                </goals>
-                                <configuration>
-                                    <artifactItems>
-                                        <artifactItem>
-                                            <groupId>org.keycloak.testsuite</groupId>
-                                            <artifactId>integration-arquillian-migration-server</artifactId>
-                                            <version>${project.version}</version>
-                                            <type>zip</type>
-                                        </artifactItem>
-                                    </artifactItems>
-                                    <outputDirectory>${containers.home}</outputDirectory>
-                                    <overWriteIfNewer>true</overWriteIfNewer>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
-                                <auth.server.jboss.migration>true</auth.server.jboss.migration>
-                                <keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home>
-                                <migration.import.props.previous>${migration.import.props.previous}</migration.import.props.previous>
-                            </systemPropertyVariables>
-                        </configuration>
-                    </plugin>
-                </plugins>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <artifactId>maven-enforcer-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <goals>
+                                        <goal>enforce</goal>
+                                    </goals>
+                                    <configuration>
+                                        <rules>
+                                            <requireProperty>
+                                                <property>migrated.auth.server.version</property>
+                                            </requireProperty>
+                                            <requireProperty>
+                                                <property>migration.mode</property>
+                                            </requireProperty>
+                                        </rules>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <artifactId>maven-dependency-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>unpack-migrated-auth-server-jboss</id>
+                                    <phase>generate-resources</phase>
+                                    <goals>
+                                        <goal>unpack</goal>
+                                    </goals>
+                                    <configuration>
+                                        <artifactItems>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-migration-server</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>zip</type>
+                                            </artifactItem>
+                                        </artifactItems>
+                                        <outputDirectory>${containers.home}</outputDirectory>
+                                        <overWriteIfNewer>true</overWriteIfNewer>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
+                                    <auth.server.jboss.migration>true</auth.server.jboss.migration>
+                                    <keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home>
+                                    <migration.import.props.previous>${migration.import.props.previous}</migration.import.props.previous>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
             </build>
         </profile>    
         
@@ -499,34 +501,36 @@
                 <skip.add.user.json>true</skip.add.user.json>
             </properties>
             <build>
-                <plugins>
-                    <plugin>
-                        <artifactId>maven-enforcer-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <goals>
-                                    <goal>enforce</goal>
-                                </goals>
-                                <configuration>
-                                    <rules>
-                                        <requireProperty>
-                                            <property>migrated.auth.server.version</property>
-                                        </requireProperty>
-                                    </rules>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
-                                <migration.import.properties>${migration.import.properties}</migration.import.properties>
-                            </systemPropertyVariables>
-                        </configuration>
-                    </plugin>
-                </plugins>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <artifactId>maven-enforcer-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <goals>
+                                        <goal>enforce</goal>
+                                    </goals>
+                                    <configuration>
+                                        <rules>
+                                            <requireProperty>
+                                                <property>migrated.auth.server.version</property>
+                                            </requireProperty>
+                                        </rules>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                        <plugin>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <systemPropertyVariables>
+                                    <migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
+                                    <migration.import.properties>${migration.import.properties}</migration.import.properties>
+                                </systemPropertyVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
             </build>
         </profile>    
       
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
index 2036e52..af25c11 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
@@ -54,7 +54,7 @@
             <td>{{instance.providerId}}</td>
             <td>{{instance.config['priority'][0]}}</td>
             <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
-            <td class="kc-action-cell" data-ng-click="removeInstance(instance)">{{:: 'delete' | translate}}</td>
+            <td class="kc-action-cell" ng-show="instances.length > 1" data-ng-click="removeInstance(instance)">{{:: 'delete' | translate}}</td>
         </tr>
         </tbody>
     </table>