Skip to content

GCPAuthenticator executes malformed gcloud cmd #1821

Closed
@kharf

Description

@kharf

Describe the bug
I'm not sure if it is correct to create an Issue for current SNAPSHOT, but I wanted to contribute to fix a bug, so I hope that this is fine.
When trying to authenticate to GCP, the GCPAuthenticator composes a gcloud cmd where the args are added without empty spaces:

 String cmdPath = (String) config.get(CMD_PATH);
 String cmdArgs = (String) config.get(CMD_ARGS);
 String fullCmd = cmdPath + cmdArgs;
    try {
      Process process = this.pb.command(Arrays.asList(fullCmd.split(" "))).start();

resulting in a cmd like:
/opt/google-cloud-sdk/bin/gcloudconfig config-helper --format=json

** Client Version **
13.0.1-SNAPSHOT

To Reproduce
Run the KubeConfigFileClientExample against GCP

or write a unit test, e.g.:

@Test
    public void testRefresh() {
        String cmdPath = "/usr/lib/google-cloud-sdk/bin/gcloud";
        String cmdArgs = "config config-helper --format=json";
        String[] cmdArgsSplit = cmdArgs.split(" ");
        Map<String, Object> gcpConfig = new HashMap<String, Object>() {{
            put(GCPAuthenticator.ACCESS_TOKEN, "eyXXX");
            put(GCPAuthenticator.CMD_PATH, cmdPath);
            put(GCPAuthenticator.CMD_ARGS, cmdArgs);
            put(GCPAuthenticator.EXPIRY, "2121-08-05T02:30:24Z");
        }};
        String fakeExecResult =
                "{\n"
                        + "  \"credential\": {\n"
                        + "    \"access_token\": \"new-fake-token\",\n"
                        + "    \"id_token\": \"id-fake-token\",\n"
                        + "    \"token_expiry\": \"2121-08-05T02:30:24Z\"\n"
                        + "  }\n"
                        + "}";
        ProcessBuilder mockPB = Mockito.mock(ProcessBuilder.class);
        Process mockProcess = Mockito.mock(Process.class);
        Mockito.when(mockProcess.exitValue()).thenReturn(0);
        Mockito.when(mockProcess.getInputStream())
                .thenReturn(new ByteArrayInputStream(fakeExecResult.getBytes(StandardCharsets.UTF_8)));
        try {
            Mockito.when(mockPB.command(Mockito.anyList())).thenCallRealMethod();
            Mockito.when(mockPB.start()).thenReturn(mockProcess);
            Mockito.when(mockPB.command()).thenCallRealMethod();
        } catch (IOException ex) {
            ex.printStackTrace();
            fail("Unexpected exception: " + ex);
        }
        new GCPAuthenticator(mockPB).refresh(gcpConfig);
        List<String> expectedCommand = new ArrayList<String>() {{
            add(cmdPath);
            add(cmdArgsSplit[0]);
            add(cmdArgsSplit[1]);
            add(cmdArgsSplit[2]);
        }};
        List<String> executedCommand = mockPB.command();
        Assert.assertEquals(4, executedCommand.size());
        MatcherAssert.assertThat(executedCommand, is(expectedCommand));
    }

Expected behavior
the command /opt/google-cloud-sdk/bin/gcloud config config-helper --format=json should be composed, which should then execute without errors

KubeConfig

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxx
    server: https://xxxx
  name: xxxdev
- cluster:
    certificate-authority-data: xxx
    server: https://xxx
  name: xxxprod
contexts:
- context:
    cluster: xxxdev
    namespace: preview
    user: xxxdev
  name: dev
- context:
    cluster: xxxprod
    namespace: prod
    user: xxxprod
  name: prod
current-context: dev
kind: Config
preferences: {}
users:
- name: xxx
  user:
    auth-provider:
      config:
        access-token: xxx
        cmd-args: config config-helper --format=json
        cmd-path: /opt/google-cloud-sdk/bin/gcloud
        expiry: "2021-06-29T13:37:37Z"
        expiry-key: '{.credential.token_expiry}'
        token-key: '{.credential.access_token}'
      name: gcp
- name: xxxdev
  user:
    auth-provider:
      config:
        access-token: xxx
        cmd-args: config config-helper --format=json
        cmd-path: /opt/google-cloud-sdk/bin/gcloud
        expiry: "2021-08-13T06:42:53Z"
        expiry-key: '{.credential.token_expiry}'
        token-key: '{.credential.access_token}'
      name: gcp
- name: xxxprod
  user:
    auth-provider:
      config:
        access-token: xxx
        cmd-args: config config-helper --format=json
        cmd-path: /opt/google-cloud-sdk/bin/gcloud
        expiry: "2021-08-13T18:55:38Z"
        expiry-key: '{.credential.token_expiry}'
        token-key: '{.credential.access_token}'
      name: gcp

Server (please complete the following information):

  • OS: Linux (endeavourOS)
  • Cloud: GCP

Comment
Currently the GCPAuthenticator has side effects and they are untested. In my opinion the GCPAuthenticator should not directly rely on a ProcessBuilder, but when it does, then it should be explicitly tested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    lifecycle/rottenDenotes an issue or PR that has aged beyond stale and will be auto-closed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions