From c35c6e6ab778cdb53fe1dfda74cc9420876cecbb Mon Sep 17 00:00:00 2001 From: Marko Strukelj Date: Mon, 27 Nov 2017 16:07:02 +0100 Subject: [PATCH] KEYCLOAK-5762 [Client Registration CLI] Fix instructions in built-in help --- .../cli/commands/AbstractAuthOptionsCmd.java | 8 ++++++-- .../cli/commands/ConfigCredentialsCmd.java | 2 ++ .../cli/commands/ConfigInitialTokenCmd.java | 3 ++- .../commands/ConfigRegistrationTokenCmd.java | 5 +++-- .../cli/commands/ConfigTruststoreCmd.java | 3 ++- .../registration/cli/commands/CreateCmd.java | 5 +++-- .../registration/cli/commands/DeleteCmd.java | 7 ++++--- .../registration/cli/commands/GetCmd.java | 7 ++++--- .../registration/cli/commands/KcRegCmd.java | 1 + .../registration/cli/commands/UpdateCmd.java | 7 ++++--- .../cli/commands/UpdateTokenCmd.java | 9 +++++---- .../cli/registration/KcRegConfigTest.java | 15 +++++++++++++++ .../testsuite/cli/registration/KcRegTest.java | 12 ++++++++++++ .../cli/registration/KcRegTruststoreTest.java | 17 ++++++++++++----- 14 files changed, 75 insertions(+), 26 deletions(-) diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractAuthOptionsCmd.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractAuthOptionsCmd.java index 7c5e5fe601..196c789575 100644 --- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractAuthOptionsCmd.java +++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/commands/AbstractAuthOptionsCmd.java @@ -29,7 +29,7 @@ public abstract class AbstractAuthOptionsCmd extends AbstractGlobalOptionsCmd { @Option(name = "config", description = "Path to the config file (~/.keycloak/kcreg.config by default)", hasValue = true) protected String config; - @Option(name = "no-config", description = "No configuration file should be used, no authentication info should be saved", hasValue = false) + @Option(name = "no-config", description = "No configuration file should be used, no authentication info is loaded or saved", hasValue = false) protected boolean noconfig; @Option(name = "server", description = "Server endpoint url (e.g. 'http://localhost:8080/auth')", hasValue = true) @@ -237,8 +237,12 @@ public abstract class AbstractAuthOptionsCmd extends AbstractGlobalOptionsCmd { String value = options[++i]; if (value != null) { - throw new RuntimeException("Unsupported option: " + name); + throw new IllegalArgumentException("Unsupported option: " + name); } } } + + protected static String booleanOptionForCheck(boolean value) { + return value ? "true" : null; + } } 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 d83f2c4c6f..31f7bd2aab 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 @@ -67,6 +67,8 @@ public class ConfigCredentialsCmd extends AbstractAuthOptionsCmd implements Comm return help ? CommandResult.SUCCESS : CommandResult.FAILURE; } + checkUnsupportedOptions("--no-config", booleanOptionForCheck(noconfig)); + processGlobalOptions(); return process(commandInvocation); 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 0db641ee0e..ee46d85e0e 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 @@ -111,7 +111,8 @@ public class ConfigInitialTokenCmd extends AbstractAuthOptionsCmd implements Com "--keypass", keyPass, "--alias", alias, "--truststore", trustStore, - "--trustpass", keyPass); + "--trustpass", keyPass, + "--no-config", booleanOptionForCheck(noconfig)); if (!delete && token == null) { 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 9e38503f68..5bd7af81d2 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 @@ -63,7 +63,7 @@ public class ConfigRegistrationTokenCmd extends AbstractAuthOptionsCmd implement List args = new ArrayList<>(); Iterator it = parent.args.iterator(); - // skip the first argument 'initial-token' + // skip the first argument 'registration-token' it.next(); while (it.hasNext()) { @@ -107,7 +107,8 @@ public class ConfigRegistrationTokenCmd extends AbstractAuthOptionsCmd implement "--keypass", keyPass, "--alias", alias, "--truststore", trustStore, - "--trustpass", keyPass); + "--trustpass", keyPass, + "--no-config", booleanOptionForCheck(noconfig)); if (!delete && token == null) { 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 ecadf62643..d88d6b0265 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 @@ -114,7 +114,8 @@ public class ConfigTruststoreCmd extends AbstractAuthOptionsCmd implements Comma "--truststore", trustStore, "--keystore", keystore, "--keypass", keyPass, - "--alias", alias); + "--alias", alias, + "--no-config", booleanOptionForCheck(noconfig)); // now update the config processGlobalOptions(); 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 cdecfff99a..ae3791e122 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 @@ -260,11 +260,12 @@ public class CreateCmd extends AbstractAuthOptionsCmd implements Command { out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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"); - out.println(" an authenticated sessions. This allows on-the-fly transient authentication that does"); - out.println(" not touch a config file."); + out.println(" an authenticated sessions. In combination with --no-config option this allows transient"); + out.println(" (on-the-fly) authentication to be performed which leaves no tokens in config file."); out.println(); out.println(" Command specific options:"); out.println(" -t, --token TOKEN Use the specified Initial Access Token for authorization or read it from standard input "); 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 291023ae89..457e5e0064 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 @@ -142,15 +142,16 @@ public class DeleteCmd extends AbstractAuthOptionsCmd { out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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"); out.println(" CREDENTIALS OPTIONS Same set of options as accepted by '" + CMD + " config credentials' in order to establish"); - out.println(" an authenticated sessions. This allows on-the-fly transient authentication that does"); - out.println(" not touch a config file."); + out.println(" an authenticated sessions. In combination with --no-config option this allows transient"); + out.println(" (on-the-fly) authentication to be performed which leaves no tokens in config file."); out.println(); out.println(" Command specific options:"); out.println(" CLIENT ClientId of the client to delete"); + out.println(" -t, --token TOKEN Use the specified Registration Access Token for authorization"); out.println(); out.println("Examples:"); out.println(); 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 c28fd95979..2a9ee8ec88 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 @@ -204,15 +204,16 @@ public class GetCmd extends AbstractAuthOptionsCmd { out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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(" -t, --token TOKEN Registration access token to use"); out.println(" CREDENTIALS OPTIONS Same set of options as accepted by '" + CMD + " config credentials' in order to establish"); - out.println(" an authenticated sessions. This allows on-the-fly transient authentication that does"); - out.println(" not touch a config file."); + out.println(" an authenticated sessions. In combination with --no-config option this allows transient"); + out.println(" (on-the-fly) authentication to be performed which leaves no tokens in config file."); out.println(); out.println(" Command specific options:"); out.println(" CLIENT ClientId of the client to display"); + out.println(" -t, --token TOKEN Use the specified Registration Access Token for authorization"); out.println(" -c, --compressed Don't pretty print the output"); out.println(" -e, --endpoint TYPE Endpoint type to use - one of: 'default', 'oidc', 'install'"); out.println(); 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 a166303871..8704cd875a 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 @@ -94,6 +94,7 @@ public class KcRegCmd extends AbstractGlobalOptionsCmd { out.println(" -x Print full stack trace when exiting with error"); out.println(" --help Print help for specific command"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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 91928790fc..4704608a94 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 @@ -364,15 +364,16 @@ public class UpdateCmd extends AbstractAuthOptionsCmd { out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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"); out.println(" CREDENTIALS OPTIONS Same set of options as accepted by '" + CMD + " config credentials' in order to establish"); - out.println(" an authenticated sessions. This allows on-the-fly transient authentication that does"); - out.println(" not touch a config file."); + out.println(" an authenticated sessions. In combination with --no-config option this allows transient"); + out.println(" (on-the-fly) authentication to be performed which leaves no tokens in config file."); out.println(); out.println(" Command specific options:"); out.println(" CLIENT ClientId of the client to update"); + out.println(" -t, --token TOKEN Use the specified Registration Access Token for authorization"); out.println(" -s, --set KEY=VALUE Set specific attribute to a specified value"); out.println(" KEY+=VALUE Add item to an array"); out.println(" -d, --delete NAME Delete the specific attribute, or array item"); 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 16295f4ef1..e555638c70 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 @@ -161,16 +161,17 @@ public class UpdateTokenCmd extends AbstractAuthOptionsCmd { out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to the config file (" + DEFAULT_CONFIG_FILE_STRING + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); 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"); - out.println(" an authenticated sessions. This allows on-the-fly transient authentication that leaves"); - out.println(" no tokens in config file."); + out.println(" an authenticated sessions. In combination with --no-config option this allows transient"); + out.println(" (on-the-fly) authentication to be performed which leaves no tokens in config file."); out.println(); out.println(" Command specific options:"); out.println(" CLIENT ClientId of the client to reissue a new Registration Access Token for"); - out.println(" The new token is saved to a config file or printed to stdout if on-the-fly\n"); - out.println(" authentication is used"); + out.println(" The new token is saved to a config file or printed to stdout if --no-config"); + out.println(" (on-the-fly) authentication is used"); out.println(); out.println("Examples:"); out.println(); 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 1bf7b3896e..8917f210b2 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 @@ -70,4 +70,19 @@ public class KcRegConfigTest extends AbstractRegCliTest { assertExitCodeAndStreamSizes(exe, 0, 0, 0); } } + + @Test + public void testNoConfigOption() throws IOException { + + KcRegExec exe = execute("config registration-token --no-config --server http://localhost:8080/auth --realm test --client my_client --delete"); + assertExitCodeAndStreamSizes(exe, 1, 0, 2); + Assert.assertEquals("stderr first line", "Unsupported option: --no-config", exe.stderrLines().get(0)); + Assert.assertEquals("try help", "Try '" + CMD + " help config registration-token' for more information", exe.stderrLines().get(1)); + + exe = execute("config initial-token --no-config --server http://localhost:8080/auth --realm test --delete"); + assertExitCodeAndStreamSizes(exe, 1, 0, 2); + Assert.assertEquals("stderr first line", "Unsupported option: --no-config", exe.stderrLines().get(0)); + Assert.assertEquals("try help", "Try '" + CMD + " help config initial-token' for more information", exe.stderrLines().get(1)); + + } } \ No newline at end of file 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 872ed320d0..1033da1d62 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 @@ -246,6 +246,18 @@ public class KcRegTest extends AbstractRegCliTest { Assert.assertEquals("try help", "Try '" + CMD + " help config credentials' for more information", exe.stderrLines().get(1)); } + @Test + public void testCredentialsWithNoConfig() { + /* + * Test with --no-config specified which is not supported + */ + KcRegExec exe = KcRegExec.execute("config credentials --no-config --server " + serverUrl + " --realm master --user admin --password admin"); + + assertExitCodeAndStreamSizes(exe, 1, 0, 2); + Assert.assertEquals("stderr first line", "Unsupported option: --no-config", exe.stderrLines().get(0)); + Assert.assertEquals("try help", "Try '" + CMD + " help config credentials' for more information", exe.stderrLines().get(1)); + } + @Test public void testUserLoginWithDefaultConfig() { /* diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTruststoreTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTruststoreTest.java index 34c9584fa2..fcfdeb23d8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTruststoreTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegTruststoreTest.java @@ -4,6 +4,7 @@ import org.junit.Assert; 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.util.OsUtil; import org.keycloak.testsuite.cli.KcRegExec; import org.keycloak.testsuite.util.TempFileResource; @@ -23,21 +24,27 @@ public class KcRegTruststoreTest extends AbstractRegCliTest { @Test public void testTruststore() throws IOException { - // only run this test if ssl protected keycloak server is available + File truststore = new File("src/test/resources/keystore/keycloak.truststore"); + + KcRegExec exe = execute("config truststore --no-config '" + truststore.getAbsolutePath() + "'"); + + assertExitCodeAndStreamSizes(exe, 1, 0, 2); + Assert.assertEquals("stderr first line", "Unsupported option: --no-config", exe.stderrLines().get(0)); + Assert.assertEquals("try help", "Try '" + OsUtil.CMD + " help config truststore' for more information", exe.stderrLines().get(1)); + + // only run the rest of this test if ssl protected keycloak server is available if (!isAuthServerSSL()) { System.out.println("TEST SKIPPED - This test requires HTTPS. Run with '-Pauth-server-wildfly -Dauth.server.ssl.required=true'"); return; } - File truststore = new File("src/test/resources/keystore/keycloak.truststore"); - FileConfigHandler handler = initCustomConfigFile(); try (TempFileResource configFile = new TempFileResource(handler.getConfigFile())) { if (runIntermittentlyFailingTests()) { // configure truststore - KcRegExec exe = execute("config truststore --config '" + configFile.getName() + "' '" + truststore.getAbsolutePath() + "'"); + exe = execute("config truststore --config '" + configFile.getName() + "' '" + truststore.getAbsolutePath() + "'"); assertExitCodeAndStreamSizes(exe, 0, 0, 0); @@ -80,7 +87,7 @@ public class KcRegTruststoreTest extends AbstractRegCliTest { } // configure truststore with password - KcRegExec exe = execute("config truststore --trustpass secret '" + truststore.getAbsolutePath() + "'"); + exe = execute("config truststore --trustpass secret '" + truststore.getAbsolutePath() + "'"); assertExitCodeAndStreamSizes(exe, 0, 0, 0); // perform authentication against server - asks for password, then for truststore password