diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e59d63ecd..1f08ef19521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ #### Dependency Upgrade #### New Features +* Fix #5608 Support authentication with certificate in exec-credentials #### _**Note**_: Breaking changes 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 89ce3f8b599..b386cf91b5b 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 @@ -785,10 +785,16 @@ private static void mergeKubeConfigExecCredential(Config config, ExecConfig exec if (exec != null) { try { ExecCredential ec = getExecCredentialFromExecConfig(exec, configFile); - if (ec != null && ec.status != null && ec.status.token != null) { - config.setAutoOAuthToken(ec.status.token); - } else { - LOGGER.warn("No token returned"); + if (ec != null && ec.status != null) { + if (ec.status.token != null) { + config.setAutoOAuthToken(ec.status.token); + } else if (Utils.isNotNullOrEmpty(ec.status.clientCertificateData) + && Utils.isNotNullOrEmpty(ec.status.clientKeyData)) { + config.setClientCertData(ec.status.clientCertificateData); + config.setClientKeyData(ec.status.clientKeyData); + } else { + LOGGER.warn("No token or certificate returned"); + } } } catch (InterruptedException interruptedException) { Thread.currentThread().interrupt(); @@ -898,7 +904,9 @@ public static final class ExecCredentialSpec { @JsonIgnoreProperties(ignoreUnknown = true) public static final class ExecCredentialStatus { public String token; - // TODO clientCertificateData, clientKeyData, expirationTimestamp + public String clientCertificateData; + public String clientKeyData; + // TODO expirationTimestamp } private static boolean tryNamespaceFromPath(Config config) { 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 8308b7b2eba..ed2fd90d156 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 @@ -84,6 +84,16 @@ class ConfigTest { private static final String TEST_KUBECONFIG_NO_CURRENT_CONTEXT_FILE = Utils .filePath(ConfigTest.class.getResource("/test-kubeconfig-nocurrentctxt.yml")); + private static final String TEST_KUBECONFIG_EXEC_FILE_CERT_AUTH = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-cert-auth")); + private static final String TEST_KUBECONFIG_EXEC_WIN_FILE_CERT_AUTH = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-win-cert-auth")); + private static final String TEST_KUBECONFIG_EXEC_FILE_CERT_AUTH_EC_INVALID = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-cert-auth-ec-invalid")); + private static final String TEST_KUBECONFIG_EXEC_WIN_FILE_CERT_AUTH_EC_INVALID = Utils + .filePath(ConfigTest.class.getResource("/test-kubeconfig-exec-win-cert-auth-ec-invalid")); + private static final String TEST_CERT_GENERATOR_FILE = Utils.filePath(ConfigTest.class.getResource("/cert-generator")); + @BeforeEach public void setUp() { System.getProperties().remove(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY); @@ -504,6 +514,44 @@ void should_accept_client_authentication_commands_with_null_args() throws Except } } + @Test + void testClientAuthenticationWithCert() throws Exception { + try { + if (FileSystem.getCurrent() == FileSystem.WINDOWS) { + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_WIN_FILE_CERT_AUTH); + } else { + Files.setPosixFilePermissions(Paths.get(TEST_CERT_GENERATOR_FILE), PosixFilePermissions.fromString("rwxrwxr-x")); + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_CERT_AUTH); + } + + Config config = Config.autoConfigure(null); + assertNotNull(config); + assertEquals("CERT DATA", config.getClientCertData()); + assertEquals("KEY DATA", config.getClientKeyData()); + } finally { + System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); + } + } + + @Test + void testClientAuthenticationWithCertAndECInvalid() throws Exception { + try { + if (FileSystem.getCurrent() == FileSystem.WINDOWS) { + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_WIN_FILE_CERT_AUTH_EC_INVALID); + } else { + Files.setPosixFilePermissions(Paths.get(TEST_CERT_GENERATOR_FILE), PosixFilePermissions.fromString("rwxrwxr-x")); + System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, TEST_KUBECONFIG_EXEC_FILE_CERT_AUTH_EC_INVALID); + } + + Config config = Config.autoConfigure(null); + assertNotNull(config); + assertNull(config.getClientCertData()); + assertNull(config.getClientKeyData()); + } finally { + System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); + } + } + @Test void should_accept_client_authentication_commands_args_with_spaces() throws Exception { try { diff --git a/kubernetes-client-api/src/test/resources/cert-generator b/kubernetes-client-api/src/test/resources/cert-generator new file mode 100644 index 00000000000..c5e62216b0f --- /dev/null +++ b/kubernetes-client-api/src/test/resources/cert-generator @@ -0,0 +1,14 @@ +#!/bin/sh +certData=`echo $PART1 $1 | tr '[a-z]' '[A-Z]'` +keyData=`echo $PART2 $1 | tr '[a-z]' '[A-Z]'` +cat <