From 445f60242e6fa7ccdefde6a5562bce9e2e4d133e Mon Sep 17 00:00:00 2001 From: Sun Seng David TAN Date: Tue, 21 Feb 2023 17:20:46 +0100 Subject: [PATCH] fix(config): Fix kubeconfig loading when exec auth command contains spaces Signed-off-by: Sun Seng David TAN --- .../io/fabric8/kubernetes/client/Config.java | 15 +++++- .../fabric8/kubernetes/client/ConfigTest.java | 52 +++++++++++++++++++ .../test-kubeconfig-exec-args-with-spaces | 23 ++++++++ ...t-kubeconfig-exec-args-with-spaces-windows | 23 ++++++++ .../test-kubeconfig-exec-with-spaces | 23 ++++++++ .../test-kubeconfig-exec-with-spaces-windows | 23 ++++++++ .../resources/token-generator with spaces | 12 +++++ .../token-generator-win with spaces.bat | 37 +++++++++++++ .../test/resources/token-generator-win.bat | 2 +- 9 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces create mode 100644 kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces-windows create mode 100644 kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces create mode 100644 kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces-windows create mode 100755 kubernetes-client-api/src/test/resources/token-generator with spaces create mode 100644 kubernetes-client-api/src/test/resources/token-generator-win with spaces.bat diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java index 1c01181ed58..f1c3f2889e7 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java @@ -813,14 +813,27 @@ protected static List getAuthenticatorCommandFromExecConfig(ExecConfig e } List argv = new ArrayList<>(Utils.getCommandPlatformPrefix()); command = getCommandWithFullyQualifiedPath(command, systemPathValue); + + command = shellQuote(command); + List args = exec.getArgs(); if (args != null && !args.isEmpty()) { - command += " " + String.join(" ", args); + command += " " + args + .stream() + .map(Config::shellQuote) + .collect(Collectors.joining(" ")); } argv.add(command); return argv; } + private static String shellQuote(String value) { + if (value.contains(" ") || value.contains("\"") || value.contains("'")) { + return "\"" + value.replace("\"", "\\\"") + "\""; + } + return value; + } + protected static String getCommandWithFullyQualifiedPath(String command, String pathValue) { String[] pathParts = pathValue.split(File.pathSeparator); diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java index 0d6bddd24b5..ffde9029b01 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java @@ -57,6 +57,8 @@ public class ConfigTest { private static final String TEST_KUBECONFIG_EXEC_FILE = Utils.filePath(ConfigTest.class.getResource("/test-kubeconfig-exec")); private static final String TEST_TOKEN_GENERATOR_FILE = Utils.filePath(ConfigTest.class.getResource("/token-generator")); + private static final String TEST_TOKEN_GENERATOR_FILE_WITH_SPACES = Utils + .filePath(ConfigTest.class.getResource("/token-generator with spaces")); private static final String TEST_KUBECONFIG_EXEC_WIN_FILE = Utils .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-win")); @@ -66,6 +68,18 @@ public class ConfigTest { private static final String TEST_KUBECONFIG_EXEC_FILE_WIN_NULL_ARGS = Utils .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-win-null-args")); + private static final String TEST_KUBECONFIG_EXEC_FILE_WITH_SPACES_WIN = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-with-spaces-windows")); + + private static final String TEST_KUBECONFIG_EXEC_FILE_WITH_SPACES = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-with-spaces")); + + private static final String TEST_KUBECONFIG_EXEC_FILE_ARGS_WITH_SPACES_WIN = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-args-with-spaces-windows")); + + private static final String TEST_KUBECONFIG_EXEC_FILE_ARGS_WITH_SPACES = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-args-with-spaces")); + private static final String TEST_KUBECONFIG_NO_CURRENT_CONTEXT_FILE = Utils .filePath(ConfigTest.class.getResource("/test-kubeconfig-nocurrentctxt.yml")); @@ -489,6 +503,44 @@ void should_accept_client_authentication_commands_with_null_args() throws Except } } + @Test + void should_accept_client_authentication_commands_args_with_spaces() throws Exception { + try { + if (FileSystem.getCurrent() == FileSystem.WINDOWS) { + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_ARGS_WITH_SPACES_WIN); + } else { + Files.setPosixFilePermissions(Paths.get(TEST_TOKEN_GENERATOR_FILE_WITH_SPACES), + PosixFilePermissions.fromString("rwxrwxr-x")); + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_ARGS_WITH_SPACES); + } + + Config config = Config.autoConfigure(null); + assertNotNull(config); + assertEquals("HELLO W O R L D", config.getOauthToken()); + } finally { + System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); + } + } + + @Test + void should_accept_client_authentication_commands_with_spaces() throws Exception { + try { + if (FileSystem.getCurrent() == FileSystem.WINDOWS) { + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_WITH_SPACES_WIN); + } else { + Files.setPosixFilePermissions(Paths.get(TEST_TOKEN_GENERATOR_FILE_WITH_SPACES), + PosixFilePermissions.fromString("rwxrwxr-x")); + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_WITH_SPACES); + } + + Config config = Config.autoConfigure(null); + assertNotNull(config); + assertEquals("HELLO WORLD", config.getOauthToken()); + } finally { + System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); + } + } + @Test void shouldBeUsedTokenSuppliedByProvider() { diff --git a/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces new file mode 100644 index 00000000000..42cd7e68101 --- /dev/null +++ b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://wherever + name: test +contexts: +- context: + cluster: test + user: test + name: test +current-context: test +users: +- name: test + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + args: + - "w o r l d" + command: "./token-generator" + env: + - name: PART1 + value: hello diff --git a/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces-windows b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces-windows new file mode 100644 index 00000000000..22e66193236 --- /dev/null +++ b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-args-with-spaces-windows @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://wherever + name: test +contexts: +- context: + cluster: test + user: test + name: test +current-context: test +users: +- name: test + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + args: + - "w o r l d" + command: ".\\token-generator-win.bat" + env: + - name: PART1 + value: hello diff --git a/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces new file mode 100644 index 00000000000..8dd9a174b67 --- /dev/null +++ b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://wherever + name: test +contexts: +- context: + cluster: test + user: test + name: test +current-context: test +users: +- name: test + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + args: + - world + command: "./token-generator with spaces" + env: + - name: PART1 + value: hello diff --git a/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces-windows b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces-windows new file mode 100644 index 00000000000..407a0a96174 --- /dev/null +++ b/kubernetes-client-api/src/test/resources/test-kubeconfig-exec-with-spaces-windows @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://wherever + name: test +contexts: +- context: + cluster: test + user: test + name: test +current-context: test +users: +- name: test + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + args: + - world + command: ".\\token-generator-win with spaces.bat" + env: + - name: PART1 + value: hello diff --git a/kubernetes-client-api/src/test/resources/token-generator with spaces b/kubernetes-client-api/src/test/resources/token-generator with spaces new file mode 100755 index 00000000000..43b0fb90e1c --- /dev/null +++ b/kubernetes-client-api/src/test/resources/token-generator with spaces @@ -0,0 +1,12 @@ +#!/bin/sh +token=`echo $PART1 $1 | tr '[a-z]' '[A-Z]'` +cat <