Skip to content

Commit d177116

Browse files
committed
Extracted method with multiple return values for clarity.
1 parent 28b1732 commit d177116

File tree

1 file changed

+63
-53
lines changed

1 file changed

+63
-53
lines changed

util/src/main/java/io/kubernetes/client/util/KubeConfig.java

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -222,59 +222,9 @@ public String getAccessToken() {
222222
}
223223
}
224224
}
225-
Object exec = currentUser.get("exec");
226-
if (exec != null) {
227-
// TODO extract to helper method for clarity
228-
Map<String, Object> execMap = (Map<String, Object>) exec;
229-
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
230-
String apiVersion = (String) execMap.get("apiVersion");
231-
if ("client.authentication.k8s.io/v1beta1".equals(apiVersion)) { // TODO or v1alpha1 is apparently identical and could be supported
232-
String command = (String) execMap.get("command");
233-
List<Map<String, String>> env = (List) execMap.get("env");
234-
List<String> args = (List) execMap.get("args");
235-
// TODO relativize command to basedir of config file (requires KubeConfig to be given a basedir)
236-
List<String> argv = new ArrayList<>();
237-
argv.add(command);
238-
if (args != null) {
239-
argv.addAll(args);
240-
}
241-
ProcessBuilder pb = new ProcessBuilder(argv);
242-
if (env != null) {
243-
// TODO apply
244-
}
245-
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
246-
try {
247-
Process proc = pb.start();
248-
JsonElement root = null;
249-
try (InputStream is = proc.getInputStream();
250-
Reader r = new InputStreamReader(is, StandardCharsets.UTF_8)) {
251-
root = new JsonParser().parse(r);
252-
} catch (JsonParseException x) {
253-
log.error("Failed to parse output of " + command, x);
254-
}
255-
int r = proc.waitFor();
256-
if (r == 0) {
257-
if (root != null) {
258-
// TODO verify .apiVersion and .kind = ExecCredential
259-
JsonObject status = root.getAsJsonObject().get("status").getAsJsonObject();
260-
JsonElement token = status.get("token");
261-
if (token != null) {
262-
return token.getAsString();
263-
}
264-
// TODO handle clientCertificateData/clientKeyData (KubeconfigAuthentication is not yet set up for that to be dynamic)
265-
}
266-
} else {
267-
log.error("{} failed with exit code {}", command, r);
268-
}
269-
} catch (IOException | InterruptedException x) {
270-
log.error("Failed to run " + command, x);
271-
}
272-
// TODO cache tokens between calls, up to .status.expirationTimestamp
273-
// TODO a 401 is supposed to force a refresh, but KubeconfigAuthentication hard-codes AccessTokenAuthentication which does not support that
274-
// and anyway ClientBuilder only calls Authenticator.provide once per ApiClient; we would need to do it on every request
275-
} else {
276-
log.error("Unrecognized user.exec.apiVersion: {}", apiVersion);
277-
}
225+
String tokenViaExecCredential = tokenViaExecCredential((Map<String, Object>) currentUser.get("exec"));
226+
if (tokenViaExecCredential != null) {
227+
return tokenViaExecCredential;
278228
}
279229
if (currentUser.containsKey("token")) {
280230
return (String) currentUser.get("token");
@@ -291,6 +241,66 @@ public String getAccessToken() {
291241
return null;
292242
}
293243

244+
/**
245+
* Attempt to create an access token by running a configured external program.
246+
* @see <a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins">Authenticating » client-go credential plugins</a>
247+
*/
248+
private String tokenViaExecCredential(Map<String, Object> execMap) {
249+
if (execMap == null) {
250+
return null;
251+
}
252+
String apiVersion = (String) execMap.get("apiVersion");
253+
if (!"client.authentication.k8s.io/v1beta1".equals(apiVersion)) { // TODO or v1alpha1 is apparently identical and could be supported
254+
log.error("Unrecognized user.exec.apiVersion: {}", apiVersion);
255+
return null;
256+
}
257+
String command = (String) execMap.get("command");
258+
List<Map<String, String>> env = (List) execMap.get("env");
259+
List<String> args = (List) execMap.get("args");
260+
// TODO relativize command to basedir of config file (requires KubeConfig to be given a basedir)
261+
List<String> argv = new ArrayList<>();
262+
argv.add(command);
263+
if (args != null) {
264+
argv.addAll(args);
265+
}
266+
ProcessBuilder pb = new ProcessBuilder(argv);
267+
if (env != null) {
268+
// TODO apply
269+
}
270+
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
271+
try {
272+
Process proc = pb.start();
273+
JsonElement root;
274+
try (InputStream is = proc.getInputStream();
275+
Reader r = new InputStreamReader(is, StandardCharsets.UTF_8)) {
276+
root = new JsonParser().parse(r);
277+
} catch (JsonParseException x) {
278+
log.error("Failed to parse output of " + command, x);
279+
return null;
280+
}
281+
int r = proc.waitFor();
282+
if (r != 0) {
283+
log.error("{} failed with exit code {}", command, r);
284+
return null;
285+
}
286+
// TODO verify .apiVersion and .kind = ExecCredential
287+
JsonObject status = root.getAsJsonObject().get("status").getAsJsonObject();
288+
JsonElement token = status.get("token");
289+
if (token == null) {
290+
// TODO handle clientCertificateData/clientKeyData (KubeconfigAuthentication is not yet set up for that to be dynamic)
291+
log.warn("No token produced by {}", command);
292+
return null;
293+
}
294+
return token.getAsString();
295+
} catch (IOException | InterruptedException x) {
296+
log.error("Failed to run " + command, x);
297+
return null;
298+
}
299+
// TODO cache tokens between calls, up to .status.expirationTimestamp
300+
// TODO a 401 is supposed to force a refresh, but KubeconfigAuthentication hard-codes AccessTokenAuthentication which does not support that
301+
// and anyway ClientBuilder only calls Authenticator.provide once per ApiClient; we would need to do it on every request
302+
}
303+
294304
public boolean verifySSL() {
295305
if (currentCluster == null) {
296306
return false;

0 commit comments

Comments
 (0)