From c7e9ee2bfffe96d01fc8634e6b2e303abc9ea7c0 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Thu, 6 Jun 2024 09:08:23 -0400 Subject: [PATCH] fix: adds handling for all kcadm prompts as env variables (#29430) closes: #21961 Signed-off-by: Steve Hawkins --- .../server_admin/topics/admin-cli.adoc | 11 +++++-- .../keycloak/client/admin/cli/KcAdmMain.java | 5 ++++ .../cli/commands/AbstractAuthOptionsCmd.java | 1 - .../admin/cli/commands/AddRolesCmd.java | 22 ++------------ .../client/admin/cli/commands/CreateCmd.java | 22 +------------- .../client/admin/cli/commands/DeleteCmd.java | 22 +------------- .../client/admin/cli/commands/GetCmd.java | 22 +------------- .../admin/cli/commands/GetRolesCmd.java | 21 +------------ .../client/admin/cli/commands/HelpCmd.java | 16 +++++----- .../admin/cli/commands/RemoveRolesCmd.java | 21 +------------ .../admin/cli/commands/SetPasswordCmd.java | 25 ++-------------- .../client/admin/cli/commands/UpdateCmd.java | 22 +------------- .../client/cli/common/BaseAuthOptionsCmd.java | 30 +++++++++++++++---- .../cli/common/BaseConfigCredentialsCmd.java | 16 +++++----- .../cli/common/BaseConfigTruststoreCmd.java | 2 +- .../client/cli/common/CommandState.java | 2 ++ .../org/keycloak/client/cli/util/IoUtil.java | 8 ----- .../client/registration/cli/KcRegMain.java | 5 ++++ .../registration/cli/commands/CreateCmd.java | 20 +------------ .../registration/cli/commands/DeleteCmd.java | 20 +------------ .../registration/cli/commands/GetCmd.java | 20 +------------ .../registration/cli/commands/HelpCmd.java | 10 +++---- .../registration/cli/commands/UpdateCmd.java | 19 +----------- .../cli/commands/UpdateTokenCmd.java | 20 +------------ .../cli/admin/AbstractAdmCliTest.java | 14 ++++++--- .../testsuite/cli/admin/KcAdmSessionTest.java | 5 ++-- 26 files changed, 95 insertions(+), 306 deletions(-) diff --git a/docs/documentation/server_admin/topics/admin-cli.adoc b/docs/documentation/server_admin/topics/admin-cli.adoc index 2c4745cf92..837deae50c 100644 --- a/docs/documentation/server_admin/topics/admin-cli.adoc +++ b/docs/documentation/server_admin/topics/admin-cli.adoc @@ -87,6 +87,10 @@ $ kcadm.sh config truststore --trustpass $PASSWORD ~/.keycloak/truststore.jks c:\> kcadm config truststore --trustpass %PASSWORD% %HOMEPATH%\.keycloak\truststore.jks ---- +=== Sensitive Options + +Sensitive values, such as passwords, may be specified as command options. That is generally not recommended. There are also mechanisms by which you can be prompted for the sensitive value - by either omitting the option or providing a value or -. Finally all will have a corresponding env variable that can be used instead - check the help of the command you are running to see all possible options. + === Authenticating When you log in with the Admin CLI, you specify: @@ -105,7 +109,7 @@ Two primary mechanisms are available for authentication. One mechanism uses `kca [options="nowrap",subs="attributes+"] ---- -$ kcadm.sh config credentials --server http://localhost:8080{kc_base_path} --realm master --user admin --password admin +$ kcadm.sh config credentials --server http://localhost:8080{kc_base_path} --realm master --user admin ---- This mechanism maintains an authenticated session between the `kcadm` command invocations by saving the obtained access token and its associated refresh token. It can maintain other secrets in a private configuration file. See the <<_working_with_alternative_configurations, next chapter>> for more information. @@ -115,13 +119,14 @@ The second mechanism authenticates each command invocation for the duration of t For example, when performing an operation, specify all the information required for authentication. [options="nowrap",subs="attributes+"] ---- -$ kcadm.sh get realms --no-config --server http://localhost:8080{kc_base_path} --realm master --user admin --password admin +$ kcadm.sh get realms --no-config --server http://localhost:8080{kc_base_path} --realm master --user admin ---- Run the `kcadm.sh help` command for more information on using the Admin CLI. Run the `kcadm.sh config credentials --help` command for more information about starting an authenticated session. +If you do not specify the --password option (it is generally recommended to not provide passwords as part of the command), you will be prompted for a password unless one is specified as the environment variable KC_CLI_PASSWORD. [[_working_with_alternative_configurations]] === Working with alternative configurations @@ -184,7 +189,7 @@ SERVER_URI/admin/realms/TARGET_REALM/ENDPOINT For example: [options="nowrap",subs="attributes+"] ---- -$ kcadm.sh config credentials --server http://localhost:8080{kc_base_path} --realm master --user admin --password admin +$ kcadm.sh config credentials --server http://localhost:8080{kc_base_path} --realm master --user admin $ kcadm.sh create users -s username=testuser -s enabled=true -r demorealm ---- diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java index 50e35ee2b8..b50000dc24 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java @@ -44,6 +44,11 @@ public class KcAdmMain { return DEFAULT_CONFIG_FILE_PATH; } + @Override + public boolean isTokenGlobal() { + return true; + }; + }; public static void main(String [] args) { diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AbstractAuthOptionsCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AbstractAuthOptionsCmd.java index 88234618d2..8e8f16e2c3 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AbstractAuthOptionsCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AbstractAuthOptionsCmd.java @@ -22,7 +22,6 @@ import org.keycloak.client.cli.config.ConfigData; import picocli.CommandLine.Option; - /** * @author Marko Strukelj */ diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AddRolesCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AddRolesCmd.java index 9f4c8e3d95..314a22991a 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AddRolesCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/AddRolesCmd.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import picocli.CommandLine.Command; import picocli.CommandLine.Option; -import org.keycloak.client.admin.cli.KcAdmMain; import org.keycloak.client.admin.cli.operations.ClientOperations; import org.keycloak.client.admin.cli.operations.GroupOperations; import org.keycloak.client.admin.cli.operations.RoleOperations; @@ -264,10 +263,6 @@ public class AddRolesCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " add-roles (--uusername USERNAME | --uid ID) [--cclientid CLIENT_ID | --cid ID] (--rolename NAME | --roleid ID)+ [ARGUMENTS]"); @@ -284,21 +279,7 @@ public class AddRolesCmd extends AbstractAuthOptionsCmd { out.println("to a specific user. If group is specified using --gname, --gpath or --gid then roles are added to a specific group."); out.println("If composite role is specified using --rname or --rid then roles are added to a specific composite role."); out.println("One or more roles have to be specified using --rolename or --roleid so that they are added to a group, a user or a composite role."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" --uusername User's 'username'. If more than one user exists with the same username"); out.println(" you'll have to use --uid to specify the target user"); out.println(" --uid User's 'id' attribute"); @@ -333,4 +314,5 @@ public class AddRolesCmd extends AbstractAuthOptionsCmd { out.println("Use '" + CMD + " help' for general information and a list of commands"); return sb.toString(); } + } diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/CreateCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/CreateCmd.java index 98694244f5..acd83f7976 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/CreateCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/CreateCmd.java @@ -16,8 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; - import java.io.PrintWriter; import java.io.StringWriter; @@ -75,10 +73,6 @@ public class CreateCmd extends AbstractRequestCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " create ENDPOINT_URI [ARGUMENTS]"); @@ -87,21 +81,7 @@ public class CreateCmd extends AbstractRequestCmd { out.println(); out.println("Use '" + CMD + " config credentials' to establish an authenticated sessions, or use --no-config with "); out.println("CREDENTIALS OPTIONS to perform one time authentication."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" ENDPOINT_URI URI used to compose a target resource url. Commonly used values are:"); out.println(" realms, users, roles, groups, clients, keys, serverinfo, components ..."); out.println(" If it starts with 'http://' then it will be used as target resource url"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/DeleteCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/DeleteCmd.java index 85a52e458c..8d8d76efdd 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/DeleteCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/DeleteCmd.java @@ -16,8 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; - import java.io.PrintWriter; import java.io.StringWriter; @@ -39,10 +37,6 @@ public class DeleteCmd extends CreateCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " delete ENDPOINT_URI [ARGUMENTS]"); @@ -51,21 +45,7 @@ public class DeleteCmd extends CreateCmd { out.println(); out.println("Use '" + CMD + " config credentials' to establish an authenticated sessions, or use CREDENTIALS OPTIONS"); out.println("to perform one time authentication."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" ENDPOINT_URI URI used to compose a target resource url. Commonly used values start with:"); out.println(" realms/, users/, roles/, groups/, clients/, keys/, components/ ..."); out.println(" If it starts with 'http://' then it will be used as target resource url"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetCmd.java index 13866bb5c8..383e3999b8 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetCmd.java @@ -16,8 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; - import java.io.PrintWriter; import java.io.StringWriter; @@ -75,10 +73,6 @@ public class GetCmd extends AbstractRequestCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " get ENDPOINT_URI [ARGUMENTS]"); @@ -87,21 +81,7 @@ public class GetCmd extends AbstractRequestCmd { out.println(); out.println("Use '" + CMD + " config credentials' to establish an authenticated session, or use CREDENTIALS OPTIONS"); out.println("to perform one time authentication."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" ENDPOINT_URI URI used to compose a target resource url. Commonly used values are:"); out.println(" realms, users, roles, groups, clients, keys, serverinfo, components ..."); out.println(" If it starts with 'http://' then it will be used as target resource url"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetRolesCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetRolesCmd.java index 3568d45869..6716c9908c 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetRolesCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/GetRolesCmd.java @@ -16,7 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; import org.keycloak.client.admin.cli.operations.ClientOperations; import org.keycloak.client.admin.cli.operations.GroupOperations; import org.keycloak.client.admin.cli.operations.RoleOperations; @@ -293,10 +292,6 @@ public class GetRolesCmd extends GetCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " get-roles [--cclientid CLIENT_ID | --cid ID] [ARGUMENTS]"); @@ -319,21 +314,7 @@ public class GetRolesCmd extends GetCmd { out.println("If --effective is specified, then roles added to the target user or group are transitively resolved and a full"); out.println("set of roles in effect for that user, group or composite role is returned."); out.println("If --all is specified, then client roles for all clients are returned in addition to realm roles."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" --uusername User's 'username'. If more than one user exists with the same username"); out.println(" you'll have to use --uid to specify the target user"); out.println(" --uid User's 'id' attribute"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/HelpCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/HelpCmd.java index 3a3ca05a1e..c04d6db0e8 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/HelpCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/HelpCmd.java @@ -52,35 +52,35 @@ public class HelpCmd implements Runnable { break; } case "create": { - printOut(CreateCmd.usage()); + printOut(new CreateCmd().help()); break; } case "get": { - printOut(GetCmd.usage()); + printOut(new GetCmd().help()); break; } case "update": { - printOut(UpdateCmd.usage()); + printOut(new UpdateCmd().help()); break; } case "delete": { - printOut(DeleteCmd.usage()); + printOut(new DeleteCmd().help()); break; } case "get-roles": { - printOut(GetRolesCmd.usage()); + printOut(new GetRolesCmd().help()); break; } case "add-roles": { - printOut(AddRolesCmd.usage()); + printOut(new AddRolesCmd().help()); break; } case "remove-roles": { - printOut(RemoveRolesCmd.usage()); + printOut(new RemoveRolesCmd().help()); break; } case "set-password": { - printOut(SetPasswordCmd.usage()); + printOut(new SetPasswordCmd().help()); break; } case "new-object": { diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/RemoveRolesCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/RemoveRolesCmd.java index b07b5de404..992a9226e8 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/RemoveRolesCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/RemoveRolesCmd.java @@ -16,7 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; import org.keycloak.client.admin.cli.operations.ClientOperations; import org.keycloak.client.admin.cli.operations.GroupOperations; import org.keycloak.client.admin.cli.operations.LocalSearch; @@ -271,10 +270,6 @@ public class RemoveRolesCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " remove-roles (--uusername USERNAME | --uid ID) [--cclientid CLIENT_ID | --cid ID] (--rolename NAME | --roleid ID)+ [ARGUMENTS]"); @@ -291,21 +286,7 @@ public class RemoveRolesCmd extends AbstractAuthOptionsCmd { out.println("from a specific user. If group is specified using --gname, --gpath or --gid then roles are removed from a specific group."); out.println("If composite role is specified using --rname or --rid then roles are removed from a specific composite role."); out.println("One or more roles have to be specified using --rolename or --roleid to be removed from a group, a user or a composite role."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" --uusername User's 'username'. If more than one user exists with the same username"); out.println(" you'll have to use --uid to specify the target user"); out.println(" --uid User's 'id' attribute"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/SetPasswordCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/SetPasswordCmd.java index baa99fc828..2446070b17 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/SetPasswordCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/SetPasswordCmd.java @@ -16,7 +16,6 @@ */ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; import org.keycloak.client.cli.config.ConfigData; import java.io.PrintWriter; @@ -45,7 +44,7 @@ public class SetPasswordCmd extends AbstractAuthOptionsCmd { @Option(names = "--userid", description = "User ID") String userid; - @Option(names = {"-p", "--new-password"}, description = "New password") + @Option(names = {"-p", "--new-password"}, description = "New password", defaultValue = "${env:KC_CLI_PASSWORD}") String pass; @Option(names = {"-t", "--temporary"}, description = "is password temporary") @@ -99,10 +98,6 @@ public class SetPasswordCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " set-password (--username USERNAME | --userid ID) [--new-password PASSWORD] [ARGUMENTS]"); @@ -111,24 +106,10 @@ public class SetPasswordCmd extends AbstractAuthOptionsCmd { out.println(); out.println("Use `" + CMD + " config credentials` to establish an authenticated session, or use CREDENTIALS OPTIONS"); out.println("to perform one time authentication."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" --username USERNAME Identify target user by 'username'"); out.println(" --userid ID Identify target user by 'id'"); - out.println(" -p, --new-password New password to set. If not specified you will be prompted for it."); + out.println(" -p, --new-password New password to set. If not specified and the env variable KC_CLI_PASSWORD is not defined, you will be prompted for it."); out.println(" -t, --temporary Make the new password temporary - user has to change it on next logon"); out.println(" -a, --admin-root URL URL of Admin REST endpoint root if not default - e.g. http://localhost:8080/admin"); out.println(" -r, --target-realm REALM Target realm to issue requests against if not the one authenticated against"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/UpdateCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/UpdateCmd.java index 2ef02b1a0b..29cd5ceb1d 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/UpdateCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/commands/UpdateCmd.java @@ -17,8 +17,6 @@ package org.keycloak.client.admin.cli.commands; -import org.keycloak.client.admin.cli.KcAdmMain; - import java.io.PrintWriter; import java.io.StringWriter; @@ -81,10 +79,6 @@ public class UpdateCmd extends AbstractRequestCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " update ENDPOINT_URI [ARGUMENTS]"); @@ -93,21 +87,7 @@ public class UpdateCmd extends AbstractRequestCmd { out.println(); out.println("Use '" + CMD + " config credentials' to establish an authenticated sessions, or use CREDENTIALS OPTIONS"); out.println("to perform one time authentication."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcAdmMain.DEFAULT_CONFIG_FILE_STRING + " by default)"); - out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); - out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); - 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. 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:"); + globalOptions(out); out.println(" ENDPOINT_URI URI used to compose a target resource url. Commonly used values start with:"); out.println(" realms/, users/, roles/, groups/, clients/, keys/, components/ ..."); out.println(" If it starts with 'http://' then it will be used as target resource url"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseAuthOptionsCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseAuthOptionsCmd.java index 6393e3bacf..e2fd26374b 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseAuthOptionsCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseAuthOptionsCmd.java @@ -28,6 +28,7 @@ import org.keycloak.client.cli.util.HttpUtil; import org.keycloak.client.cli.util.IoUtil; import java.io.File; +import java.io.PrintWriter; import picocli.CommandLine.Option; @@ -62,19 +63,19 @@ public abstract class BaseAuthOptionsCmd extends BaseGlobalOptionsCmd { @Option(names = "--user", description = "Username to login with") protected String user; - @Option(names = "--password", description = "Password to login with (prompted for if not specified and --user is used)") + @Option(names = "--password", description = "Password to login with (prompted for if not specified, --user is used, and the env variable KC_CLI_PASSWORD is not defined)", defaultValue = "${env:KC_CLI_PASSWORD}") protected String password; - @Option(names = "--secret", description = "Secret to authenticate the client (prompted for if no --user or --keystore is specified)") + @Option(names = "--secret", description = "Secret to authenticate the client (prompted for if no --user nor --keystore is specified, and the env variable KC_CLI_CLIENT_SECRET is not defined)", defaultValue = "${env:KC_CLI_CLIENT_SECRET}") protected String secret; @Option(names = "--keystore", description = "Path to a keystore containing private key") protected String keystore; - @Option(names = "--storepass", description = "Keystore password (prompted for if not specified and --keystore is used)") + @Option(names = "--storepass", description = "Keystore password (prompted for if not specified, --keystore is used, and the env variable KC_CLI_STORE_PASSWORD is undefined)", defaultValue = "${env:KC_CLI_STORE_PASSWORD}") protected String storePass; - @Option(names = "--keypass", description = "Key password (prompted for if not specified and --keystore is used without --storepass, \n otherwise defaults to keystore password)") + @Option(names = "--keypass", description = "Key password (prompted for if not specified and --keystore is used without --storepass, \n otherwise defaults to keystore password)", defaultValue = "${env:KC_CLI_KEY_PASSWORD}") protected String keyPass; @Option(names = "--alias", description = "Alias of the key inside a keystore (defaults to the value of ClientId)") @@ -83,7 +84,7 @@ public abstract class BaseAuthOptionsCmd extends BaseGlobalOptionsCmd { @Option(names = "--truststore", description = "Path to a truststore") protected String trustStore; - @Option(names = "--trustpass", description = "Truststore password (prompted for if not specified and --truststore is used)") + @Option(names = "--trustpass", description = "Truststore password (prompted for if not specified, --user is used, and the env variable KC_CLI_TRUSTSTORE_PASSWORD is not defined)", defaultValue = "${env:KC_CLI_TRUSTSTORE_PASSWORD}") protected String trustPass; @Option(names = "--insecure", description = "Turns off TLS validation") @@ -273,4 +274,23 @@ public abstract class BaseAuthOptionsCmd extends BaseGlobalOptionsCmd { return AuthUtil.ensureToken(config, getCommand()); } + protected void globalOptions(PrintWriter out) { + out.println(); + out.println("Arguments:"); + out.println(); + out.println(" Global options:"); + out.println(" -x Print full stack trace when exiting with error"); + out.println(" --config Path to the config file (" + commandState.getDefaultConfigFilePath() + " by default)"); + out.println(" --no-config Don't use config file - no authentication info is loaded or saved"); + if (commandState.isTokenGlobal()) { + out.println(" --token Token to use to invoke on Keycloak. Other credential may be ignored if this flag is set."); + } + out.println(" --truststore PATH Path to a truststore containing trusted certificates"); + out.println(" --trustpass PASSWORD Truststore password (prompted for if not specified, --truststore is used, and the KC_CLI_TRUSTSTORE_PASSWORD env property is not defined)"); + out.println(" CREDENTIALS OPTIONS Same set of options as accepted by '" + commandState.getCommand() + " config credentials' in order to establish"); + 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(); + } + } diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigCredentialsCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigCredentialsCmd.java index 66cff02731..0fcd28e390 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigCredentialsCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigCredentialsCmd.java @@ -113,10 +113,8 @@ public class BaseConfigCredentialsCmd extends BaseAuthOptionsCmd { } else if (keystore != null || secret != null || clientSet) { grantTypeForAuthentication = OAuth2Constants.CLIENT_CREDENTIALS; printErr("Logging into " + server + " as " + "service-account-" + clientId + " of realm " + realm); - if (keystore == null) { - if (secret == null) { - secret = readSecret("Enter client secret: "); - } + if (keystore == null && secret == null) { + secret = readSecret("Enter client secret: "); } } @@ -196,18 +194,18 @@ public class BaseConfigCredentialsCmd extends BaseAuthOptionsCmd { out.println(" -x Print full stack trace when exiting with error"); out.println(" --config Path to a config file (" + getDefaultConfigFilePath() + " 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(" --trustpass PASSWORD Truststore password (prompted for if not specified, --truststore is used, and the KC_CLI_TRUSTSTORE_PASSWORD env property is not defined)"); out.println(); out.println(" Command specific options:"); out.println(" --server SERVER_URL Server endpoint url (e.g. 'http://localhost:8080')"); out.println(" --realm REALM Realm name to use"); out.println(" --user USER Username to login with"); - out.println(" --password PASSWORD Password to login with (prompted for if not specified and --user is used)"); + out.println(" --password PASSWORD Password to login with (prompted for if not specified, --user is used, and the env variable KC_CLI_PASSWORD is not defined)"); out.println(" --client CLIENT_ID ClientId used by this client tool ('admin-cli' by default)"); - out.println(" --secret SECRET Secret to authenticate the client (prompted for if --client is specified, and no --keystore is specified)"); + out.println(" --secret SECRET Secret to authenticate the client (prompted for if no --user nor --keystore is specified, and the env variable KC_CLI_CLIENT_SECRET is not defined)"); out.println(" --keystore PATH Path to a keystore containing private key"); - out.println(" --storepass PASSWORD Keystore password (prompted for if not specified and --keystore is used)"); - out.println(" --keypass PASSWORD Key password (prompted for if not specified and --keystore is used without --storepass,"); + out.println(" --storepass PASSWORD Keystore password (prompted for if not specified, --keystore is used, and the env variable KC_CLI_STORE_PASSWORD)"); + out.println(" --keypass PASSWORD Key password (prompted for if not specified, --keystore is used without --storepass, and KC_CLI_KEY_PASSWORD"); out.println(" otherwise defaults to keystore password)"); out.println(" --alias ALIAS Alias of the key inside a keystore (defaults to the value of ClientId)"); out.println(); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigTruststoreCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigTruststoreCmd.java index bc289fc31f..8eaa218579 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigTruststoreCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/BaseConfigTruststoreCmd.java @@ -115,7 +115,7 @@ public class BaseConfigTruststoreCmd extends BaseAuthOptionsCmd { out.println(); out.println(" Command specific options:"); out.println(" TRUSTSTORE Path to truststore file"); - out.println(" --trustpass PASSWORD Truststore password to unlock truststore (prompted for if set to '-')"); + out.println(" --trustpass PASSWORD Truststore password to unlock truststore (prompted for if set to '-'), defaults to the env variable KC_CLI_TRUSTSTORE_PASSWORD"); out.println(" -d, --delete Remove truststore configuration"); out.println(); out.println(); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/CommandState.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/CommandState.java index da6f6d7184..5a8b24b1c2 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/CommandState.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/common/CommandState.java @@ -23,4 +23,6 @@ public interface CommandState { String getDefaultConfigFilePath(); + boolean isTokenGlobal(); + } diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/util/IoUtil.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/util/IoUtil.java index f2ececae02..adde5df289 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/util/IoUtil.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/cli/util/IoUtil.java @@ -65,14 +65,6 @@ public class IoUtil { return content; } - public static void waitFor(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted"); - } - } - public static String readSecret(String prompt) { Console cons = System.console(); if (cons == null) { diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java index 94b2a03905..381a1553ca 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java @@ -28,6 +28,11 @@ public class KcRegMain { return DEFAULT_CONFIG_FILE_PATH; } + @Override + public boolean isTokenGlobal() { + return false; + }; + }; public static void main(String [] args) { diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java index dda3b9f4fe..48a2ca9938 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/CreateCmd.java @@ -20,7 +20,6 @@ package org.keycloak.client.registration.cli.commands; import org.keycloak.client.registration.cli.CmdStdinContext; import org.keycloak.client.registration.cli.EndpointType; import org.keycloak.client.registration.cli.EndpointTypeConverter; -import org.keycloak.client.registration.cli.KcRegMain; import org.keycloak.client.cli.common.AttributeOperation; import org.keycloak.client.cli.config.ConfigData; import org.keycloak.client.cli.util.HttpUtil; @@ -200,10 +199,6 @@ public class CreateCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " create [ARGUMENTS]"); @@ -211,20 +206,7 @@ public class CreateCmd extends AbstractAuthOptionsCmd { out.println("Command to create new client configurations on the server. If Initial Access Token is specified (-t TOKEN)"); out.println("or has previously been set for the server, and realm in the configuration ('" + CMD + " config initial-token'),"); out.println("then that will be used, otherwise session access / refresh tokens will be used."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcRegMain.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. 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:"); + globalOptions(out); out.println(" -t, --token TOKEN Use the specified Initial Access Token for authorization or read it from standard input "); out.println(" if '-' is specified. This overrides any token set by '" + CMD + " config initial-token'."); out.println(" If not specified, session credentials are used - see: CREDENTIALS OPTIONS."); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java index 8011513ed1..920d529d75 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/DeleteCmd.java @@ -17,7 +17,6 @@ package org.keycloak.client.registration.cli.commands; -import org.keycloak.client.registration.cli.KcRegMain; import org.keycloak.client.cli.config.ConfigData; import org.keycloak.client.registration.cli.CmdStdinContext; @@ -98,30 +97,13 @@ public class DeleteCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " delete CLIENT [ARGUMENTS]"); out.println(); out.println("Command to delete a specific client configuration. If registration access token is specified or is available in "); out.println("configuration file, then it is used. Otherwise, current active session is used."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcRegMain.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. 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:"); + globalOptions(out); out.println(" CLIENT ClientId of the client to delete"); out.println(" -t, --token TOKEN Use the specified Registration Access Token for authorization"); out.println(); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java index 92dae5791d..333dc61408 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/GetCmd.java @@ -17,7 +17,6 @@ package org.keycloak.client.registration.cli.commands; -import org.keycloak.client.registration.cli.KcRegMain; import org.keycloak.client.cli.config.ConfigData; import org.keycloak.client.registration.cli.CmdStdinContext; import org.keycloak.client.registration.cli.EndpointType; @@ -160,30 +159,13 @@ public class GetCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " get CLIENT [ARGUMENTS]"); out.println(); out.println("Command to retrieve a client configuration description for a specified client. If registration access token"); out.println("is specified or is available in configuration file, then it is used. Otherwise, current active session is used."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcRegMain.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. 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:"); + globalOptions(out); 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"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/HelpCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/HelpCmd.java index 510c79302b..9c428478d2 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/HelpCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/HelpCmd.java @@ -48,19 +48,19 @@ public class HelpCmd implements Runnable { break; } case "create": { - printOut(CreateCmd.usage()); + printOut(new CreateCmd().help()); break; } case "get": { - printOut(GetCmd.usage()); + printOut(new GetCmd().help()); break; } case "update": { - printOut(UpdateCmd.usage()); + printOut(new UpdateCmd().help()); break; } case "delete": { - printOut(DeleteCmd.usage()); + printOut(new DeleteCmd().help()); break; } case "attrs": { @@ -68,7 +68,7 @@ public class HelpCmd implements Runnable { break; } case "update-token": { - printOut(UpdateTokenCmd.usage()); + printOut(new UpdateTokenCmd().help()); break; } default: { diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java index 78aac47c92..ff20171a7d 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateCmd.java @@ -28,7 +28,6 @@ import org.keycloak.client.registration.cli.CmdStdinContext; import org.keycloak.client.registration.cli.EndpointType; import org.keycloak.client.registration.cli.EndpointTypeConverter; import org.keycloak.client.registration.cli.ReflectionUtil; -import org.keycloak.client.registration.cli.KcRegMain; import org.keycloak.client.cli.common.AttributeOperation; import org.keycloak.client.cli.config.ConfigData; import org.keycloak.representations.idm.ClientRepresentation; @@ -311,10 +310,6 @@ public class UpdateCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " update CLIENT [ARGUMENTS]"); @@ -323,19 +318,7 @@ public class UpdateCmd extends AbstractAuthOptionsCmd { out.println("Otherwise, if 'registrationAccessToken' attribute is set, that is used. Otherwise, if registration access"); out.println("token is available in configuration file, we use that. Finally, if it's not available anywhere, the current "); out.println("active session is used."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcRegMain.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. 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(); + globalOptions(out); 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"); diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java index dbbd9b5df2..c66fcab22b 100644 --- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java +++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/registration/cli/commands/UpdateTokenCmd.java @@ -22,7 +22,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; -import org.keycloak.client.registration.cli.KcRegMain; import org.keycloak.client.cli.config.ConfigData; import org.keycloak.client.registration.cli.CmdStdinContext; import org.keycloak.representations.idm.ClientRepresentation; @@ -120,30 +119,13 @@ public class UpdateTokenCmd extends AbstractAuthOptionsCmd { @Override protected String help() { - return usage(); - } - - public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " update-token CLIENT [ARGUMENTS]"); out.println(); out.println("Command to reissue, and set a new registration access token if an old one is lost or becomes invalid."); out.println("It requires an authenticated session using an account with administrator privileges."); - out.println(); - out.println("Arguments:"); - out.println(); - out.println(" Global options:"); - out.println(" -x Print full stack trace when exiting with error"); - out.println(" --config Path to the config file (" + KcRegMain.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. 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:"); + globalOptions(out); 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 --no-config"); out.println(" (on-the-fly) authentication is used"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/AbstractAdmCliTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/AbstractAdmCliTest.java index a69a060217..e411b939bf 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/AbstractAdmCliTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/AbstractAdmCliTest.java @@ -345,12 +345,18 @@ public abstract class AbstractAdmCliTest extends AbstractCliTest { realm.getUsers().add(account); } - void loginAsUser(File configFile, String server, String realm, String user, String password) { - - KcAdmExec exe = KcAdmExec.execute("config credentials --server " + server + " --realm " + realm + - " --user " + user + " --password " + password + " --config " + configFile.getAbsolutePath()); + void loginAsUser(File configFile, String server, String realm, String user, String password, boolean envPassword) { + KcAdmExec exe = KcAdmExec.newBuilder() + .argsLine("config credentials --server " + server + " --realm " + realm + + " --user " + user + (envPassword ? "" : (" --password " + password)) + " --config " + configFile.getAbsolutePath()) + .env(envPassword ? "KC_CLI_PASSWORD=" + password : null) + .execute(); assertExitCodeAndStreamSizes(exe, 0, 0, 1); } + void loginAsUser(File configFile, String server, String realm, String user, String password) { + loginAsUser(configFile, server, realm, user, password, false); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmSessionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmSessionTest.java index ee9153c924..23cf21bd31 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmSessionTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmSessionTest.java @@ -36,8 +36,9 @@ public class KcAdmSessionTest extends AbstractAdmCliTest { try (TempFileResource configFile = new TempFileResource(FileConfigHandler.getConfigFile())) { - // login as admin - loginAsUser(configFile.getFile(), serverUrl, "master", "admin", "admin"); + // login as admin using command option and env password + loginAsUser(configFile.getFile(), serverUrl, "master", "admin", "admin", false); + loginAsUser(configFile.getFile(), serverUrl, "master", "admin", "admin", true); // create realm KcAdmExec exe = execute("create realms --config '" + configFile.getName() + "' -s realm=demorealm -s enabled=true");