keycloak-uncached

Changes

Details

diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 04e16f8..f6c6f5e 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -113,7 +113,7 @@ public class KeycloakDeploymentBuilder {
             deployment.setClient(new HttpClientBuilder().build(adapterConfig));
         }
         if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
-            throw new RuntimeException("You must specify auth-url");
+            throw new RuntimeException("You must specify auth-server-url");
         }
         deployment.setAuthServerBaseUrl(adapterConfig);
         if (adapterConfig.getTurnOffChangeSessionIdOnLogin() != null) {
diff --git a/adapters/oidc/js/src/main/resources/keycloak-authz.js b/adapters/oidc/js/src/main/resources/keycloak-authz.js
index dd18477..4e42556 100644
--- a/adapters/oidc/js/src/main/resources/keycloak-authz.js
+++ b/adapters/oidc/js/src/main/resources/keycloak-authz.js
@@ -17,7 +17,7 @@
  */
 
 (function( window, undefined ) {
-    
+
     var KeycloakAuthorization = function (keycloak) {
         var _instance = this;
         this.rpt = null;
@@ -112,44 +112,44 @@
                 }
             };
 
-            /**
-             * Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
-             */
-            this.entitlement = function (resourceSeververId) {
-                this.then = function (onGrant, onDeny, onError) {
-                    var request = new XMLHttpRequest();
-
-                    request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
-                    request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
-
-                    request.onreadystatechange = function () {
-                        if (request.readyState == 4) {
-                            var status = request.status;
-
-                            if (status >= 200 && status < 300) {
-                                var rpt = JSON.parse(request.responseText).rpt;
-                                _instance.rpt = rpt;
-                                onGrant(rpt);
-                            } else if (status == 403) {
-                                if (onDeny) {
-                                    onDeny();
-                                } else {
-                                    console.error('Authorization request was denied by the server.');
-                                }
+            return this;
+        };
+
+        /**
+         * Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
+         */
+        this.entitlement = function (resourceSeververId) {
+            this.then = function (onGrant, onDeny, onError) {
+                var request = new XMLHttpRequest();
+
+                request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
+                request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
+
+                request.onreadystatechange = function () {
+                    if (request.readyState == 4) {
+                        var status = request.status;
+
+                        if (status >= 200 && status < 300) {
+                            var rpt = JSON.parse(request.responseText).rpt;
+                            _instance.rpt = rpt;
+                            onGrant(rpt);
+                        } else if (status == 403) {
+                            if (onDeny) {
+                                onDeny();
                             } else {
-                                if (onError) {
-                                    onError();
-                                } else {
-                                    console.error('Could not obtain authorization data from server.');
-                                }
+                                console.error('Authorization request was denied by the server.');
+                            }
+                        } else {
+                            if (onError) {
+                                onError();
+                            } else {
+                                console.error('Could not obtain authorization data from server.');
                             }
                         }
-                    };
-
-                    request.send(null);
+                    }
                 };
 
-                return this;
+                request.send(null);
             };
 
             return this;
diff --git a/adapters/oidc/js/src/main/resources/login-status-iframe.html b/adapters/oidc/js/src/main/resources/login-status-iframe.html
index 8794d54..9bc8fd9 100755
--- a/adapters/oidc/js/src/main/resources/login-status-iframe.html
+++ b/adapters/oidc/js/src/main/resources/login-status-iframe.html
@@ -24,7 +24,7 @@
         if (!init) {
             var req = new XMLHttpRequest();
 
-            var url = "http://localhost:8080/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init";
+            var url = location.href + "/init";
             url += "?client_id=" + encodeURIComponent(clientId);
             url += "&origin=" + encodeURIComponent(origin);
             url += "&session_state=" + encodeURIComponent(sessionState);
diff --git a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java
index 95bdf46..f196cf6 100644
--- a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java
+++ b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootProperties.java
@@ -17,15 +17,27 @@
 
 package org.keycloak.adapters.springboot;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.keycloak.representations.adapters.config.AdapterConfig;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @ConfigurationProperties(prefix = "keycloak", ignoreUnknownFields = false)
 public class KeycloakSpringBootProperties extends AdapterConfig {
 
+    /* this is a dummy property to avoid re-rebinding problem with property keycloak.config.resolver
+       when using spring cloud - see KEYCLOAK-2977 */
+    @JsonIgnore
+    private Map config = new HashMap();
+
+    public Map getConfig() {
+        return config;
+    }
+
     private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
 
     public static class SecurityConstraint {
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractGlobalOptionsCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractGlobalOptionsCmd.java
index a3dc6e1..0183eee 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractGlobalOptionsCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractGlobalOptionsCmd.java
@@ -4,6 +4,8 @@ import org.jboss.aesh.cl.Option;
 import org.jboss.aesh.console.command.Command;
 import org.keycloak.client.registration.cli.aesh.Globals;
 
+import static org.keycloak.client.registration.cli.util.IoUtil.printOut;
+
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
  */
@@ -12,11 +14,28 @@ public abstract class AbstractGlobalOptionsCmd implements Command {
     @Option(shortName = 'x', description = "Print full stack trace when exiting with error", hasValue = false)
     protected boolean dumpTrace;
 
+    @Option(name = "help", description = "Print command specific help", hasValue = false)
+    protected boolean help;
+
     protected void init(AbstractGlobalOptionsCmd parent) {
         dumpTrace = parent.dumpTrace;
+        help = parent.help;
     }
 
     protected void processGlobalOptions() {
         Globals.dumpTrace = dumpTrace;
     }
+
+    protected boolean printHelp() {
+        if (help) {
+            printOut(help());
+            return true;
+        }
+
+        return false;
+    }
+
+    protected String help() {
+        return KcRegCmd.usage();
+    }
 }
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AttrsCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AttrsCmd.java
index fb52357..958ae27 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AttrsCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AttrsCmd.java
@@ -48,6 +48,9 @@ public class AttrsCmd extends AbstractGlobalOptionsCmd {
         try {
             processGlobalOptions();
 
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
 
             EndpointType regType = EndpointType.DEFAULT;
             PrintStream out = commandInvocation.getShell().out();
@@ -120,6 +123,10 @@ public class AttrsCmd extends AbstractGlobalOptionsCmd {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCmd.java
index be9358d..b4be107 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCmd.java
@@ -42,7 +42,11 @@ public class ConfigCmd extends AbstractAuthOptionsCmd implements Command {
 
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
         try {
-            if (args.size() == 0) {
+            if (args == null || args.size() == 0) {
+                if (printHelp()) {
+                    return CommandResult.SUCCESS;
+                }
+
                 throw new RuntimeException("Sub-command required by '" + OsUtil.CMD + " config' - one of: 'credentials', 'truststore', 'initial-token', 'registration-token'");
             }
 
@@ -60,8 +64,12 @@ public class ConfigCmd extends AbstractAuthOptionsCmd implements Command {
                 case "registration-token": {
                     return new ConfigRegistrationTokenCmd(this).execute(commandInvocation);
                 }
-                default:
+                default: {
+                    if (printHelp()) {
+                        return CommandResult.SUCCESS;
+                    }
                     throw new RuntimeException("Unknown sub-command: " + cmd);
+                }
             }
 
         } finally {
@@ -69,6 +77,10 @@ public class ConfigCmd extends AbstractAuthOptionsCmd implements Command {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCredentialsCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCredentialsCmd.java
index 6d60530..4cc050f 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCredentialsCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigCredentialsCmd.java
@@ -69,6 +69,10 @@ public class ConfigCredentialsCmd extends AbstractAuthOptionsCmd implements Comm
         try {
             processGlobalOptions();
 
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             return process(commandInvocation);
         } finally {
             commandInvocation.stop();
@@ -170,6 +174,10 @@ public class ConfigCredentialsCmd extends AbstractAuthOptionsCmd implements Comm
         return CommandResult.SUCCESS;
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigInitialTokenCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigInitialTokenCmd.java
index 5770e33..937787e 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigInitialTokenCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigInitialTokenCmd.java
@@ -43,6 +43,10 @@ public class ConfigInitialTokenCmd extends AbstractAuthOptionsCmd implements Com
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
         try {
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             return process(commandInvocation);
         } finally {
             commandInvocation.stop();
@@ -130,6 +134,10 @@ public class ConfigInitialTokenCmd extends AbstractAuthOptionsCmd implements Com
         return CommandResult.SUCCESS;
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigRegistrationTokenCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigRegistrationTokenCmd.java
index facea57..761affd 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigRegistrationTokenCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigRegistrationTokenCmd.java
@@ -40,6 +40,10 @@ public class ConfigRegistrationTokenCmd extends AbstractAuthOptionsCmd implement
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
         try {
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             return process(commandInvocation);
         } finally {
             commandInvocation.stop();
@@ -120,6 +124,10 @@ public class ConfigRegistrationTokenCmd extends AbstractAuthOptionsCmd implement
         return CommandResult.SUCCESS;
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigTruststoreCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigTruststoreCmd.java
index 99917f3..49d8975 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigTruststoreCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/ConfigTruststoreCmd.java
@@ -40,6 +40,10 @@ public class ConfigTruststoreCmd extends AbstractAuthOptionsCmd implements Comma
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
         try {
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             return process(commandInvocation);
         } finally {
             commandInvocation.stop();
@@ -130,6 +134,9 @@ public class ConfigTruststoreCmd extends AbstractAuthOptionsCmd implements Comma
         return CommandResult.SUCCESS;
     }
 
+    protected String help() {
+        return usage();
+    }
 
     public static String usage() {
         StringWriter sb = new StringWriter();
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java
index 35f18a1..30008ca 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java
@@ -102,6 +102,10 @@ public class CreateCmd extends AbstractAuthOptionsCmd implements Command {
         try {
             processGlobalOptions();
 
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             if (args != null) {
                 Iterator<String> it = args.iterator();
                 while (it.hasNext()) {
@@ -226,6 +230,10 @@ public class CreateCmd extends AbstractAuthOptionsCmd implements Command {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java
index 1d6e817..7a0102d 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java
@@ -27,7 +27,6 @@ import org.keycloak.client.registration.cli.util.ParseUtil;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 import static org.keycloak.client.registration.cli.util.AuthUtil.ensureToken;
@@ -46,19 +45,23 @@ import static org.keycloak.client.registration.cli.util.OsUtil.PROMPT;
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
  */
-@CommandDefinition(name = "delete", description = "CLIENT_ID [GLOBAL_OPTIONS]")
+@CommandDefinition(name = "delete", description = "CLIENT [GLOBAL_OPTIONS]")
 public class DeleteCmd extends AbstractAuthOptionsCmd {
 
     @Arguments
-    private List<String> args = new ArrayList<>();
+    private List<String> args;
 
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
         try {
             processGlobalOptions();
 
-            if (args.isEmpty()) {
-                throw new RuntimeException("CLIENT_ID not specified");
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
+            if (args == null || args.isEmpty()) {
+                throw new RuntimeException("CLIENT not specified");
             }
 
             if (args.size() > 1) {
@@ -68,7 +71,7 @@ public class DeleteCmd extends AbstractAuthOptionsCmd {
             String clientId = args.get(0);
 
             if (clientId.startsWith("-")) {
-                warnfErr(ParseUtil.CLIENTID_OPTION_WARN, clientId);
+                warnfErr(ParseUtil.CLIENT_OPTION_WARN, clientId);
             }
 
             String regType = "default";
@@ -110,6 +113,10 @@ public class DeleteCmd extends AbstractAuthOptionsCmd {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java
index 1b6b7cc..3593641 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java
@@ -35,7 +35,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 import static org.keycloak.client.registration.cli.util.AuthUtil.ensureToken;
@@ -67,7 +66,7 @@ public class GetCmd extends AbstractAuthOptionsCmd {
     private String endpoint;
 
     @Arguments
-    private List<String> args = new ArrayList<>();
+    private List<String> args;
 
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
@@ -75,6 +74,10 @@ public class GetCmd extends AbstractAuthOptionsCmd {
         try {
             processGlobalOptions();
 
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             if (args == null || args.isEmpty()) {
                 throw new RuntimeException("CLIENT not specified");
             }
@@ -88,7 +91,7 @@ public class GetCmd extends AbstractAuthOptionsCmd {
 
 
             if (clientId.startsWith("-")) {
-                warnfErr(ParseUtil.CLIENTID_OPTION_WARN, clientId);
+                warnfErr(ParseUtil.CLIENT_OPTION_WARN, clientId);
             }
 
             ConfigData config = loadConfig();
@@ -172,6 +175,10 @@ public class GetCmd extends AbstractAuthOptionsCmd {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/KcRegCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/KcRegCmd.java
index d2b8a85..3b51342 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/KcRegCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/KcRegCmd.java
@@ -87,7 +87,8 @@ public class KcRegCmd extends AbstractGlobalOptionsCmd {
         out.println();
         out.println("Global options:");
         out.println("  -x            Print full stack trace when exiting with error");
-        out.println("  -c, --config  Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
+        out.println("  --help        Print help for specific command");
+        out.println("  --config      Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
         out.println();
         out.println("Commands: ");
         out.println("  config        Set up credentials, and other configuration settings using the config file");
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 87ab781..f028c46 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
@@ -106,6 +106,10 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
         try {
             processGlobalOptions();
 
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
             String clientId = null;
 
             if (args != null) {
@@ -117,7 +121,7 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
                 clientId = it.next();
 
                 if (clientId.startsWith("-")) {
-                    warnfErr(ParseUtil.CLIENTID_OPTION_WARN, clientId);
+                    warnfErr(ParseUtil.CLIENT_OPTION_WARN, clientId);
                 }
 
                 while (it.hasNext()) {
@@ -334,6 +338,10 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
@@ -348,7 +356,7 @@ public class UpdateCmd extends AbstractAuthOptionsCmd {
         out.println();
         out.println("  Global options:");
         out.println("    -x                    Print full stack trace when exiting with error");
-        out.println("    -c, --config          Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
+        out.println("    --config              Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
         out.println("    --truststore PATH     Path to a truststore containing trusted certificates");
         out.println("    --trustpass PASSWORD  Truststore password (prompted for if not specified and --truststore is used)");
         out.println("    --token TOKEN         Registration access token to use");
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java
index e52f5a2..3255cad 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java
@@ -32,7 +32,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 import static org.keycloak.client.registration.cli.util.AuthUtil.ensureToken;
@@ -55,7 +54,7 @@ import static org.keycloak.client.registration.cli.util.OsUtil.PROMPT;
 public class UpdateTokenCmd extends AbstractAuthOptionsCmd {
 
     @Arguments
-    private List<String> args = new ArrayList<>();
+    private List<String> args;
 
     @Override
     public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
@@ -63,14 +62,18 @@ public class UpdateTokenCmd extends AbstractAuthOptionsCmd {
         try {
             processGlobalOptions();
 
-            if (args.isEmpty()) {
+            if (printHelp()) {
+                return CommandResult.SUCCESS;
+            }
+
+            if (args == null || args.isEmpty()) {
                 throw new RuntimeException("CLIENT not specified");
             }
 
             String clientId = args.get(0);
 
             if (clientId.startsWith("-")) {
-                warnfOut(ParseUtil.CLIENTID_OPTION_WARN, clientId);
+                warnfOut(ParseUtil.CLIENT_OPTION_WARN, clientId);
             }
 
             ConfigData config = loadConfig();
@@ -129,6 +132,10 @@ public class UpdateTokenCmd extends AbstractAuthOptionsCmd {
         }
     }
 
+    protected String help() {
+        return usage();
+    }
+
     public static String usage() {
         StringWriter sb = new StringWriter();
         PrintWriter out = new PrintWriter(sb);
@@ -141,7 +148,7 @@ public class UpdateTokenCmd extends AbstractAuthOptionsCmd {
         out.println();
         out.println("  Global options:");
         out.println("    -x                    Print full stack trace when exiting with error");
-        out.println("    -c, --config          Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
+        out.println("    --config              Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)");
         out.println("    --truststore PATH     Path to a truststore containing trusted certificates");
         out.println("    --trustpass PASSWORD  Truststore password (prompted for if not specified and --truststore is used)");
         out.println("    CREDENTIALS OPTIONS   Same set of options as accepted by '" + CMD + " config credentials' in order to establish");
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/util/ParseUtil.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/util/ParseUtil.java
index 02ed27a..8d237dd 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/util/ParseUtil.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/util/ParseUtil.java
@@ -38,7 +38,7 @@ import static org.keycloak.client.registration.cli.util.ReflectionUtil.setAttrib
  */
 public class ParseUtil {
 
-    public static final String CLIENTID_OPTION_WARN = "You're using what looks like an OPTION as CLIENT_ID: %s";
+    public static final String CLIENT_OPTION_WARN = "You're using what looks like an OPTION as CLIENT: %s";
     public static final String TOKEN_OPTION_WARN = "You're using what looks like an OPTION as TOKEN: %s";
 
     public static String[] shift(String[] args) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
index 4317317..a42234c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
@@ -80,7 +80,9 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest {
 
     private void modifyClientJWKSUrl(RealmRepresentation realm, String regex, String replacement) {
         if (realm.getClients() != null) {
-            realm.getClients().stream().filter(client -> "client-jwt".equals(client.getClientAuthenticatorType())).forEach(client -> {
+            realm.getClients().stream().
+                    filter(client -> "client-jwt".equals(client.getClientAuthenticatorType()) && client.getAttributes().containsKey("jwks.url")).
+                    forEach(client -> {
                 Map<String, String> attr = client.getAttributes();
                 attr.put("jwks.url", attr.get("jwks.url").replaceFirst(regex, replacement));
                 client.setAttributes(attr);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java
index bd8fc7c..473fb1d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java
@@ -23,17 +23,17 @@ public class KcRegConfigTest extends AbstractCliTest {
 
         try (TempFileResource configFile = new TempFileResource(handler.getConfigFile())) {
 
-            // forget --server
+            // without --server
             KcRegExec exe = execute("config registration-token --config '" + configFile.getName() + "' ");
             assertExitCodeAndStreamSizes(exe, 1, 0, 1);
             Assert.assertEquals("error message", "Required option not specified: --server", exe.stderrLines().get(0));
 
-            // forget --realm
+            // without --realm
             exe = execute("config registration-token --config '" + configFile.getName() + "' --server http://localhost:8080/auth");
             assertExitCodeAndStreamSizes(exe, 1, 0, 1);
             Assert.assertEquals("error message", "Required option not specified: --realm", exe.stderrLines().get(0));
 
-            // forget --client
+            // without --client
             exe = execute("config registration-token --config '" + configFile.getName() + "' --server http://localhost:8080/auth --realm test");
             assertExitCodeAndStreamSizes(exe, 1, 0, 1);
             Assert.assertEquals("error message", "Required option not specified: --client", exe.stderrLines().get(0));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTest.java
index b4ea473..2469880 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTest.java
@@ -5,6 +5,7 @@ import org.junit.Test;
 import org.keycloak.client.registration.cli.config.ConfigData;
 import org.keycloak.client.registration.cli.config.FileConfigHandler;
 import org.keycloak.client.registration.cli.config.RealmConfigData;
+import org.keycloak.client.registration.cli.util.OsUtil;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.testsuite.cli.KcRegExec;
 import org.keycloak.testsuite.util.TempFileResource;
@@ -16,6 +17,7 @@ import java.io.IOException;
 import java.util.List;
 import java.util.UUID;
 
+import static org.keycloak.client.registration.cli.util.OsUtil.CMD;
 import static org.keycloak.client.registration.cli.util.OsUtil.EOL;
 import static org.keycloak.testsuite.cli.KcRegExec.execute;
 
@@ -27,7 +29,7 @@ public class KcRegTest extends AbstractCliTest {
     @Test
     public void testNoArgs() {
         /*
-         *  Test most basic execution that returns the initial help
+         *  Test (sub)commands without any arguments
          */
         KcRegExec exe = execute("");
 
@@ -41,6 +43,123 @@ public class KcRegTest extends AbstractCliTest {
 
         lines = exe.stderrLines();
         Assert.assertTrue("stderr output empty", lines.size() == 0);
+
+        /*
+         * Test commands without arguments
+         */
+        exe = execute("config");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message",
+                "Sub-command required by '" + OsUtil.CMD + " config' - one of: 'credentials', 'truststore', 'initial-token', 'registration-token'",
+                exe.stderrLines().get(0));
+
+        exe = execute("create");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message", "No file nor attribute values specified", exe.stderrLines().get(0));
+
+        exe = execute("get");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message", "CLIENT not specified", exe.stderrLines().get(0));
+
+        exe = execute("update");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message", "No file nor attribute values specified", exe.stderrLines().get(0));
+
+        exe = execute("delete");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message", "CLIENT not specified", exe.stderrLines().get(0));
+
+        exe = execute("attrs");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertTrue("stdout has response", exe.stdoutLines().size() > 10);
+        Assert.assertEquals("first line", "Attributes for default format:", exe.stdoutLines().get(0));
+
+        exe = execute("update-token");
+        assertExitCodeAndStreamSizes(exe, 1, 0, 1);
+        Assert.assertEquals("error message", "CLIENT not specified", exe.stderrLines().get(0));
+
+        exe = execute("help");
+        Assert.assertEquals("exitCode == 0", 0, exe.exitCode());
+        lines = exe.stdoutLines();
+        Assert.assertTrue("stdout output not empty", lines.size() > 0);
+        Assert.assertEquals("stdout first line", "Keycloak Client Registration CLI", lines.get(0));
+        Assert.assertEquals("stdout one but last line", "Use '" + KcRegExec.CMD + " help <command>' for more information about a given command.", lines.get(lines.size() - 2));
+        Assert.assertEquals("stdout last line", "", lines.get(lines.size() - 1));
+    }
+
+    @Test
+    public void testHelpGlobalOption() {
+        /*
+         *  Test --help for all commands
+         */
+        KcRegExec exe = execute("--help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Keycloak Client Registration CLI", exe.stdoutLines().get(0));
+
+        exe = execute("create --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " create [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("get --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " get CLIENT [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("update --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " update CLIENT [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("delete --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " delete CLIENT [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("attrs --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " attrs [ATTRIBUTE] [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("update-token --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + CMD + " update-token CLIENT [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("config --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line", "Usage: " + OsUtil.CMD + " config SUB_COMMAND [ARGUMENTS]", exe.stdoutLines().get(0));
+
+        exe = execute("config credentials --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line",
+                "Usage: " + CMD + " config credentials --server SERVER_URL --realm REALM [ARGUMENTS]",
+                exe.stdoutLines().get(0));
+
+        exe = execute("config initial-token --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line",
+                "Usage: " + CMD + " config initial-token --server SERVER --realm REALM [--delete | TOKEN] [ARGUMENTS]",
+                exe.stdoutLines().get(0));
+
+        exe = execute("config registration-token --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line",
+                "Usage: " + CMD + " config registration-token --server SERVER --realm REALM --client CLIENT [--delete | TOKEN] [ARGUMENTS]",
+                exe.stdoutLines().get(0));
+
+        exe = execute("config truststore --help");
+        Assert.assertEquals("exit code", 0, exe.exitCode());
+        Assert.assertEquals("no stderr", 0, exe.stderrLines().size());
+        Assert.assertEquals("stdout first line",
+                "Usage: " + CMD + " config truststore [TRUSTSTORE | --delete] [--trustpass PASSWOD] [ARGUMENTS]",
+                exe.stdoutLines().get(0));
+
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/InitialAccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/InitialAccessTokenTest.java
index 4383583..b87efd6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/InitialAccessTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/InitialAccessTokenTest.java
@@ -57,6 +57,7 @@ public class InitialAccessTokenTest extends AbstractClientRegistrationTest {
 
         try {
             reg.create(rep);
+            Assert.fail("Expected exception");
         } catch (ClientRegistrationException e) {
             Assert.assertEquals(401, ((HttpErrorException) e.getCause()).getStatusLine().getStatusCode());
         }
@@ -78,6 +79,7 @@ public class InitialAccessTokenTest extends AbstractClientRegistrationTest {
 
         try {
             reg.create(rep);
+            Assert.fail("Expected exception");
         } catch (ClientRegistrationException e) {
             Assert.assertEquals(401, ((HttpErrorException) e.getCause()).getStatusLine().getStatusCode());
         }
@@ -95,6 +97,7 @@ public class InitialAccessTokenTest extends AbstractClientRegistrationTest {
 
         try {
             reg.create(rep);
+            Assert.fail("Expected exception");
         } catch (ClientRegistrationException e) {
             Assert.assertEquals(401, ((HttpErrorException) e.getCause()).getStatusLine().getStatusCode());
         }
@@ -112,6 +115,7 @@ public class InitialAccessTokenTest extends AbstractClientRegistrationTest {
 
         try {
             reg.create(rep);
+            Assert.fail("Expected exception");
         } catch (ClientRegistrationException e) {
             Assert.assertEquals(401, ((HttpErrorException) e.getCause()).getStatusLine().getStatusCode());
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/RegistrationAccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/RegistrationAccessTokenTest.java
index 491470e..1e48290 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/RegistrationAccessTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/RegistrationAccessTokenTest.java
@@ -109,7 +109,9 @@ public class RegistrationAccessTokenTest extends AbstractClientRegistrationTest 
 
     @Test
     public void getClientWithBadRegistrationToken() throws ClientRegistrationException {
-        reg.auth(Auth.token("invalid"));
+        String oldToken = client.getRegistrationAccessToken();
+        reg.update(client);
+        reg.auth(Auth.token(oldToken));
         try {
             reg.get(client.getClientId());
             fail("Expected 401");
@@ -134,9 +136,9 @@ public class RegistrationAccessTokenTest extends AbstractClientRegistrationTest 
 
     @Test
     public void updateClientWithBadRegistrationToken() throws ClientRegistrationException {
-        client.setRootUrl("http://newroot");
-
-        reg.auth(Auth.token("invalid"));
+        String oldToken = client.getRegistrationAccessToken();
+        reg.update(client);
+        reg.auth(Auth.token(oldToken));
         try {
             reg.update(client);
             fail("Expected 401");
@@ -155,7 +157,9 @@ public class RegistrationAccessTokenTest extends AbstractClientRegistrationTest 
 
     @Test
     public void deleteClientWithBadRegistrationToken() throws ClientRegistrationException {
-        reg.auth(Auth.token("invalid"));
+        String oldToken = client.getRegistrationAccessToken();
+        reg.update(client);
+        reg.auth(Auth.token(oldToken));
         try {
             reg.delete(client);
             fail("Expected 401");
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
index a7c9e5d..ade7b83 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
@@ -15,7 +15,7 @@
         <div class="row" data-ng-show="access.manageIdentityProviders">
           <div class="col-sm-4 col-sm-offset-4">
             <div class="form-group">
-            <select class="selectpicker form-control" ng-model="provider"
+            <select class="form-control" ng-model="provider"
               ng-options="p.name group by p.groupName for p in allProviders track by p.id"
               data-ng-change="addProvider(provider); provider = null">
               <option value="" disabled selected>{{:: 'add-provider.placeholder' | translate}}</option>