Skip to content

Commit

Permalink
reload service account token after expiry
Browse files Browse the repository at this point in the history
  • Loading branch information
zshihang committed Jun 2, 2020
1 parent 970ed2b commit dabe51a
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

import com.google.common.base.Strings;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.util.credentials.AccessTokenAuthentication;
import io.kubernetes.client.util.credentials.Authentication;
import io.kubernetes.client.util.credentials.KubeconfigAuthentication;
import io.kubernetes.client.util.credentials.TokenFileAuthentication;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
Expand All @@ -34,7 +34,6 @@
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
Expand Down Expand Up @@ -209,11 +208,8 @@ public static ClientBuilder cluster() throws IOException {
final String port = System.getenv(ENV_SERVICE_PORT);
builder.setBasePath(host, port);

final String token =
new String(
Files.readAllBytes(Paths.get(SERVICEACCOUNT_TOKEN_PATH)), Charset.defaultCharset());
builder.setCertificateAuthority(Files.readAllBytes(Paths.get(SERVICEACCOUNT_CA_PATH)));
builder.setAuthentication(new AccessTokenAuthentication(token));
builder.setAuthentication(new TokenFileAuthentication(SERVICEACCOUNT_TOKEN_PATH));

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.kubernetes.client.util.credentials;

import io.kubernetes.client.openapi.ApiClient;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class TokenFileAuthentication implements Authentication, Interceptor {
private String file;
private String token;
private Instant expiry;

public TokenFileAuthentication(String file) {
this.expiry = Instant.MIN;
this.file = file;
}

private String getToken() {
if (Instant.now().isAfter(this.expiry)) {
try {
this.token =
new String(Files.readAllBytes(Paths.get(this.file)), Charset.defaultCharset()).trim();
expiry = Instant.now().plusSeconds(60);
} catch (IOException ie) {
throw new RuntimeException("Cannot read file: " + this.file);
}
}

return this.token;
}

public void setExpiry(Instant expiry) {
this.expiry = expiry;
}

public void setFile(String file) {
this.file = file;
}

@Override
public void provide(ApiClient client) {
OkHttpClient withInterceptor = client.getHttpClient().newBuilder().addInterceptor(this).build();
client.setHttpClient(withInterceptor);
}

@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request newRequest;
newRequest = request.newBuilder().header("Authorization", "Bearer " + getToken()).build();
return chain.proceed(newRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.kubernetes.client.util.credentials;

import static com.github.tomakehurst.wiremock.client.WireMock.*;

import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.google.common.io.Resources;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import java.io.IOException;
import java.time.Instant;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

public class TokenFileAuthenticationTest {
private static final String SERVICEACCOUNT_TOKEN1_PATH =
Resources.getResource("token1").getPath();
private static final String SERVICEACCOUNT_TOKEN2_PATH =
Resources.getResource("token2").getPath();
private static final int PORT = 8089;
private TokenFileAuthentication auth;

@Rule public WireMockRule wireMockRule = new WireMockRule(PORT);

@Before
public void setup() throws IOException {
final ApiClient client = new ApiClient();
client.setBasePath("http://localhost:" + PORT);
this.auth = new TokenFileAuthentication(SERVICEACCOUNT_TOKEN1_PATH);
this.auth.provide(client);
Configuration.setDefaultApiClient(client);
}

@Test
public void testTokenProvided() throws IOException, ApiException {
stubFor(
get(urlPathEqualTo("/api/v1/pods")).willReturn(okForContentType("application/json", "{}")));
CoreV1Api api = new CoreV1Api();

api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
WireMock.verify(
1,
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
.withHeader("Authorization", equalTo("Bearer token1")));

this.auth.setFile(SERVICEACCOUNT_TOKEN2_PATH);
api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
WireMock.verify(
2,
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
.withHeader("Authorization", equalTo("Bearer token1")));

this.auth.setExpiry(Instant.now().minusSeconds(1));
api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
WireMock.verify(
1,
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
.withHeader("Authorization", equalTo("Bearer token2")));
}
}
1 change: 1 addition & 0 deletions util/src/test/resources/token1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
token1
1 change: 1 addition & 0 deletions util/src/test/resources/token2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
token2

0 comments on commit dabe51a

Please sign in to comment.